From 7dbcb47845e11329be49049c276617aa3567ab8d Mon Sep 17 00:00:00 2001 From: MartinGumGum <109325501+MartinGumGum@users.noreply.github.com> Date: Wed, 10 Apr 2024 10:47:13 -0700 Subject: [PATCH 001/147] GumGum Bid Adapter : Add support for the DSA (#11311) * Fix for the multi-size in- slot * added comment * displaymanager: add field for displaymanager and displaymanagerver * fix: displayManager to include 'gumgum' * fix: test case * Add support for DSA in the bid request --------- Co-authored-by: ahzgg Co-authored-by: ahzgg <163184035+ahzgg@users.noreply.github.com> --- modules/gumgumBidAdapter.js | 5 ++++- test/spec/modules/gumgumBidAdapter_spec.js | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index 60851d2b4dd..ff249ec9b50 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -422,6 +422,10 @@ function buildRequests(validBidRequests, bidderRequest) { data.gppString = bidderRequest.ortb2.regs.gpp data.gppSid = Array.isArray(bidderRequest.ortb2.regs.gpp_sid) ? bidderRequest.ortb2.regs.gpp_sid.join(',') : '' } + const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa'); + if (dsa) { + data.dsa = dsa + } if (coppa) { data.coppa = coppa; } @@ -549,7 +553,6 @@ function interpretResponse(serverResponse, bidRequest) { mediaType: type || mediaType }; let sizes = parseSizesInput(bidRequest.sizes); - if (maxw && maxh) { sizes = [`${maxw}x${maxh}`]; } else if (product === 5 && includes(sizes, '1x1')) { diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 29e372d0f87..3720d357b51 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -589,6 +589,29 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.gppString).to.eq('') expect(bidRequest.data.gppSid).to.eq('') }); + it('should add DSA information to payload if available', function () { + // Define the sample ORTB2 object with DSA information + const ortb2 = { + regs: { + ext: { + dsa: { + dsarequired: '1', + pubrender: '2', + datatopub: '3', + transparency: [{ + domain: 'test.com', + dsaparams: [1, 2, 3] + }] + } + } + } + }; + const fakeBidRequest = { ortb2 }; + // Call the buildRequests function to generate the bid request + const [bidRequest] = spec.buildRequests(bidRequests, fakeBidRequest); + // Assert that the DSA information in the bid request matches the provided ORTB2 data + expect(bidRequest.data.dsa).to.deep.equal(fakeBidRequest.ortb2.regs.ext.dsa); + }); it('should not set coppa parameter if coppa config is set to false', function () { config.setConfig({ coppa: false From 458036a383c89a08f046d6873f362ad4d5edbbf6 Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Thu, 11 Apr 2024 01:01:18 -0300 Subject: [PATCH 002/147] JW Player RTD Module : populate content url, title and description (#11178) * caches items * updates fetch tests * verifies against entire object * updates docs * appens to ext * renames tests * parses source from playlist * Update modules/jwplayerRtdProvider.js Co-authored-by: Demetrio Girardi * Update modules/jwplayerRtdProvider.js Co-authored-by: Demetrio Girardi * adds indentation * allow override configuration * adds tests * uses labels * populates tests * updates tests * adds config docs * updates demo * uses ix * adds todos --------- Co-authored-by: Demetrio Girardi --- .../jwplayerRtdProvider_example.html | 70 +- modules/jwplayerRtdProvider.js | 119 ++- modules/jwplayerRtdProvider.md | 25 +- test/spec/modules/jwplayerRtdProvider_spec.js | 701 +++++++++++++++++- 4 files changed, 816 insertions(+), 99 deletions(-) rename integrationExamples/{gpt => realTimeData}/jwplayerRtdProvider_example.html (51%) diff --git a/integrationExamples/gpt/jwplayerRtdProvider_example.html b/integrationExamples/realTimeData/jwplayerRtdProvider_example.html similarity index 51% rename from integrationExamples/gpt/jwplayerRtdProvider_example.html rename to integrationExamples/realTimeData/jwplayerRtdProvider_example.html index 41c27b70ece..4f29ef1c406 100644 --- a/integrationExamples/gpt/jwplayerRtdProvider_example.html +++ b/integrationExamples/realTimeData/jwplayerRtdProvider_example.html @@ -1,8 +1,10 @@ + + /* Paste JW Player script tag here */ + - JW Player RTD Provider Example + function renderHighestBid() { + const highestBids = pbjs.getHighestCpmBids('video-ad-unit'); + const highestBid = highestBids && highestBids.length && highestBids[0]; + if (!highestBid) { + return; + } - -
Div-1
-
- -
diff --git a/modules/jwplayerRtdProvider.js b/modules/jwplayerRtdProvider.js index e8c1c445816..29ce0da5317 100644 --- a/modules/jwplayerRtdProvider.js +++ b/modules/jwplayerRtdProvider.js @@ -23,10 +23,20 @@ import {getGlobal} from '../src/prebidGlobal.js'; const SUBMODULE_NAME = 'jwplayer'; const JWPLAYER_DOMAIN = SUBMODULE_NAME + '.com'; -const segCache = {}; +const ENRICH_ALWAYS = 'always'; +const ENRICH_WHEN_EMPTY = 'whenEmpty'; +const ENRICH_NEVER = 'never'; +const overrideValidationRegex = /^(always|never|whenEmpty)$/; +const playlistItemCache = {}; const pendingRequests = {}; let activeRequestCount = 0; let resumeBidRequest; +// defaults to 'always' for backwards compatibility +// TODO: Prebid 9 - replace with ENRICH_WHEN_EMPTY +let overrideContentId = ENRICH_ALWAYS; +let overrideContentUrl = ENRICH_WHEN_EMPTY; +let overrideContentTitle = ENRICH_WHEN_EMPTY; +let overrideContentDescription = ENRICH_WHEN_EMPTY; /** @type {RtdSubmodule} */ export const jwplayerSubmodule = { @@ -38,7 +48,7 @@ export const jwplayerSubmodule = { /** * add targeting data to bids and signal completion to realTimeData module * @function - * @param {Obj} bidReqConfig + * @param {object} bidReqConfig * @param {function} onDone */ getBidRequestData: enrichBidRequest, @@ -53,6 +63,7 @@ config.getConfig('realTimeData', ({realTimeData}) => { return; } fetchTargetingInformation(params); + setOverrides(params); }); submodule('realTimeData', jwplayerSubmodule); @@ -71,15 +82,32 @@ export function fetchTargetingInformation(jwTargeting) { }); } +export function setOverrides(params) { + // For backwards compatibility, default to always unless overridden by Publisher. + // TODO: Prebid 9 - replace with ENRICH_WHEN_EMPTY + overrideContentId = sanitizeOverrideParam(params.overrideContentId, ENRICH_ALWAYS); + overrideContentUrl = sanitizeOverrideParam(params.overrideContentUrl, ENRICH_WHEN_EMPTY); + overrideContentTitle = sanitizeOverrideParam(params.overrideContentTitle, ENRICH_WHEN_EMPTY); + overrideContentDescription = sanitizeOverrideParam(params.overrideContentDescription, ENRICH_WHEN_EMPTY); +} + +function sanitizeOverrideParam(overrideParam, defaultValue) { + if (overrideValidationRegex.test(overrideParam)) { + return overrideParam; + } + + return defaultValue; +} + export function fetchTargetingForMediaId(mediaId) { const ajax = ajaxBuilder(); // TODO: Avoid checking undefined vs null by setting a callback to pendingRequests. pendingRequests[mediaId] = null; ajax(`https://cdn.${JWPLAYER_DOMAIN}/v2/media/${mediaId}`, { success: function (response) { - const segment = parseSegment(response); - cacheSegments(segment, mediaId); - onRequestCompleted(mediaId, !!segment); + const item = parsePlaylistItem(response); + cachePlaylistItem(item, mediaId); + onRequestCompleted(mediaId, !!item); }, error: function () { logError('failed to retrieve targeting information'); @@ -88,8 +116,8 @@ export function fetchTargetingForMediaId(mediaId) { }); } -function parseSegment(response) { - let segment; +function parsePlaylistItem(response) { + let item; try { const data = JSON.parse(response); if (!data) { @@ -101,16 +129,16 @@ function parseSegment(response) { throw ('Empty playlist'); } - segment = playlist[0].jwpseg; + item = playlist[0]; } catch (err) { logError(err); } - return segment; + return item; } -function cacheSegments(jwpseg, mediaId) { - if (jwpseg && mediaId) { - segCache[mediaId] = jwpseg; +function cachePlaylistItem(playlistItem, mediaId) { + if (playlistItem && mediaId) { + playlistItemCache[mediaId] = playlistItem; } } @@ -167,7 +195,7 @@ export function enrichAdUnits(adUnits, ortb2Fragments = {}) { const contentData = getContentData(mediaId, contentSegments); const targeting = formatTargetingResponse(vat); enrichBids(adUnit.bids, targeting, contentId, contentData); - addOrtbSiteContent(ortb2Fragments.global, contentId, contentData); + addOrtbSiteContent(ortb2Fragments.global, contentId, contentData, vat.title, vat.description, vat.mediaUrl); }; loadVat(jwTargeting, onVatResponse); }); @@ -217,18 +245,27 @@ function loadVatForPendingRequest(playerDivId, mediaID, callback) { } export function getVatFromCache(mediaID) { - const segments = segCache[mediaID]; + const item = playlistItemCache[mediaID]; - if (!segments) { + if (!item) { return null; } + const mediaUrl = item.file ?? getFileFromSources(item); + return { - segments, + segments: item.jwpseg, + title: item.title, + description: item.description, + mediaUrl, mediaID }; } +function getFileFromSources(playlistItem) { + return playlistItem.sources?.find?.(source => !!source.file)?.file; +} + export function getVatFromPlayer(playerDivId, mediaID) { const player = getPlayer(playerDivId); if (!player) { @@ -241,12 +278,18 @@ export function getVatFromPlayer(playerDivId, mediaID) { } mediaID = mediaID || item.mediaid; + const title = item.title; + const description = item.description; + const mediaUrl = item.file; const segments = item.jwpseg; - cacheSegments(segments, mediaID) + cachePlaylistItem(item, mediaID) return { segments, - mediaID + mediaID, + title, + mediaUrl, + description }; } @@ -313,11 +356,7 @@ export function getContentData(mediaId, segments) { return contentData; } -export function addOrtbSiteContent(ortb2, contentId, contentData) { - if (!contentId && !contentData) { - return; - } - +export function addOrtbSiteContent(ortb2, contentId, contentData, contentTitle, contentDescription, contentUrl) { if (ortb2 == null) { ortb2 = {}; } @@ -325,11 +364,24 @@ export function addOrtbSiteContent(ortb2, contentId, contentData) { let site = ortb2.site = ortb2.site || {}; let content = site.content = site.content || {}; - if (contentId) { + if (shouldOverride(content.id, contentId, overrideContentId)) { content.id = contentId; } - const currentData = content.data = content.data || []; + if (shouldOverride(content.url, contentUrl, overrideContentUrl)) { + content.url = contentUrl; + } + + if (shouldOverride(content.title, contentTitle, overrideContentTitle)) { + content.title = contentTitle; + } + + if (shouldOverride(content.ext && content.ext.description, contentDescription, overrideContentDescription)) { + content.ext = content.ext || {}; + content.ext.description = contentDescription; + } + + const currentData = content.data || []; // remove old jwplayer data const data = currentData.filter(datum => datum.name !== JWPLAYER_DOMAIN); @@ -337,11 +389,26 @@ export function addOrtbSiteContent(ortb2, contentId, contentData) { data.push(contentData); } - content.data = data; + if (data.length) { + content.data = data; + } return ortb2; } +function shouldOverride(currentValue, newValue, configValue) { + switch (configValue) { + case ENRICH_ALWAYS: + return !!newValue; + case ENRICH_NEVER: + return false; + case ENRICH_WHEN_EMPTY: + return !!newValue && currentValue === undefined; + default: + return false; + } +} + function enrichBids(bids, targeting, contentId, contentData) { if (!bids) { return; diff --git a/modules/jwplayerRtdProvider.md b/modules/jwplayerRtdProvider.md index a4c2f3621e1..936cd1d10a2 100644 --- a/modules/jwplayerRtdProvider.md +++ b/modules/jwplayerRtdProvider.md @@ -78,6 +78,19 @@ realTimeData = { }; ``` +## Configuration syntax + +| Name |Type | Description | Notes | +| :------------ | :------------ | :------------ |:------------ | +| name | String | Real time data module name | Always 'jwplayer' | +| waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false | +| params | Object | | | +| params.mediaIDs | Array of Strings | Media Ids for prefetching | Optional | +| params.overrideContentId | String enum: 'always', 'whenEmpty' or 'never' | Determines when the module should update the oRTB site.content.id | Defaults to 'always' | +| params.overrideContentUrl | String enum: 'always', 'whenEmpty' or 'never' | Determines when the module should update the oRTB site.content.url | Defaults to 'whenEmpty' | +| params.overrideContentTitle | String enum: 'always', 'whenEmpty' or 'never' | Determines when the module should update the oRTB site.content.title | Defaults to 'whenEmpty' | +| params.overrideContentDescription | String enum: 'always', 'whenEmpty' or 'never' | Determines when the module should update the oRTB site.content.ext.description | Defaults to 'whenEmpty' | + # Usage for Bid Adapters: Implement the `buildRequests` function. When it is called, the `bidRequests` param will be an array of bids. @@ -94,6 +107,8 @@ Example: site: { content: { id: 'jw_abc123', + title: 'media title', + url: 'https:www.cdn.com/media.mp4', data: [{ name: 'jwplayer.com', ext: { @@ -105,7 +120,10 @@ Example: }, { id: '456' }] - }] + }], + ext: { + description: 'media description' + } } } } @@ -116,7 +134,10 @@ where: - `ortb2` is an object containing first party data - `site` is an object containing page specific information - `content` is an object containing metadata for the media. It may contain the following information: - - `id` is a unique identifier for the specific media asset + - `id` is a unique identifier for the specific media asset, + - `title` is the title of the media content + - `url` is the url of the media asset + - `ext.description` is the description of the media content - `data` is an array containing segment taxonomy objects that have the following parameters: - `name` is the `jwplayer.com` string indicating the provider name - `ext.segtax` whose `502` value is the unique identifier for JW Player's proprietary taxonomy diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js index 12fe9a7e800..c57c8a685e7 100644 --- a/test/spec/modules/jwplayerRtdProvider_spec.js +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -11,6 +11,7 @@ import { getContentSegments, getVatFromCache, getVatFromPlayer, + setOverrides, jwplayerSubmodule } from 'modules/jwplayerRtdProvider.js'; import {server} from 'test/mocks/xhr.js'; @@ -47,7 +48,9 @@ describe('jwplayerRtdProvider', function() { playlist: [ { file: 'test.mp4', - jwpseg: validSegments + jwpseg: validSegments, + title: 'test', + description: 'this is a test' } ] }) @@ -57,7 +60,44 @@ describe('jwplayerRtdProvider', function() { const validTargeting = { segments: validSegments, - mediaID: testIdForSuccess + mediaID: testIdForSuccess, + mediaUrl: 'test.mp4', + title: 'test', + description: 'this is a test' + }; + + expect(targetingInfo).to.deep.equal(validTargeting); + }); + + it('should obtain file from sources', function () { + request.respond( + 200, + responseHeader, + JSON.stringify({ + playlist: [ + { + sources: [{ + label: 'missing file', + }, { + file: 'source.mp4', + label: 'valid file' + }], + jwpseg: validSegments, + title: 'test', + description: 'this is a test' + } + ] + }) + ); + + const targetingInfo = getVatFromCache(testIdForSuccess); + + const validTargeting = { + segments: validSegments, + mediaID: testIdForSuccess, + mediaUrl: 'source.mp4', + title: 'test', + description: 'this is a test' }; expect(targetingInfo).to.deep.equal(validTargeting); @@ -82,16 +122,12 @@ describe('jwplayerRtdProvider', function() { expect(targetingInfo).to.be.null; }); - it('should not write to cache when segments are absent', function() { + it('should not write to cache when playlist is empty', function() { request.respond( 200, responseHeader, JSON.stringify({ - playlist: [ - { - file: 'test.mp4' - } - ] + playlist: [] }) ); const targetingInfo = getVatFromCache(testIdForFailure); @@ -150,26 +186,41 @@ describe('jwplayerRtdProvider', function() { describe('When jwplayer.js is on page', function () { const playlistItemWithSegmentMock = { mediaid: mediaIdWithSegment, + title: 'Media With Segment', + description: 'The media has segments', + file: 'mediaWithSegments.mp4', jwpseg: validSegments }; const targetingForMediaWithSegment = { segments: validSegments, - mediaID: mediaIdWithSegment + mediaID: mediaIdWithSegment, + title: 'Media With Segment', + description: 'The media has segments', + mediaUrl: 'mediaWithSegments.mp4', }; const playlistItemNoSegmentMock = { - mediaid: mediaIdNoSegment + mediaid: mediaIdNoSegment, + title: 'Media Without Segment', + description: 'The media has no segments', + file: 'mediaWithoutSegments.mp4', }; const currentItemSegments = ['test_seg_3', 'test_seg_4']; const currentPlaylistItemMock = { mediaid: mediaIdForCurrentItem, - jwpseg: currentItemSegments + jwpseg: currentItemSegments, + title: 'Current Item', + description: 'The current playlist item', + file: 'currentItem.mp4', }; const targetingForCurrentItem = { segments: currentItemSegments, - mediaID: mediaIdForCurrentItem + mediaID: mediaIdForCurrentItem, + title: 'Current Item', + description: 'The current playlist item', + mediaUrl: 'currentItem.mp4', }; const playerInstanceMock = { @@ -199,23 +250,23 @@ describe('jwplayerRtdProvider', function() { expect(targeting).to.be.null; }); - it('returns segments when media ID matches a playlist item with segments', function () { + it('returns targeting when media ID matches a playlist item', function () { const targeting = getVatFromPlayer(validPlayerID, mediaIdWithSegment); expect(targeting).to.deep.equal(targetingForMediaWithSegment); }); - it('caches segments when media ID matches a playist item with segments', function () { + it('caches item when media ID matches a valid playist item', function () { getVatFromPlayer(validPlayerID, mediaIdWithSegment); const vat = getVatFromCache(mediaIdWithSegment); - expect(vat.segments).to.deep.equal(validSegments); + expect(vat).to.deep.equal(targetingForMediaWithSegment); }); - it('returns segments of current item when media ID is missing', function () { + it('returns targeting of current item when media ID is missing', function () { const targeting = getVatFromPlayer(validPlayerID); expect(targeting).to.deep.equal(targetingForCurrentItem); }); - it('caches segments from the current item', function () { + it('caches metadata from the current item', function () { getVatFromPlayer(validPlayerID); window.jwplayer = null; @@ -225,10 +276,11 @@ describe('jwplayerRtdProvider', function() { it('returns undefined segments when segments are absent', function () { const targeting = getVatFromPlayer(validPlayerID, mediaIdNoSegment); - expect(targeting).to.deep.equal({ - mediaID: mediaIdNoSegment, - segments: undefined - }); + expect(targeting.segments).to.be.undefined; + expect(targeting.mediaID).to.equal(mediaIdNoSegment); + expect(targeting.title).to.equal('Media Without Segment'); + expect(targeting.description).to.equal('The media has no segments'); + expect(targeting.mediaUrl).to.equal('mediaWithoutSegments.mp4'); }); describe('Get Bid Request Data', function () { @@ -489,7 +541,9 @@ describe('jwplayerRtdProvider', function() { playlist: [ { file: 'test.mp4', - jwpseg: validSegments + jwpseg: validSegments, + title: 'test title', + description: 'test description', } ] }) @@ -498,6 +552,9 @@ describe('jwplayerRtdProvider', function() { expect(ortb2Fragments.global).to.have.property('site'); expect(ortb2Fragments.global.site).to.have.property('content'); expect(ortb2Fragments.global.site.content).to.have.property('id', 'jw_' + testIdForSuccess); + expect(ortb2Fragments.global.site.content).to.have.property('url', 'test.mp4'); + expect(ortb2Fragments.global.site.content).to.have.property('title', 'test title'); + expect(ortb2Fragments.global.site.content.ext).to.have.property('description', 'test description'); expect(ortb2Fragments.global.site.content).to.have.property('data'); const data = ortb2Fragments.global.site.content.data; expect(data).to.have.length(1); @@ -742,6 +799,15 @@ describe('jwplayerRtdProvider', function() { }); describe(' Add Ortb Site Content', function () { + beforeEach(() => { + setOverrides({ + overrideContentId: 'always', + overrideContentUrl: 'whenEmpty', + overrideContentTitle: 'whenEmpty', + overrideContentDescription: 'whenEmpty' + }); + }); + it('should maintain object structure when id and data params are empty', function () { const ortb2 = { site: { @@ -766,9 +832,15 @@ describe('jwplayerRtdProvider', function() { it('should create a structure compliant with the oRTB 2 spec', function() { const ortb2 = {} const expectedId = 'expectedId'; + const expectedUrl = 'expectedUrl'; + const expectedTitle = 'expectedTitle'; + const expectedDescription = 'expectedDescription'; const expectedData = { datum: 'datum' }; - addOrtbSiteContent(ortb2, expectedId, expectedData); + addOrtbSiteContent(ortb2, expectedId, expectedData, expectedTitle, expectedDescription, expectedUrl); expect(ortb2).to.have.nested.property('site.content.id', expectedId); + expect(ortb2).to.have.nested.property('site.content.url', expectedUrl); + expect(ortb2).to.have.nested.property('site.content.title', expectedTitle); + expect(ortb2).to.have.nested.property('site.content.ext.description', expectedDescription); expect(ortb2).to.have.nested.property('site.content.data'); expect(ortb2.site.content.data[0]).to.be.deep.equal(expectedData); }); @@ -777,11 +849,14 @@ describe('jwplayerRtdProvider', function() { const ortb2 = { site: { content: { - id: 'oldId' + id: 'oldId', + ext: { + random_field: 'randomField' + } }, random: { random_sub: 'randomSub' - } + }, }, app: { content: { @@ -791,23 +866,30 @@ describe('jwplayerRtdProvider', function() { }; const expectedId = 'expectedId'; + const expectedUrl = 'expectedUrl'; + const expectedTitle = 'expectedTitle'; + const expectedDescription = 'expectedDescription'; const expectedData = { datum: 'datum' }; - addOrtbSiteContent(ortb2, expectedId, expectedData); + addOrtbSiteContent(ortb2, expectedId, expectedData, expectedTitle, expectedDescription, expectedUrl); expect(ortb2).to.have.nested.property('site.random.random_sub', 'randomSub'); expect(ortb2).to.have.nested.property('app.content.id', 'appId'); + expect(ortb2).to.have.nested.property('site.content.ext.random_field', 'randomField'); expect(ortb2).to.have.nested.property('site.content.id', expectedId); + expect(ortb2).to.have.nested.property('site.content.url', expectedUrl); + expect(ortb2).to.have.nested.property('site.content.title', expectedTitle); + expect(ortb2).to.have.nested.property('site.content.ext.description', expectedDescription); expect(ortb2).to.have.nested.property('site.content.data'); expect(ortb2.site.content.data[0]).to.be.deep.equal(expectedData); }); - it('should set content id', function () { + it('should set content id by default when absent from ortb2', function () { const ortb2 = {}; const expectedId = 'expectedId'; addOrtbSiteContent(ortb2, expectedId); expect(ortb2).to.have.nested.property('site.content.id', expectedId); }); - it('should override content id', function () { + it('should override content id by default', function () { const ortb2 = { site: { content: { @@ -821,7 +903,7 @@ describe('jwplayerRtdProvider', function() { expect(ortb2).to.have.nested.property('site.content.id', expectedId); }); - it('should keep previous content id when not set', function () { + it('should keep previous content id when new value is not available', function () { const previousId = 'oldId'; const ortb2 = { site: { @@ -836,6 +918,122 @@ describe('jwplayerRtdProvider', function() { expect(ortb2).to.have.nested.property('site.content.id', previousId); }); + it('should override content id when override is always', function () { + setOverrides({ + overrideContentId: 'always', + }); + + const ortb2 = { + site: { + content: { + id: 'oldId' + } + } + }; + + const expectedId = 'expectedId'; + addOrtbSiteContent(ortb2, expectedId); + expect(ortb2).to.have.nested.property('site.content.id', expectedId); + }); + + it('should keep previous content id when override is always and new value is not available', function () { + setOverrides({ + overrideContentId: 'always', + }); + + const ortb2 = { + site: { + content: { + id: 'oldId' + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2).to.have.nested.property('site.content.id', 'oldId'); + }); + + it('should populate content id when override is whenEmpty and value is empty', function () { + setOverrides({ + overrideContentId: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2, 'newId'); + expect(ortb2).to.have.nested.property('site.content.id', 'newId'); + }); + + it('should keep previous content id when override is whenEmpty and value is already populated', function () { + setOverrides({ + overrideContentId: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + id: 'oldId' + } + } + }; + + addOrtbSiteContent(ortb2, 'newId'); + expect(ortb2).to.have.nested.property('site.content.id', 'oldId'); + }); + + it('should keep previous content id when override is whenEmpty and new value is not available', function () { + setOverrides({ + overrideContentId: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2.site.content.id).to.be.undefined; + }); + + it('should keep previous content id when overrideContentId is set to never', function () { + setOverrides({ + overrideContentId: 'never', + }); + + const ortb2 = { + site: { + content: { + id: 'oldId' + } + } + }; + + addOrtbSiteContent(ortb2, 'newId'); + expect(ortb2).to.have.nested.property('site.content.id', 'oldId'); + }); + + it('should not populate content id when override is set to never', function () { + setOverrides({ + overrideContentId: 'never', + }); + + const ortb2 = { + site: { + content: {} + } + }; + + addOrtbSiteContent(ortb2, 'newId'); + expect(ortb2.site.content.id).to.be.undefined; + }); + it('should set content data', function () { const ortb2 = {}; const expectedData = { datum: 'datum' }; @@ -878,6 +1076,451 @@ describe('jwplayerRtdProvider', function() { expect(ortb2.site.content.data[0]).to.be.deep.equal(expectedData); expect(ortb2).to.have.nested.property('site.content.id', expectedId); }); + + it('should set content title by default when absent from ortb2', function () { + const ortb2 = {}; + const expectedTitle = 'expectedTitle'; + addOrtbSiteContent(ortb2, null, null, expectedTitle); + expect(ortb2).to.have.nested.property('site.content.title', expectedTitle); + }); + + it('should keep previous content title by default when already defined', function () { + const ortb2 = { + site: { + content: { + title: 'oldTitle' + } + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2).to.have.nested.property('site.content.title', 'oldTitle'); + }); + + it('should keep previous content title by default when new value is not available', function () { + const ortb2 = { + site: { + content: { + title: 'oldTitle', + data: [{ datum: 'first_datum' }] + } + } + }; + + addOrtbSiteContent(ortb2, null, { datum: 'new_datum' }); + expect(ortb2).to.have.nested.property('site.content.title', 'oldTitle'); + }); + + it('should override content title when override is always', function () { + setOverrides({ + overrideContentTitle: 'always', + }); + + const ortb2 = { + site: { + content: { + title: 'oldTitle' + } + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2).to.have.nested.property('site.content.title', 'newTitle'); + }); + + it('should keep previous content title when override is always and new value is not available', function () { + setOverrides({ + overrideContentTitle: 'always', + }); + + const ortb2 = { + site: { + content: { + title: 'oldTitle' + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2).to.have.nested.property('site.content.title', 'oldTitle'); + }); + + it('should populate content title when override is whenEmpty and value is empty', function () { + setOverrides({ + overrideContentTitle: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2).to.have.nested.property('site.content.title', 'newTitle'); + }); + + it('should keep previous content title when override is whenEmpty and value is already populated', function () { + setOverrides({ + overrideContentTitle: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + title: 'oldTitle' + } + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2).to.have.nested.property('site.content.title', 'oldTitle'); + }); + + it('should keep previous content title when override is whenEmpty and new value is not available', function () { + setOverrides({ + overrideContentTitle: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2.site.content.title).to.be.undefined; + }); + + it('should keep previous content title when override is set to never', function () { + setOverrides({ + overrideContentTitle: 'never', + }); + + const ortb2 = { + site: { + content: { + title: 'oldTitle' + } + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2).to.have.nested.property('site.content.title', 'oldTitle'); + }); + + it('should not populate content title when override is set to never', function () { + setOverrides({ + overrideContentTitle: 'never', + }); + + const ortb2 = { + site: { + content: {} + } + }; + + addOrtbSiteContent(ortb2, null, null, 'newTitle'); + expect(ortb2.site.content.title).to.be.undefined; + }); + + it('should set content description by default when absent from ortb2', function () { + const ortb2 = {}; + const expectedDescription = 'expectedDescription'; + addOrtbSiteContent(ortb2, null, null, null, expectedDescription); + expect(ortb2).to.have.nested.property('site.content.ext.description', expectedDescription); + }); + + it('should keep previous content description by default when already defined', function () { + const ortb2 = { + site: { + content: { + ext: { + description: 'oldDescription' + } + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, 'newDescription'); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'oldDescription'); + }); + + it('should override content description when override is always', function () { + setOverrides({ + overrideContentDescription: 'always', + }); + + const ortb2 = { + site: { + content: { + ext: { + description: 'oldDescription' + } + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, 'newDescription'); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'newDescription'); + }); + + it('should keep previous content description when override is always and new value is not available', function () { + setOverrides({ + overrideContentDescription: 'always', + }); + + const ortb2 = { + site: { + content: { + ext: { + description: 'oldDescription' + } + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'oldDescription'); + }); + + it('should populate content description when override is whenEmpty and value is empty', function () { + setOverrides({ + overrideContentDescription: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, 'newDescription'); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'newDescription'); + }); + + it('should keep previous content description when override is whenEmpty and value is already populated', function () { + setOverrides({ + overrideContentDescription: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + ext: { + description: 'oldDescription' + } + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, 'newDescription'); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'oldDescription'); + }); + + it('should keep previous content description when override is whenEmpty and new value is not available', function () { + setOverrides({ + overrideContentDescription: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2.site.content.ext).to.be.undefined; + }); + + it('should keep previous content description when override is set to never', function () { + setOverrides({ + overrideContentDescription: 'never', + }); + + const ortb2 = { + site: { + content: { + ext: { + description: 'oldDescription' + } + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, 'newDescription'); + expect(ortb2).to.have.nested.property('site.content.ext.description', 'oldDescription'); + }); + + it('should not populate content description when override is set to never', function () { + setOverrides({ + overrideContentDescription: 'never', + }); + + const ortb2 = { + site: { + content: {} + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2.site.content.ext).to.be.undefined; + }); + + it('should set content url by default when absent from ortb2', function () { + const ortb2 = {}; + const expectedUrl = 'expectedUrl'; + addOrtbSiteContent(ortb2, null, null, null, null, expectedUrl); + expect(ortb2).to.have.nested.property('site.content.url', expectedUrl); + }); + + it('should keep previous content url by default when new value is not available', function () { + const ortb2 = { + site: { + content: { + url: 'oldUrl', + data: [{ datum: 'first_datum' }] + } + } + }; + + addOrtbSiteContent(ortb2, null, { datum: 'new_datum' }); + expect(ortb2).to.have.nested.property('site.content.url', 'oldUrl'); + }); + + it('should keep previous content url by default when already defined', function () { + const ortb2 = { + site: { + content: { + url: 'oldUrl', + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, null, 'newUrl'); + expect(ortb2).to.have.nested.property('site.content.url', 'oldUrl'); + }); + + it('should override content url when override is always', function () { + setOverrides({ + overrideContentUrl: 'always', + }); + + const ortb2 = { + site: { + content: { + url: 'oldUrl', + } + } + }; + + const expectedUrl = 'expectedUrl'; + addOrtbSiteContent(ortb2, null, null, null, null, expectedUrl); + expect(ortb2).to.have.nested.property('site.content.url', expectedUrl); + }); + + it('should keep previous content url when override is always and new value is not available', function () { + setOverrides({ + overrideContentUrl: 'always', + }); + + const ortb2 = { + site: { + content: { + url: 'oldUrl', + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2).to.have.nested.property('site.content.url', 'oldUrl'); + }); + + it('should populate content url when override is whenEmpty and value is empty', function () { + setOverrides({ + overrideContentUrl: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + const expectedUrl = 'expectedUrl'; + addOrtbSiteContent(ortb2, null, null, null, null, expectedUrl); + expect(ortb2).to.have.nested.property('site.content.url', expectedUrl); + }); + + it('should keep previous content url when override is whenEmpty and value is already populated', function () { + setOverrides({ + overrideContentUrl: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + url: 'oldUrl', + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, null, 'newUrl'); + expect(ortb2).to.have.nested.property('site.content.url', 'oldUrl'); + }); + + it('should keep previous content url when override is whenEmpty and new value is not available', function () { + setOverrides({ + overrideContentUrl: 'whenEmpty', + }); + + const ortb2 = { + site: { + content: { + } + } + }; + + addOrtbSiteContent(ortb2); + expect(ortb2.site.content.url).to.be.undefined; + }); + + it('should keep previous content url when override is set to never', function () { + setOverrides({ + overrideContentUrl: 'never', + }); + + const ortb2 = { + site: { + content: { + url: 'oldUrl', + } + } + }; + + addOrtbSiteContent(ortb2, null, null, null, null, 'newUrl'); + expect(ortb2).to.have.nested.property('site.content.url', 'oldUrl'); + }); + + it('should not populate content url when override is set to never', function () { + setOverrides({ + overrideContentUrl: 'never', + }); + + const ortb2 = { + site: { + content: {} + } + }; + + addOrtbSiteContent(ortb2, null, null, null, null, 'newUrl'); + expect(ortb2.site.content.url).to.be.undefined; + }); }); describe('Add Targeting to Bid', function () { From 5e48d3b5df34db28862f3358e5253584ef7d75e3 Mon Sep 17 00:00:00 2001 From: Ilia Medvedev Date: Thu, 11 Apr 2024 16:34:39 +0400 Subject: [PATCH 003/147] Limelight Digital Bid Adapter : add page field (#11312) * Limelight Digital Bid Adapter: Add page field * fix typo * add referrer field * remove referrer field --- modules/limelightDigitalBidAdapter.js | 3 ++- .../modules/limelightDigitalBidAdapter_spec.js | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index acc76014abe..5cccf5300b3 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -169,7 +169,8 @@ function buildPlacement(bidRequest) { custom2: bidRequest.params.custom2, custom3: bidRequest.params.custom3, custom4: bidRequest.params.custom4, - custom5: bidRequest.params.custom5 + custom5: bidRequest.params.custom5, + page: bidRequest.refererInfo.page } } } diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index 0e6f4817e5e..6348d6a1ac6 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -17,6 +17,9 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, + refererInfo: { + page: 'https://publisher.com/page1' + }, placementCode: 'placement_0', auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', mediaTypes: { @@ -65,6 +68,9 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, + refererInfo: { + page: 'https://publisher.com/page2' + }, placementCode: 'placement_1', auctionId: '482f88de-29ab-45c8-981a-d25e39454a34', sizes: [[350, 200]], @@ -115,6 +121,9 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, + refererInfo: { + page: 'https://publisher.com/page3' + }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', sizes: [[800, 600]], @@ -162,6 +171,9 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, + refererInfo: { + page: 'https://publisher.com/page4' + }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', video: { @@ -237,7 +249,8 @@ describe('limelightDigitalAdapter', function () { 'custom2', 'custom3', 'custom4', - 'custom5' + 'custom5', + 'page' ); expect(adUnit.id).to.be.a('number'); expect(adUnit.bidId).to.be.a('string'); @@ -251,6 +264,7 @@ describe('limelightDigitalAdapter', function () { expect(adUnit.custom3).to.be.a('string'); expect(adUnit.custom4).to.be.a('string'); expect(adUnit.custom5).to.be.a('string'); + expect(adUnit.page).to.be.a('string'); }) }) }) @@ -685,4 +699,5 @@ function validateAdUnit(adUnit, bid) { expect(adUnit.publisherId).to.equal(bid.params.publisherId); expect(adUnit.userIdAsEids).to.deep.equal(bid.userIdAsEids); expect(adUnit.supplyChain).to.deep.equal(bid.schain); + expect(adUnit.page).to.equal(bid.refererInfo.page); } From 3aed8aa09e829893241875bb113f306a88700737 Mon Sep 17 00:00:00 2001 From: Antonios Sarhanis Date: Thu, 11 Apr 2024 22:52:28 +1000 Subject: [PATCH 004/147] Adnuntius Bid Adapter: change ad request format (#11321) --- modules/adnuntiusBidAdapter.js | 2 +- test/spec/modules/adnuntiusBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index eb5f3c19dea..97419fb94bd 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -182,7 +182,7 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { const queryParamsAndValues = []; queryParamsAndValues.push('tzo=' + new Date().getTimezoneOffset()) - queryParamsAndValues.push('format=json') + queryParamsAndValues.push('format=prebid') const gdprApplies = deepAccess(bidderRequest, 'gdprConsent.gdprApplies'); const consentString = deepAccess(bidderRequest, 'gdprConsent.consentString'); if (gdprApplies !== undefined) { diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index 71f0a6a3a6c..0e0206c2933 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -37,12 +37,12 @@ describe('adnuntiusBidAdapter', function() { }); const tzo = new Date().getTimezoneOffset(); - const ENDPOINT_URL_BASE = `${URL}${tzo}&format=json`; + const ENDPOINT_URL_BASE = `${URL}${tzo}&format=prebid`; const ENDPOINT_URL = `${ENDPOINT_URL_BASE}&userId=${usi}`; const ENDPOINT_URL_VIDEO = `${ENDPOINT_URL_BASE}&userId=${usi}&tt=vast4`; const ENDPOINT_URL_NOCOOKIE = `${ENDPOINT_URL_BASE}&userId=${usi}&noCookies=true`; const ENDPOINT_URL_SEGMENTS = `${ENDPOINT_URL_BASE}&segments=segment1,segment2,segment3&userId=${usi}`; - const ENDPOINT_URL_CONSENT = `${EURO_URL}${tzo}&format=json&consentString=consentString&gdpr=1&userId=${usi}`; + const ENDPOINT_URL_CONSENT = `${EURO_URL}${tzo}&format=prebid&consentString=consentString&gdpr=1&userId=${usi}`; const adapter = newBidder(spec); const bidderRequests = [ From 007a3b0e2e1e3d21965fb9355fbf7f1de77b0c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Leclerc?= Date: Thu, 11 Apr 2024 15:04:18 +0200 Subject: [PATCH 005/147] teads: Add more device information to payload (#11316) --- modules/teadsBidAdapter.js | 2 ++ test/spec/modules/teadsBidAdapter_spec.js | 35 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index 1108c12c822..a3c8d3e24dc 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -62,6 +62,8 @@ export const spec = { timeToFirstByte: getTimeToFirstByte(window), data: bids, deviceWidth: screen.width, + deviceHeight: screen.height, + devicePixelRatio: topWindow.devicePixelRatio, screenOrientation: screen.orientation?.type, historyLength: topWindow.history?.length, viewportHeight: topWindow.visualViewport?.height, diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js index 1e044651315..81e09b09d08 100644 --- a/test/spec/modules/teadsBidAdapter_spec.js +++ b/test/spec/modules/teadsBidAdapter_spec.js @@ -255,6 +255,33 @@ describe('teadsBidAdapter', () => { expect(payload.pageReferrer).to.deep.equal(document.referrer); }); + it('should add width info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderRequestDefault); + const payload = JSON.parse(request.data); + const deviceWidth = screen.width + + expect(payload.deviceWidth).to.exist; + expect(payload.deviceWidth).to.deep.equal(deviceWidth); + }); + + it('should add height info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderRequestDefault); + const payload = JSON.parse(request.data); + const deviceHeight = screen.height + + expect(payload.deviceHeight).to.exist; + expect(payload.deviceHeight).to.deep.equal(deviceHeight); + }); + + it('should add pixelRatio info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderRequestDefault); + const payload = JSON.parse(request.data); + const pixelRatio = window.top.devicePixelRatio + + expect(payload.devicePixelRatio).to.exist; + expect(payload.devicePixelRatio).to.deep.equal(pixelRatio); + }); + it('should add screenOrientation info to payload', function () { const request = spec.buildRequests(bidRequests, bidderRequestDefault); const payload = JSON.parse(request.data); @@ -290,6 +317,14 @@ describe('teadsBidAdapter', () => { expect(payload.viewportWidth).to.deep.equal(window.top.visualViewport.width); }); + it('should add viewportHeight info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderRequestDefault); + const payload = JSON.parse(request.data); + + expect(payload.viewportHeight).to.exist; + expect(payload.viewportHeight).to.deep.equal(window.top.visualViewport.height); + }); + it('should add hardwareConcurrency info to payload', function () { const request = spec.buildRequests(bidRequests, bidderRequestDefault); const payload = JSON.parse(request.data); From e51046edd5daddb902a12d821bdc6aa0073d94bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Thu, 11 Apr 2024 15:20:26 +0200 Subject: [PATCH 006/147] Grid Bid Adapter : fix invalid DSA adrender field mapping (#11313) * Criteo Bid Adapter: Fix invalid DSA adrender field mapping * Grid Bid Adapter: Fix invalid DSA adrender field mapping --- modules/gridBidAdapter.js | 4 ++-- test/spec/modules/gridBidAdapter_spec.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index d56639ed714..f7db6d878f1 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -554,8 +554,8 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid bidResponse.meta.demandSource = serverBid.ext.bidder.grid.demandSource; } - if (serverBid.ext && serverBid.ext.dsa && serverBid.ext.dsa.adrender) { - bidResponse.meta.adrender = serverBid.ext.dsa.adrender; + if (serverBid.ext && serverBid.ext.dsa) { + bidResponse.meta.dsa = serverBid.ext.dsa; } if (serverBid.content_type === 'video') { diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index abaa4b37fcd..efd7b06685f 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -1430,7 +1430,9 @@ describe('TheMediaGrid Adapter', function () { 'netRevenue': true, 'ttl': 360, 'meta': { - adrender: 1, + dsa: { + adrender: 1 + }, advertiserDomains: [] }, }, From 9aff4adeab156a5ecc5949fd24e4c4facd49fc33 Mon Sep 17 00:00:00 2001 From: teqblaze <162988436+teqblaze@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:42:59 +0300 Subject: [PATCH 007/147] Loyal Bid Adapter: initial release (#11253) * init loyal adapter * fix linter * upd * fix linter --------- Co-authored-by: loyal --- modules/loyalBidAdapter.js | 190 +++++++++++ modules/loyalBidAdapter.md | 79 +++++ test/spec/modules/loyalBidAdapter_spec .js | 375 +++++++++++++++++++++ 3 files changed, 644 insertions(+) create mode 100644 modules/loyalBidAdapter.js create mode 100644 modules/loyalBidAdapter.md create mode 100644 test/spec/modules/loyalBidAdapter_spec .js diff --git a/modules/loyalBidAdapter.js b/modules/loyalBidAdapter.js new file mode 100644 index 00000000000..30fdeb44233 --- /dev/null +++ b/modules/loyalBidAdapter.js @@ -0,0 +1,190 @@ +import { logMessage, logError } from '../src/utils.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'loyal'; +const AD_URL = 'https://us-east-1.loyal.app/pbjs'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl || bid.vastXml); + case NATIVE: + return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length); + default: + return false; + } +} + +function getPlacementReqData(bid) { + const { params, bidId, mediaTypes } = bid; + const schain = bid.schain || {}; + const { placementId, endpointId } = params; + const bidfloor = getBidFloor(bid); + + const placement = { + bidId, + schain, + bidfloor, + eids: [] + }; + + if (placementId) { + placement.placementId = placementId; + placement.type = 'publisher'; + } else if (endpointId) { + placement.endpointId = endpointId; + placement.type = 'network'; + } + + if (mediaTypes && mediaTypes[BANNER]) { + placement.adFormat = BANNER; + placement.sizes = mediaTypes[BANNER].sizes; + } else if (mediaTypes && mediaTypes[VIDEO]) { + placement.adFormat = VIDEO; + placement.playerSize = mediaTypes[VIDEO].playerSize; + placement.minduration = mediaTypes[VIDEO].minduration; + placement.maxduration = mediaTypes[VIDEO].maxduration; + placement.mimes = mediaTypes[VIDEO].mimes; + placement.protocols = mediaTypes[VIDEO].protocols; + placement.startdelay = mediaTypes[VIDEO].startdelay; + placement.placement = mediaTypes[VIDEO].placement; + placement.skip = mediaTypes[VIDEO].skip; + placement.skipafter = mediaTypes[VIDEO].skipafter; + placement.minbitrate = mediaTypes[VIDEO].minbitrate; + placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; + placement.delivery = mediaTypes[VIDEO].delivery; + placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; + placement.api = mediaTypes[VIDEO].api; + placement.linearity = mediaTypes[VIDEO].linearity; + } else if (mediaTypes && mediaTypes[NATIVE]) { + placement.native = mediaTypes[NATIVE]; + placement.adFormat = NATIVE; + } + + return placement; +} + +function getBidFloor(bid) { + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid = {}) => { + const { params, bidId, mediaTypes } = bid; + let valid = Boolean(bidId && params && (params.placementId || params.endpointId)); + + if (mediaTypes && mediaTypes[BANNER]) { + valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes); + } else if (mediaTypes && mediaTypes[VIDEO]) { + valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize); + } else if (mediaTypes && mediaTypes[NATIVE]) { + valid = valid && Boolean(mediaTypes[NATIVE]); + } else { + valid = false; + } + return valid; + }, + + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + // convert Native ORTB definition to old-style prebid native definition + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + + let deviceWidth = 0; + let deviceHeight = 0; + + let winLocation; + try { + const winTop = window.top; + deviceWidth = winTop.screen.width; + deviceHeight = winTop.screen.height; + winLocation = winTop.location; + } catch (e) { + logMessage(e); + winLocation = window.location; + } + + const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page; + let refferLocation; + try { + refferLocation = refferUrl && new URL(refferUrl); + } catch (e) { + logMessage(e); + } + // TODO: does the fallback make sense here? + let location = refferLocation || winLocation; + const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : ''; + const host = location.host; + const page = location.pathname; + const secure = location.protocol === 'https:' ? 1 : 0; + const placements = []; + const request = { + deviceWidth, + deviceHeight, + language, + secure, + host, + page, + placements, + coppa: config.getConfig('coppa') === true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined, + tmax: bidderRequest.timeout + }; + + if (bidderRequest.gdprConsent?.consentString) { + request.gdpr = { + consentString: bidderRequest.gdprConsent.consentString + }; + } + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + placements.push(getPlacementReqData(bid)); + } + + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; + resItem.meta = { ...resItem.meta, advertiserDomains }; + + response.push(resItem); + } + } + return response; + }, +}; + +registerBidder(spec); diff --git a/modules/loyalBidAdapter.md b/modules/loyalBidAdapter.md new file mode 100644 index 00000000000..db77c04c34f --- /dev/null +++ b/modules/loyalBidAdapter.md @@ -0,0 +1,79 @@ +# Overview + +``` +Module Name: Loyal Bidder Adapter +Module Type: Loyal Bidder Adapter +Maintainer: hello@loyal.app +``` + +# Description + +Connects to Loyal exchange for bids. +Loyal bid adapter supports Banner, Video (instream and outstream) and Native. + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'adunit1', + mediaTypes: { + banner: { + sizes: [ [300, 250], [320, 50] ], + } + }, + bids: [ + { + bidder: 'loyal', + params: { + placementId: 'testBanner', + } + } + ] + }, + { + code: 'addunit2', + mediaTypes: { + video: { + playerSize: [ [640, 480] ], + context: 'instream', + minduration: 5, + maxduration: 60, + } + }, + bids: [ + { + bidder: 'loyal', + params: { + placementId: 'testVideo', + } + } + ] + }, + { + code: 'addunit3', + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + }, + bids: [ + { + bidder: 'loyal', + params: { + placementId: 'testNative', + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/test/spec/modules/loyalBidAdapter_spec .js b/test/spec/modules/loyalBidAdapter_spec .js new file mode 100644 index 00000000000..28e87fc7047 --- /dev/null +++ b/test/spec/modules/loyalBidAdapter_spec .js @@ -0,0 +1,375 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/loyalBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'loyal' + +describe('LoyalBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative', + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: { + consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw' + }, + refererInfo: { + referer: 'https://test.com' + }, + timeout: 500 + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, bidderRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://us-east-1.loyal.app/pbjs'); + }); + + it('Returns general data valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', + 'deviceHeight', + 'language', + 'secure', + 'host', + 'page', + 'placements', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + expect(data.coppa).to.be.a('number'); + expect(data.gdpr).to.be.a('object'); + expect(data.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + expect(placement.eids).to.exist.and.to.be.an('array'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('object'); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([], bidderRequest); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); +}); From 19fce05a2ee0c6fc4f7d6c2217ba19feb5dc220e Mon Sep 17 00:00:00 2001 From: ecoeco163 <147788250+ecoeco163@users.noreply.github.com> Date: Fri, 12 Apr 2024 21:17:36 +0800 Subject: [PATCH 008/147] Discovery Bid Adapter : build UTM tag data (#11317) * feat(isBidRequestValid): just filter token once. not filter publisher and tagid * feat(isBidRequestValid): add unit test * feat(spec): fix eslint * feat(spec): fix unit test * feat(spec): fix unit test * feat(ext): change default value * feat(utm): build UTMTag data * feat(spec): fix utm test --------- Co-authored-by: yubei01 --- modules/discoveryBidAdapter.js | 21 +++++++++++ test/spec/modules/discoveryBidAdapter_spec.js | 36 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index de2fd3c3a94..7493dcb9af4 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -25,6 +25,9 @@ const COOKIE_RETENTION_TIME = 365 * 24 * 60 * 60 * 1000; // 1 year const COOKY_SYNC_IFRAME_URL = 'https://asset.popin.cc/js/cookieSync.html'; export const THIRD_PARTY_COOKIE_ORIGIN = 'https://asset.popin.cc'; +const UTM_KEY = '_ss_pp_utm'; +let UTMValue = {}; + const NATIVERET = { id: 'id', bidfloor: 0, @@ -409,6 +412,20 @@ function getItems(validBidRequests, bidderRequest) { return items; } +export const buildUTMTagData = (url) => { + if (!storage.cookiesAreEnabled()) return; + const urlParams = utils.parseUrl(url).search; + const UTMParams = {}; + Object.keys(urlParams).forEach(key => { + if (/^utm_/.test(key)) { + UTMParams[key] = urlParams[key]; + } + }); + UTMValue = JSON.parse(storage.getCookie(UTM_KEY) || '{}'); + Object.assign(UTMValue, UTMParams); + storage.setCookie(UTM_KEY, JSON.stringify(UTMValue), getCurrentTimeToUTCString()); +} + /** * get rtb qequest params * @@ -443,6 +460,10 @@ function getParam(validBidRequests, bidderRequest) { const desc = getPageDescription(); const keywords = getPageKeywords(); + try { + buildUTMTagData(page); + } catch (error) { } + if (items && items.length) { let c = { // TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781 diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index f1475ec3739..d148d5062a4 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -9,7 +9,8 @@ import { getConnectionDownLink, THIRD_PARTY_COOKIE_ORIGIN, COOKIE_KEY_MGUID, - getCurrentTimeToUTCString + getCurrentTimeToUTCString, + buildUTMTagData } from 'modules/discoveryBidAdapter.js'; import * as utils from 'src/utils.js'; @@ -252,6 +253,39 @@ describe('discovery:BidAdapterTests', function () { expect(storage.setCookie.calledOnce).to.be.false; }); }) + describe('buildUTMTagData function', function() { + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(storage, 'getCookie'); + sandbox.stub(storage, 'setCookie'); + sandbox.stub(utils, 'parseUrl').returns({ + search: { + utm_source: 'example.com' + } + }); + sandbox.stub(storage, 'cookiesAreEnabled'); + }) + + afterEach(() => { + sandbox.restore(); + }); + + it('should set UTM cookie', () => { + storage.cookiesAreEnabled.callsFake(() => true); + storage.getCookie.callsFake(() => null); + buildUTMTagData(); + expect(storage.setCookie.calledOnce).to.be.true; + }); + + it('should not set UTM when cookies are not enabled', () => { + storage.cookiesAreEnabled.callsFake(() => false); + storage.getCookie.callsFake(() => null); + buildUTMTagData(); + expect(storage.setCookie.calledOnce).to.be.false; + }); + }) }); it('discovery:validate_response_params', function () { From bee8ce7d041c2f90b1fec0a48b08070eb8a980c3 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 12 Apr 2024 17:15:41 +0000 Subject: [PATCH 009/147] Prebid 8.44.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b65a43a197e..a641f81805c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.44.0-pre", + "version": "8.44.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index b7a1e1bafab..463c0aed8ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.44.0-pre", + "version": "8.44.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From eb9b407b3056e333111c48c9477bf619f66262cb Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Fri, 12 Apr 2024 17:15:41 +0000 Subject: [PATCH 010/147] Increment version to 8.45.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a641f81805c..6fb87a7dcdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.44.0", + "version": "8.45.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 463c0aed8ec..88a72f3c258 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.44.0", + "version": "8.45.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 32eebd03e987483933475e46edb11fe7c4e1c75e Mon Sep 17 00:00:00 2001 From: kapil-tuptewar <91458408+kapil-tuptewar@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:41:59 +0530 Subject: [PATCH 011/147] removed transformbidparams from pubmaticbidadapter (#11328) --- modules/pubmaticBidAdapter.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index f28feaa534d..846c59c1ae5 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -5,7 +5,6 @@ import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { bidderSettings } from '../src/bidderSettings.js'; import CONSTANTS from '../src/constants.json'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -1448,20 +1447,6 @@ export const spec = { url: USER_SYNC_URL_IMAGE + syncurl }]; } - }, - - /** - * Covert bid param types for S2S - * @param {Object} params bid params - * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol - * @return {Object} params bid params - */ - - transformBidParams: function (params, isOpenRtb, adUnit, bidRequests) { - return convertTypes({ - 'publisherId': 'string', - 'adSlot': 'string' - }, params); } }; From 7cbc29b74f60231cd3af29b0392dcd047d918912 Mon Sep 17 00:00:00 2001 From: Tachfine Date: Mon, 15 Apr 2024 13:23:22 +0200 Subject: [PATCH 012/147] Criteo Bid Adapter : add support for grid bid parameters (#11315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Support optional pubid bid parameter * 🩹 Fix publisher id in test * ✨ Support optional uid bid parameter * 🩹 Bidder param uid is an integer --- modules/criteoBidAdapter.js | 9 +++++ test/spec/modules/criteoBidAdapter_spec.js | 47 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 2c0cacb7909..968a847708e 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -473,6 +473,7 @@ function checkNativeSendId(bidRequest) { */ function buildCdbRequest(context, bidRequests, bidderRequest) { let networkId; + let pubid; let schain; let userIdAsEids; let regs = Object.assign({}, { @@ -490,6 +491,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { userIdAsEids = bidRequest.userIdAsEids; } networkId = bidRequest.params.networkId || networkId; + pubid = bidRequest.params.pubid || pubid; schain = bidRequest.schain || schain; const slot = { slotid: bidRequest.bidId, @@ -513,6 +515,10 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (bidRequest.nativeOrtbRequest?.assets) { slot.ext = Object.assign({}, slot.ext, { assets: bidRequest.nativeOrtbRequest.assets }); } + if (bidRequest.params.uid) { + slot.ext = Object.assign({}, slot.ext, { bidder: { uid: bidRequest.params.uid } }); + } + if (bidRequest.params.publisherSubId) { slot.publishersubid = bidRequest.params.publisherSubId; } @@ -581,6 +587,9 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (networkId) { request.publisher.networkid = networkId; } + if (pubid) { + request.publisher.id = pubid; + } request.source = { tid: bidderRequest.ortb2?.source?.tid diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 2cdb09f2098..083ae368afb 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1949,6 +1949,53 @@ describe('The Criteo bidding adapter', function () { expect(request.data.slots[0].ext).to.not.have.property('ae'); }); + it('should properly transmit the pubid and slot uid if available', function () { + const bidderRequest = {}; + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + ortb2Imp: { + ext: { + tid: 'transaction-123', + }, + }, + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + { + bidder: 'criteo', + adUnitCode: 'bid-234', + ortb2Imp: { + ext: { + tid: 'transaction-234', + }, + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + pubid: 'pub-888', + uid: 888 + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.publisher.id).to.equal('pub-888'); + expect(request.data.slots[0].ext.bidder).to.be.undefined; + expect(request.data.slots[1].ext.bidder.uid).to.equal(888); + }); + it('should properly transmit device.ext.cdep if available', function () { const bidderRequest = { ortb2: { From 216c690cc54fa4163c13e05b68514c9b19bd97ce Mon Sep 17 00:00:00 2001 From: decemberWP <155962474+decemberWP@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:41:03 +0200 Subject: [PATCH 013/147] Piridsystem: New ID System for WPM (#11267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update tests for sspBC adapter Update tests for sspBC adapter: - change userSync test (due to tcf param appended in v4.6) - add tests for onBidWon and onTimeout * [sspbc-adapter] 5.3 updates: content-type for notifications * [sspbc-adapter] pass CTA to native bid * [sspbc-5.3] keep pbsize for detected adunits * [maintenance] - remove old test for sspBc bid adaptor * [sspbc-5.3] increment adaptor ver * [sspbc-adapter] maintenance update to sspBCBidAdapter * remove yarn.lock * Delete package-lock.json * remove package-lock.jsonfrom pull request * [sspbc-adapter] send pageViewId in request * [sspbc-adapter] update pageViewId test * [sspbc-adapter] add viewabiility tracker to native ads * [sspbc-adapter] add support for bid.admNative property * [sspbc-adapter] ensure that placement id length is always 3 (improves matching response to request) * [sspbc-adapter] read publisher id and custom ad label, then send them to banner creative * [sspbc-adapter] adlabel and pubid are set as empty strings, if not present in bid response * [sspbc-adapter] jstracker data fix * [sspbc-adapter] jstracker data fix * [sspbc-adapter] send tagid in notifications * [sspbc-adapter] add gvlid to spec; prepare getUserSyncs for iframe + image sync * update remote repo * cleanup of grupawp/prebid master branch * update sspBC adapter to v 5.9 * update tests for sspBC bid adapter * [sspbc-adapter] add support for topicsFPD module * [sspbc-adapter] change topic segment ids to int * add pirIdSystem * pirIdSystem * piridSystem - preCR * fix after CR --------- Co-authored-by: wojciech-bialy-wpm <67895844+wojciech-bialy-wpm@users.noreply.github.com> Co-authored-by: Wojciech Biały Co-authored-by: Wojciech Biały --- modules/pirIdSystem.js | 62 +++++++++++++++++++++ modules/pirIdSystem.md | 27 ++++++++++ test/spec/modules/pirIdSystem_spec.js | 77 +++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 modules/pirIdSystem.js create mode 100644 modules/pirIdSystem.md create mode 100644 test/spec/modules/pirIdSystem_spec.js diff --git a/modules/pirIdSystem.js b/modules/pirIdSystem.js new file mode 100644 index 00000000000..b891e1d362a --- /dev/null +++ b/modules/pirIdSystem.js @@ -0,0 +1,62 @@ +/** + * This module adds pirId to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/pirId + * @requires module:modules/userId + */ + +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { submodule } from '../src/hook.js'; +import {domainOverrideToRootDomain} from '../libraries/domainOverrideToRootDomain/index.js'; + +/** + * @typedef {import('../modules/userId/index.js').Submodule} Submodule + * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse + */ + +const MODULE_NAME = 'pirId'; +const ID_TOKEN = 'WPxid'; +export const storage = getStorageManager({ moduleName: MODULE_NAME, moduleType: MODULE_TYPE_UID }); + +/** + * Reads the ID token from local storage or cookies. + * @returns {string|undefined} The ID token, or undefined if not found. + */ +export const readId = () => storage.getDataFromLocalStorage(ID_TOKEN) || storage.getCookie(ID_TOKEN); + +/** @type {Submodule} */ +export const pirIdSubmodule = { + name: MODULE_NAME, + gvlid: 676, + + /** + * decode the stored id value for passing to bid requests + * @function decode + * @param {string} value + * @returns {(Object|undefined)} + */ + decode(value) { + return typeof value === 'string' ? { 'pirId': value } : undefined; + }, + + /** + * performs action to obtain id and return a value + * @function + * @returns {(IdResponse|undefined)} + */ + getId() { + const pirIdToken = readId(); + + return pirIdToken ? { id: pirIdToken } : undefined; + }, + domainOverride: domainOverrideToRootDomain(storage, MODULE_NAME), + eids: { + 'pirId': { + source: 'pir.wp.pl', + atype: 1 + }, + }, +}; + +submodule('userId', pirIdSubmodule); diff --git a/modules/pirIdSystem.md b/modules/pirIdSystem.md new file mode 100644 index 00000000000..913804f85c4 --- /dev/null +++ b/modules/pirIdSystem.md @@ -0,0 +1,27 @@ +# Overview + +Module Name: pirIDSystem +Module Type: UserID Module +Maintainer: pawel.grudzien@grupawp.pl + +# Description + +User identification system for WPM + +### Prebid Params example + +``` +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'pirID', + storage: { + type: 'cookie', + name: 'pirIdToken', + expires: 7, + refreshInSeconds: 360 + }, + }] + } +}); +``` diff --git a/test/spec/modules/pirIdSystem_spec.js b/test/spec/modules/pirIdSystem_spec.js new file mode 100644 index 00000000000..5acc5a5eb9c --- /dev/null +++ b/test/spec/modules/pirIdSystem_spec.js @@ -0,0 +1,77 @@ +import { pirIdSubmodule, storage, readId } from 'modules/pirIdSystem.js'; +import sinon from 'sinon'; + +describe('pirIdSystem', () => { + let sandbox; + let getCookieStub; + let getDataFromLocalStorageStub; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + getCookieStub = sandbox.stub(storage, 'getCookie'); + getDataFromLocalStorageStub = sandbox.stub(storage, 'getDataFromLocalStorage'); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('getId', () => { + it('should return an object with id when pirIdToken is found', () => { + getDataFromLocalStorageStub.returns('testToken'); + getCookieStub.returns('testToken'); + + const result = pirIdSubmodule.getId(); + + expect(result).to.deep.equal({ id: 'testToken' }); + }); + + it('should return undefined when pirIdToken is not found', () => { + const result = pirIdSubmodule.getId(); + + expect(result).to.be.undefined; + }); + }); + + describe('decode', () => { + it('should return an object with pirId when value is a string', () => { + const result = pirIdSubmodule.decode('testId'); + + expect(result).to.deep.equal({ pirId: 'testId' }); + }); + + it('should return undefined when value is not a string', () => { + const result = pirIdSubmodule.decode({}); + + expect(result).to.be.undefined; + }); + }); + + describe('readId', () => { + it('should return data from local storage when it exists', () => { + getDataFromLocalStorageStub.returns('local_storage_data'); + + const result = readId(); + + expect(result).to.equal('local_storage_data'); + }); + + it('should return data from cookie when local storage data does not exist', () => { + getDataFromLocalStorageStub.returns(null); + getCookieStub.returns('cookie_data'); + + const result = readId(); + + expect(result).to.equal('cookie_data'); + }); + + it('should return null when neither local storage data nor cookie data exists', () => { + getDataFromLocalStorageStub.returns(null); + getCookieStub.returns(null); + + const result = readId(); + + expect(result).to.be.null; + }); + }); +}); From cf8cf49a7a3349f5aa984031d342f0a18a6da789 Mon Sep 17 00:00:00 2001 From: dalmenarDevST <116064809+dalmenarDevST@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:46:15 +0200 Subject: [PATCH 014/147] add topics and eids to payload (#11338) --- modules/seedtagBidAdapter.js | 15 ++++-- test/spec/modules/seedtagBidAdapter_spec.js | 59 +++++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 6f36c8a191e..e17ff1301a3 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -1,7 +1,7 @@ -import { isArray, _map, triggerPixel } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { VIDEO, BANNER } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { _map, isArray, triggerPixel } from '../src/utils.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -125,7 +125,7 @@ function buildBidRequest(validBidRequest) { adUnitCode: validBidRequest.adUnitCode, geom: geom(validBidRequest.adUnitCode), placement: params.placement, - requestCount: validBidRequest.bidderRequestsCount || 1, // FIXME : in unit test the parameter bidderRequestsCount is undefined + requestCount: validBidRequest.bidderRequestsCount || 1, // FIXME : in unit test the parameter bidderRequestsCount is undefinedt }; if (hasVideoMediaType(validBidRequest)) { @@ -284,6 +284,7 @@ export const spec = { auctionStart: bidderRequest.auctionStart || Date.now(), ttfb: ttfb(), bidRequests: _map(validBidRequests, buildBidRequest), + user: { topics: [], eids: [] } }; if (payload.cmp) { @@ -316,7 +317,15 @@ export const spec = { } } + if (bidderRequest.ortb2?.user?.data) { + payload.user.topics = bidderRequest.ortb2.user.data + } + if (validBidRequests[0] && validBidRequests[0].userIdAsEids) { + payload.user.eids = validBidRequests[0].userIdAsEids + } + const payloadString = JSON.stringify(payload); + return { method: 'POST', url: SEEDTAG_SSP_ENDPOINT, diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 516c5ec933a..2012c78d239 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js'; +import { getTimeoutUrl, spec } from 'modules/seedtagBidAdapter.js'; import * as utils from 'src/utils.js'; -import { config } from '../../../src/config.js'; import * as mockGpt from 'test/spec/integration/faker/googletag.js'; +import { config } from '../../../src/config.js'; const PUBLISHER_ID = '0000-0000-01'; const ADUNIT_ID = '000000'; @@ -536,8 +536,61 @@ describe('Seedtag Adapter', function () { expect(data.gppConsent).to.be.undefined; }); }); - }); + describe('User param', function () { + it('should be added to payload user data param when bidderRequest has ortb2 user info', function () { + var ortb2 = { + + user: { + + data: [ + { + ext: { + segtax: 601, + segclass: '4' + }, + segment: [ + { + id: '149' + } + ], + name: 'randomname' + } + + ] + } + } + bidderRequest['ortb2'] = ortb2 + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + + expect(data.user).to.exist; + expect(data.user.topics).to.exist; + expect(data.user.topics).to.be.an('array').that.is.not.empty; + expect(data.user.topics[0].ext).to.eql(ortb2.user.data[0].ext); + expect(data.user.topics[0].segment).to.eql(ortb2.user.data[0].segment); + expect(data.user.topics[0].name).to.eql(ortb2.user.data[0].name); + }) + + it('should be added to payload user eids param when validRequest has userId info', function () { + var userIdAsEids = [{ + source: 'sourceid', + uids: [{ + atype: 1, + id: 'randomId' + }] + }] + validBidRequests[0]['userIdAsEids'] = userIdAsEids + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + + expect(data.user).to.exist; + expect(data.user.eids).to.exist; + expect(data.user.eids).to.be.an('array').that.is.not.empty; + expect(data.user.eids).to.deep.equal(userIdAsEids); + }) + }); + }) describe('interpret response method', function () { it('should return a void array, when the server response are not correct.', function () { const request = { data: JSON.stringify({}) }; From 5ad4877e68a4be91dd4630d4687fa60c0d1d26fc Mon Sep 17 00:00:00 2001 From: g-kitiashvili <113773663+g-kitiashvili@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:07:34 +0400 Subject: [PATCH 015/147] beacon calls - we need to switch this domain to ce.lijit.com instead to better isolate raptor calls. (#11332) --- modules/sovrnBidAdapter.js | 2 +- test/spec/modules/sovrnBidAdapter_spec.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 64604618680..6dc5a3dc2ef 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -271,7 +271,7 @@ export const spec = { params.push(['informer', iidArr[0]]); tracks.push({ type: 'iframe', - url: 'https://ap.lijit.com/beacon?' + params.map(p => p.join('=')).join('&') + url: 'https://ce.lijit.com/beacon?' + params.map(p => p.join('=')).join('&') }); } } diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 274192d14a7..ad195b6924a 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -931,7 +931,7 @@ describe('sovrnBidAdapter', function() { it('should return if iid present on server response & iframe syncs enabled', function() { const expectedReturnStatement = { type: 'iframe', - url: 'https://ap.lijit.com/beacon?informer=13487408', + url: 'https://ce.lijit.com/beacon?informer=13487408', } const returnStatement = spec.getUserSyncs(syncOptions, serverResponse) @@ -945,7 +945,7 @@ describe('sovrnBidAdapter', function() { } const expectedReturnStatement = { type: 'iframe', - url: `https://ap.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&informer=13487408`, + url: `https://ce.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&informer=13487408`, } const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, gdprConsent, '', null) @@ -957,7 +957,7 @@ describe('sovrnBidAdapter', function() { const uspString = '1NYN' const expectedReturnStatement = { type: 'iframe', - url: `https://ap.lijit.com/beacon?us_privacy=${uspString}&informer=13487408`, + url: `https://ce.lijit.com/beacon?us_privacy=${uspString}&informer=13487408`, } const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, null, uspString, null) @@ -972,7 +972,7 @@ describe('sovrnBidAdapter', function() { } const expectedReturnStatement = { type: 'iframe', - url: `https://ap.lijit.com/beacon?gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections}&informer=13487408`, + url: `https://ce.lijit.com/beacon?gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections}&informer=13487408`, } const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, null, '', gppConsent) @@ -993,7 +993,7 @@ describe('sovrnBidAdapter', function() { const expectedReturnStatement = { type: 'iframe', - url: `https://ap.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&us_privacy=${uspString}&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections}&informer=13487408`, + url: `https://ce.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&us_privacy=${uspString}&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections}&informer=13487408`, } const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, gdprConsent, uspString, gppConsent) From 2fd1b7412c2d7bafd2da8d7e1bc3888c19a1ef7e Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:50:55 +0530 Subject: [PATCH 016/147] Insticator Bid Adaptor: add support for different privacy platforms, ortb site first party data, fix video validation bug (#11279) * add support for: - dsa - us_privacy/ccpa - gpp - gppSid * video validation fix * support first part site details * support user data from bidder, and update server endpoint for alternative bidder configs * - enhance user object with ext and consent - remove video param validation * add test case for more than one privacy platforms * update user.ext.consent * update coppa and support video context --- modules/insticatorBidAdapter.js | 164 ++++++++-- .../spec/modules/insticatorBidAdapter_spec.js | 297 ++++++++++++++++-- 2 files changed, 412 insertions(+), 49 deletions(-) diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 4d9b95e5948..617ce49f171 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -1,7 +1,7 @@ import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {deepAccess, generateUUID, logError, isArray, isInteger, isArrayOfNums} from '../src/utils.js'; +import {deepAccess, generateUUID, logError, isArray, isInteger, isArrayOfNums, deepSetValue} from '../src/utils.js'; import {getStorageManager} from '../src/storageManager.js'; import {find} from '../src/polyfill.js'; @@ -12,35 +12,37 @@ const USER_ID_COOKIE_EXP = 2592000000; // 30 days const BID_TTL = 300; // 5 minutes const GVLID = 910; -const isSubarray = (arr, target) => { - if (!isArrayOfNums(arr) || arr.length === 0) { - return false; - } - const targetSet = new Set(target); - return arr.every(el => targetSet.has(el)); -}; - export const OPTIONAL_VIDEO_PARAMS = { 'minduration': (value) => isInteger(value), 'maxduration': (value) => isInteger(value), - 'protocols': (value) => isSubarray(value, [2, 3, 5, 6, 7, 8]), // protocols values supported by Inticator, according to the OpenRTB spec + 'protocols': (value) => isArrayOfNums(value), // protocols values supported by Inticator, according to the OpenRTB spec 'startdelay': (value) => isInteger(value), 'linearity': (value) => isInteger(value) && [1].includes(value), 'skip': (value) => isInteger(value) && [1, 0].includes(value), 'skipmin': (value) => isInteger(value), 'skipafter': (value) => isInteger(value), 'sequence': (value) => isInteger(value), - 'battr': (value) => isSubarray(value, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]), + 'battr': (value) => isArrayOfNums(value), 'maxextended': (value) => isInteger(value), 'minbitrate': (value) => isInteger(value), 'maxbitrate': (value) => isInteger(value), - 'playbackmethod': (value) => isSubarray(value, [1, 2, 3, 4]), + 'playbackmethod': (value) => isArrayOfNums(value), 'playbackend': (value) => isInteger(value) && [1, 2, 3].includes(value), - 'delivery': (value) => isSubarray(value, [1, 2, 3]), + 'delivery': (value) => isArrayOfNums(value), 'pos': (value) => isInteger(value) && [0, 1, 2, 3, 4, 5, 6, 7].includes(value), - 'api': (value) => isSubarray(value, [1, 2, 3, 4, 5, 6, 7]), + 'api': (value) => isArrayOfNums(value), }; +const ORTB_SITE_FIRST_PARTY_DATA = { + 'cat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'sectioncat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'pagecat': v => Array.isArray(v) && v.every(c => typeof c === 'string'), + 'search': v => typeof v === 'string', + 'mobile': v => isInteger(), + 'content': v => typeof v === 'object', + 'keywords': v => typeof v === 'string', +} + export const storage = getStorageManager({bidderCode: BIDDER_CODE}); config.setDefaults({ @@ -103,6 +105,7 @@ function buildVideo(bidRequest) { const placement = deepAccess(bidRequest, 'mediaTypes.video.placement') || 3; const plcmt = deepAccess(bidRequest, 'mediaTypes.video.plcmt') || undefined; const playerSize = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + const context = deepAccess(bidRequest, 'mediaTypes.video.context'); if (!w && playerSize) { if (Array.isArray(playerSize[0])) { @@ -121,17 +124,26 @@ function buildVideo(bidRequest) { const bidRequestVideo = deepAccess(bidRequest, 'mediaTypes.video'); const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + let optionalParams = {}; for (const param in OPTIONAL_VIDEO_PARAMS) { - if (bidRequestVideo[param]) { + if (bidRequestVideo[param] && OPTIONAL_VIDEO_PARAMS[param](bidRequestVideo[param])) { optionalParams[param] = bidRequestVideo[param]; } + // remove invalid optional params from bidder specific overrides + if (videoBidderParams[param] && !OPTIONAL_VIDEO_PARAMS[param](videoBidderParams[param])) { + delete videoBidderParams[param]; + } } if (plcmt) { optionalParams['plcmt'] = plcmt; } + if (context !== undefined) { + optionalParams['context'] = context; + } + let videoObj = { placement, mimes, @@ -190,31 +202,102 @@ function buildDevice(bidRequest) { return device; } +function _getCoppa(bidderRequest) { + const coppa = deepAccess(bidderRequest, 'ortb2.regs.coppa'); + + // If coppa is defined in the request, use it + if (coppa !== undefined) { + return coppa; + } + return config.getConfig('coppa') === true ? 1 : 0; +} + +function _getGppConsent(bidderRequest) { + let gpp = deepAccess(bidderRequest, 'gppConsent.gppString') + let gppSid = deepAccess(bidderRequest, 'gppConsent.applicableSections') + + if (!gpp || !gppSid) { + gpp = deepAccess(bidderRequest, 'ortb2.regs.gpp', '') + gppSid = deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []) + } + return { gpp, gppSid } +} + +function _getUspConsent(bidderRequest) { + return (deepAccess(bidderRequest, 'uspConsent')) ? { uspConsent: bidderRequest.uspConsent } : false; +} + function buildRegs(bidderRequest) { + let regs = { + ext: {}, + }; if (bidderRequest.gdprConsent) { - return { - ext: { - gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0, - gdprConsentString: bidderRequest.gdprConsent.consentString, - }, - }; + regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + regs.ext.gdprConsentString = bidderRequest.gdprConsent.consentString; + } + + regs.coppa = _getCoppa(bidderRequest); + + const { gpp, gppSid } = _getGppConsent(bidderRequest); + + if (gpp) { + regs.ext.gpp = gpp; + } + + if (gppSid) { + regs.ext.gppSid = gppSid; + } + + const usp = _getUspConsent(bidderRequest); + + if (usp) { + regs.ext.us_privacy = usp.uspConsent; + regs.ext.ccpa = usp.uspConsent + } + + const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa'); + if (dsa) { + regs.ext.dsa = dsa; } - return {}; + return regs; } function buildUser(bid) { const userId = getUserId() || generateUUID(); const yob = deepAccess(bid, 'params.user.yob') const gender = deepAccess(bid, 'params.user.gender') + const keywords = deepAccess(bid, 'params.user.keywords') + const data = deepAccess(bid, 'params.user.data') + const ext = deepAccess(bid, 'params.user.ext') setUserId(userId); - return { + const userData = { id: userId, - yob, - gender, - }; + } + + if (yob) { + userData.yob = yob; + } + + if (gender) { + userData.gender = gender; + } + + if (keywords) { + userData.keywords = keywords; + } + + if (data) { + userData.data = data; + } + + if (ext) { + userData.ext = ext; + } + + return userData } function extractSchain(bids, requestId) { @@ -283,6 +366,20 @@ function buildRequest(validBidRequests, bidderRequest) { req.user.ext = { eids }; } + const ortb2SiteData = deepAccess(bidderRequest, 'ortb2.site'); + if (ortb2SiteData) { + for (const key in ORTB_SITE_FIRST_PARTY_DATA) { + const value = ortb2SiteData[key]; + if (value && ORTB_SITE_FIRST_PARTY_DATA[key](value)) { + req.site[key] = value; + } + } + } + + if (bidderRequest.gdprConsent) { + deepSetValue(req, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + return req; } @@ -326,6 +423,13 @@ function buildBid(bid, bidderRequest) { bidResponse.vastUrl = 'data:text/xml;charset=utf-8;base64,' + window.btoa(bidResponse.vastXml.replace(/\\"/g, '"')); } + if (bid.ext && bid.ext.dsa) { + bidResponse.ext = { + ...bidResponse.ext, + dsa: bid.ext.dsa, + } + } + return bidResponse; } @@ -453,7 +557,6 @@ function validateVideo(bid) { if (video[param]) { if (!OPTIONAL_VIDEO_PARAMS[param](video[param])) { logError(`insticator: video ${param} is invalid or not supported by insticator`); - return false } } } @@ -485,6 +588,13 @@ export const spec = { let endpointUrl = config.getConfig('insticator.endpointUrl') || ENDPOINT; endpointUrl = endpointUrl.replace(/^http:/, 'https:'); + // Use the first bid request's bid_request_url if it exists ( for updating server url) + if (validBidRequests.length > 0) { + if (deepAccess(validBidRequests[0], 'params.bid_endpoint_request_url')) { + endpointUrl = deepAccess(validBidRequests[0], 'params.bid_endpoint_request_url').replace(/^http:/, 'https:'); + } + } + if (validBidRequests.length > 0) { requests.push({ method: 'POST', diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js index 86f96834547..5e41cd6d7aa 100644 --- a/test/spec/modules/insticatorBidAdapter_spec.js +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -75,9 +75,10 @@ describe('InsticatorBidAdapter', function () { ortb2: { source: { tid: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', - } + }, }, timeout: 300, + gdprApplies: 1, gdprConsent: { consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', vendorData: {}, @@ -261,25 +262,6 @@ describe('InsticatorBidAdapter', function () { })).to.be.true; }); - it('should return false if optional video fields are not valid', () => { - expect(spec.isBidRequestValid({ - ...bidRequest, - ...{ - mediaTypes: { - video: { - mimes: [ - 'video/mp4', - 'video/mpeg', - ], - playerSize: [250, 300], - placement: 1, - startdelay: 'NaN', - }, - } - } - })).to.be.false; - }); - it('should return false if video min duration > max duration', () => { expect(spec.isBidRequestValid({ ...bidRequest, @@ -497,11 +479,58 @@ describe('InsticatorBidAdapter', function () { expect(data.user.id).to.equal(USER_ID_STUBBED); }); - it('should return empty regs object if no gdprConsent is passed', function () { + + it('should return with coppa regs object if no gdprConsent is passed', function () { const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ gdprConsent: false } }); const data = JSON.parse(requests[0].data); - expect(data.regs).to.be.an('object').that.is.empty; + expect(data.regs).to.be.an('object'); + expect(data.regs.coppa).to.be.oneOf([0, 1]); }); + + it('should return with us_privacy string if uspConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ uspConsent: '1YNN' } }); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.us_privacy).to.equal('1YNN'); + expect(data.regs.ext.ccpa).to.equal('1YNN'); + }); + + it('should return with gpp if gppConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ gppConsent: { gppString: '1YNN', applicableSections: ['1', '2'] } } }); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.gppSid).to.deep.equal(['1', '2']); + }); + + it('should create the request with dsa data and return with dsa object', function() { + const dsa = { + dsarequired: 2, + pubrender: 1, + datatopub: 2, + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }] + } + const bidRequestWithDsa = { + ...bidderRequest, + ortb2: { + regs: { + ext: { + dsa: dsa + } + } + } + } + const requests = spec.buildRequests([bidRequest], {...bidRequestWithDsa}); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.dsa).to.deep.equal(dsa); + }); + it('should return empty array if no valid requests are passed', function () { expect(spec.buildRequests([], bidderRequest)).to.be.an('array').that.have.lengthOf(0); }); @@ -539,6 +568,129 @@ describe('InsticatorBidAdapter', function () { expect(data.imp[0].video.w).to.equal(640); expect(data.imp[0].video.h).to.equal(480); }); + + it('should have sites first party data if present in bidderRequest ortb2', function () { + bidderRequest = { + ...bidderRequest, + ortb2: { + ...bidderRequest.ortb2, + site: { + keywords: 'keyword1,keyword2', + search: 'search', + content: { + title: 'title', + keywords: 'keyword3,keyword4', + genre: 'rock' + }, + cat: ['IAB1', 'IAB2'] + } + } + } + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data).to.have.property('site'); + expect(data.site).to.have.property('keywords'); + expect(data.site.keywords).to.equal('keyword1,keyword2'); + expect(data.site).to.have.property('search'); + expect(data.site.search).to.equal('search'); + expect(data.site).to.have.property('content'); + expect(data.site.content).to.have.property('title'); + expect(data.site.content.title).to.equal('title'); + expect(data.site.content).to.have.property('keywords'); + expect(data.site.content.keywords).to.equal('keyword3,keyword4'); + expect(data.site.content).to.have.property('genre'); + expect(data.site.content.genre).to.equal('rock'); + expect(data.site).to.have.property('cat'); + expect(data.site.cat).to.deep.equal(['IAB1', 'IAB2']); + }); + + it('should have device.sua if present in bidderRequest ortb2', function () { + bidderRequest = { + ...bidderRequest, + ortb2: { + ...bidderRequest.ortb2, + device: { + ...bidderRequest.ortb2.device, + sua: {} + } + } + } + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data).to.have.property('device'); + expect(data.device).to.have.property('sua'); + }) + + it('should use param bid_endpoint_request_url for request endpoint if present', function () { + const tempBiddRequest = { + ...bidRequest, + params: { + ...bidRequest.params, + bid_endpoint_request_url: 'https://example.com' + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + expect(requests[0].url).to.equal('https://example.com'); + }); + + it('should have user keywords if present in bidrequest', function () { + const tempBiddRequest = { + ...bidRequest, + params: { + ...bidRequest.params, + user: { + keywords: 'keyword1,keyword2' + } + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.user).to.have.property('keywords'); + expect(data.user.keywords).to.equal('keyword1,keyword2'); + }); + + it('should remove video params if they are invalid', function () { + const tempBiddRequest = { + ...bidRequest, + mediaTypes: { + ...bidRequest.mediaTypes, + video: { + mimes: [ + 'video/mp4', + 'video/mpeg', + 'video/x-flv', + 'video/webm', + 'video/ogg', + ], + protocols: 'NaN', + w: '300', + h: '250', + } + } + } + const requests = spec.buildRequests([tempBiddRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.imp[0].video).to.not.have.property('plcmt'); + }); + + it('should have user consent and gdpr string if gdprConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext).to.be.an('object'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.regs.ext.gdprConsentString).to.equal(bidderRequest.gdprConsent.consentString); + expect(data.user.ext).to.have.property('consent'); + expect(data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); + }); + + it('should have one or more privacy policies if present in bidrequest, like gpp, gdpr and us_privacy', function () { + const requests = spec.buildRequests([bidRequest], { ...bidderRequest, ...{ uspConsent: '1YNN' } }); + const data = JSON.parse(requests[0].data); + expect(data.regs.ext).to.have.property('gdpr'); + expect(data.regs.ext).to.have.property('us_privacy'); + expect(data.regs.ext).to.have.property('gppSid'); + }); }); describe('interpretResponse', function () { @@ -837,4 +989,105 @@ describe('InsticatorBidAdapter', function () { expect(bidResponse.vastUrl).to.match(/^data:text\/xml;charset=utf-8;base64,[\w+/=]+$/) }); }) + + describe(`Response with DSA data`, function() { + const bidRequestDsa = { + method: 'POST', + url: 'https://ex.ingage.tech/v1/openrtb', + options: { + contentType: 'application/json', + withCredentials: true, + }, + data: '', + bidderRequest: { + bidderRequestId: '22edbae2733bf6', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + timeout: 300, + bids: [ + { + bidder: 'insticator', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + adUnitCode: 'adunit-code-1', + mediaTypes: { + video: { + mimes: [ + 'video/mp4', + 'video/mpeg', + ], + playerSize: [[250, 300]], + placement: 2, + plcmt: 2, + } + }, + bidId: 'bid1', + } + ], + ortb2: { + regs: { + ext: { + dsa: { + dsarequired: 2, + pubrender: 1, + datatopub: 2, + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }] + } + }} + }, + } + }; + + const bidResponseDsa = { + body: { + id: '22edbae2733bf6', + bidid: 'foo9876', + cur: 'USD', + seatbid: [ + { + seat: 'some-dsp', + bid: [ + { + ad: '', + impid: 'bid1', + crid: 'crid1', + price: 0.5, + w: 300, + h: 250, + adm: '', + exp: 60, + adomain: ['test1.com'], + ext: { + meta: { + test: 1, + }, + dsa: { + behalf: 'Advertiser', + paid: 'Advertiser', + transparency: [{ + domain: 'google.com', + dsaparams: [1, 2] + }], + adrender: 1 + } + }, + } + ], + }, + ] + } + }; + const bidRequestWithDsa = utils.deepClone(bidRequestDsa); + it('should have related properties for DSA data', function() { + const serverResponseWithDsa = utils.deepClone(bidResponseDsa); + const bidResponse = spec.interpretResponse(serverResponseWithDsa, bidRequestWithDsa)[0]; + expect(bidResponse).to.have.any.keys('ext'); + expect(bidResponse.ext.dsa).to.have.property('behalf', 'Advertiser'); + expect(bidResponse.ext.dsa).to.have.property('paid', 'Advertiser'); + expect(bidResponse.ext.dsa).to.have.property('adrender', 1); + }); + }); }); From 3dda9d211d91e46080936349390f4a4dae610753 Mon Sep 17 00:00:00 2001 From: Nick Llerandi Date: Mon, 15 Apr 2024 13:25:28 -0400 Subject: [PATCH 017/147] KRKPD-996: refactors interpretResponse (#30) (#11340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactors interpretResponse * updates comment * simpler * removes unnecessary comment * removes more unnecessary comments * revert ttl * reverts ttl test values * revert some || changes * removes comments --------- Co-authored-by: “Nick <“nick.llerandi”@kargo.com> --- modules/kargoBidAdapter.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index fe22915223e..f3b3166ccad 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -195,25 +195,19 @@ function buildRequests(validBidRequests, bidderRequest) { } function interpretResponse(response, bidRequest) { - let bids = response.body; + const bids = response.body; const bidResponses = []; - if (isEmpty(bids)) { + if (isEmpty(bids) || typeof bids !== 'object') { return bidResponses; } - if (typeof bids !== 'object') { - return bidResponses; - } - - Object.entries(bids).forEach((entry) => { - const [bidID, adUnit] = entry; - + for (const [bidID, adUnit] of Object.entries(bids)) { let meta = { mediaType: adUnit.mediaType && BIDDER.SUPPORTED_MEDIA_TYPES.includes(adUnit.mediaType) ? adUnit.mediaType : BANNER }; - if (adUnit.metadata && adUnit.metadata.landingPageDomain) { + if (adUnit.metadata?.landingPageDomain) { meta.clickUrl = adUnit.metadata.landingPageDomain[0]; meta.advertiserDomains = adUnit.metadata.landingPageDomain; } @@ -243,7 +237,7 @@ function interpretResponse(response, bidRequest) { } bidResponses.push(bidResponse); - }) + } return bidResponses; } From ea8692c4a9f6e34e1bf93c5877b170f87e79ebf8 Mon Sep 17 00:00:00 2001 From: asurovenko-zeta <80847074+asurovenko-zeta@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:36:18 +0200 Subject: [PATCH 018/147] ZetaGlobalSsp Bid Adapter: modify timeout object (#11236) * ZetaGlobalSsp Adapter: modify onTimeout object * - * fix unit test --------- Co-authored-by: Surovenko Alexey Co-authored-by: Alexey Surovenko --- modules/zeta_global_sspBidAdapter.js | 9 ++++++++- test/spec/modules/zeta_global_sspBidAdapter_spec.js | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/zeta_global_sspBidAdapter.js b/modules/zeta_global_sspBidAdapter.js index 722c51dc058..f3e2e12c143 100644 --- a/modules/zeta_global_sspBidAdapter.js +++ b/modules/zeta_global_sspBidAdapter.js @@ -272,7 +272,14 @@ export const spec = { onTimeout: function(timeoutData) { if (timeoutData) { - ajax(TIMEOUT_URL, null, JSON.stringify(timeoutData), { + const payload = timeoutData.map(d => ({ + bidder: d?.bidder, + shortname: d?.params?.map(p => p?.tags?.shortname).find(p => p), + sid: d?.params?.map(p => p?.sid).find(p => p), + country: d?.ortb2?.device?.geo?.country, + devicetype: d?.ortb2?.device?.devicetype + })); + ajax(TIMEOUT_URL, null, JSON.stringify(payload), { method: 'POST', options: { withCredentials: false, diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js index f9cfe2dde6a..7b5c0278019 100644 --- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js @@ -544,7 +544,7 @@ describe('Zeta Ssp Bid Adapter', function () { it('Timeout should exists and be a function', function () { expect(spec.onTimeout).to.exist.and.to.be.a('function'); - expect(spec.onTimeout({ timeout: 1000 })).to.be.undefined; + expect(spec.onTimeout([{bidder: '1'}])).to.be.undefined; }); it('Test schain provided', function () { From ed2b8239e269d0f09b8044b39d94c91f0eff69df Mon Sep 17 00:00:00 2001 From: Muki Seiler Date: Mon, 15 Apr 2024 21:04:43 +0200 Subject: [PATCH 019/147] Build Related : rename constants.json to constants.js (#11292) * Fix lintWarnings gulp parameter * Fix #10829 Rename constants.json to constant.js * Remove unnecessary quotes * Fix import in genericAnalyticsAdapter * remove unnecessary quotes * Change require to imports * Revert "Fix lintWarnings gulp parameter" This reverts commit e210f4e264172bd07d2c767dfd77402bae1d2282. * Add nolint and no-lint-warnings docs to README * WIP refactoring constants into separated exported files * Refactor the rest of imports * Fix invalid import * Add missing MESSAGSES import * Add missing S2S import * Fix broken constants.js import * Use proper events import in magnite adapter * Add import to pubmatic spec * Found another CONSTANTS import * Fix shadowed var * fix zeta global test * Add missing BID_STATUS import * Fix zeta global ssp analytics for real * fix lint error * Remove duplicated TARGETING_KEYS definition * Move FLOOR_SKIPPED_REASON into priceFloors.js * Remove unused CB constants * Move FLOOR_SKIPPED_REASON into pubmaticAnalyticsAdapter * Use proper import * Remove unused var and fix linting error --- README.md | 8 +- creative/constants.js | 14 +- creative/renderers/display/constants.js | 4 +- creative/renderers/native/constants.js | 4 +- .../analyticsAdapter/AnalyticsAdapter.js | 8 +- modules/33acrossAnalyticsAdapter.js | 6 +- modules/adWMGAnalyticsAdapter.js | 20 +- modules/adagioAnalyticsAdapter.js | 16 +- modules/adkernelAdnAnalyticsAdapter.js | 16 +- modules/adlooxAdServerVideo.js | 4 +- modules/adlooxAnalyticsAdapter.js | 8 +- modules/adomikAnalyticsAdapter.js | 14 +- modules/adpod.js | 6 +- modules/adxcgAnalyticsAdapter.js | 20 +- modules/adxpremiumAnalyticsAdapter.js | 18 +- modules/agmaAnalyticsAdapter.js | 8 +- modules/appierAnalyticsAdapter.js | 12 +- modules/asteriobidAnalyticsAdapter.js | 28 +-- modules/atsAnalyticsAdapter.js | 8 +- modules/automatadAnalyticsAdapter.js | 40 ++-- modules/bidViewability.js | 6 +- modules/bidViewabilityIO.js | 6 +- modules/bidwatchAnalyticsAdapter.js | 16 +- modules/brandmetricsRtdProvider.js | 12 +- modules/browsiRtdProvider.js | 6 +- modules/byDataAnalyticsAdapter.js | 6 +- modules/cleanioRtdProvider.js | 6 +- modules/concertAnalyticsAdapter.js | 12 +- modules/confiantRtdProvider.js | 4 +- modules/conversantAnalyticsAdapter.js | 6 +- modules/currency.js | 14 +- modules/datawrkzBidAdapter.js | 8 +- modules/debugging/pbsInterceptor.js | 4 +- modules/dfpAdServerVideo.js | 4 +- modules/dsaControl.js | 10 +- modules/eplanningAnalyticsAdapter.js | 16 +- modules/fintezaAnalyticsAdapter.js | 10 +- modules/gdprEnforcement.js | 6 +- modules/geoedgeRtdProvider.js | 4 +- modules/greenbidsAnalyticsAdapter.js | 14 +- modules/greenbidsRtdProvider.js | 4 +- modules/growthCodeAnalyticsAdapter.js | 28 +-- modules/hadronAnalyticsAdapter.js | 28 +-- modules/holidBidAdapter.js | 4 +- modules/id5AnalyticsAdapter.js | 16 +- modules/instreamTracking.js | 8 +- modules/invisiblyAnalyticsAdapter.js | 32 ++- modules/ixBidAdapter.js | 6 +- modules/kargoAnalyticsAdapter.js | 6 +- modules/konduitAnalyticsAdapter.js | 26 +-- modules/liveIntentAnalyticsAdapter.js | 4 +- modules/livewrappedAnalyticsAdapter.js | 20 +- modules/magniteAnalyticsAdapter.js | 28 ++- modules/malltvAnalyticsAdapter.js | 10 +- modules/mediafilterRtdProvider.js | 4 +- modules/medianetAnalyticsAdapter.js | 24 +-- modules/multibid/index.js | 4 +- modules/neuwoRtdProvider.js | 4 +- modules/nextMillenniumBidAdapter.js | 8 +- modules/nobidAnalyticsAdapter.js | 20 +- modules/ooloAnalyticsAdapter.js | 4 +- modules/oxxionAnalyticsAdapter.js | 16 +- modules/paapi.js | 4 +- modules/pirIdSystem.js | 2 +- modules/prebidServerBidAdapter/index.js | 16 +- .../prebidServerBidAdapter/ortbConverter.js | 6 +- modules/prebidmanagerAnalyticsAdapter.js | 28 +-- modules/priceFloors.js | 15 +- modules/pubmaticAnalyticsAdapter.js | 54 +++-- modules/pubmaticBidAdapter.js | 3 +- modules/pubwiseAnalyticsAdapter.js | 22 +- modules/pubxaiAnalyticsAdapter.js | 12 +- modules/qortexRtdProvider.js | 4 +- modules/roxotAnalyticsAdapter.js | 18 +- modules/rtdModule/index.js | 14 +- modules/scaleableAnalyticsAdapter.js | 10 +- modules/sigmoidAnalyticsAdapter.js | 14 +- modules/smaatoBidAdapter.js | 3 +- modules/sonobiAnalyticsAdapter.js | 22 +- modules/sovrnAnalyticsAdapter.js | 16 +- modules/staqAnalyticsAdapter.js | 18 +- modules/terceptAnalyticsAdapter.js | 14 +- modules/ucfunnelAnalyticsAdapter.js | 12 +- modules/userId/index.js | 6 +- modules/videoModule/index.js | 8 +- modules/yandexAnalyticsAdapter.js | 4 +- modules/yieldoneAnalyticsAdapter.js | 14 +- modules/yuktamediaAnalyticsAdapter.js | 18 +- modules/zeta_global_sspAnalyticsAdapter.js | 10 +- src/adRendering.js | 30 +-- src/adapterManager.js | 16 +- src/adapters/bidderFactory.js | 16 +- src/auction.js | 54 +++-- src/auctionManager.js | 8 +- src/bidderSettings.js | 4 +- src/config.js | 4 +- src/constants.js | 190 +++++++++++++++++ src/constants.json | 196 ------------------ src/events.js | 6 +- src/native.js | 14 +- src/prebid.js | 12 +- src/secureCreatives.js | 10 +- src/targeting.js | 26 +-- src/utils.js | 8 +- test/fixtures/fixtures.js | 88 ++++---- test/helpers/analytics.js | 12 +- test/spec/AnalyticsAdapter_spec.js | 6 +- test/spec/auctionmanager_spec.js | 164 +++++++-------- .../modules/33acrossAnalyticsAdapter_spec.js | 3 +- .../modules/adWMGAnalyticsAdapter_spec.js | 28 +-- .../modules/adagioAnalyticsAdapter_spec.js | 52 ++--- .../spec/modules/adkernelAdnAnalytics_spec.js | 12 +- .../modules/adlooxAnalyticsAdapter_spec.js | 12 +- .../modules/adomikAnalyticsAdapter_spec.js | 14 +- .../modules/adxcgAnalyticsAdapter_spec.js | 14 +- .../adxpremiumAnalyticsAdapter_spec.js | 14 +- .../spec/modules/agmaAnalyticsAdapter_spec.js | 28 +-- .../modules/appierAnalyticsAdapter_spec.js | 2 +- .../asteriobidAnalyticsAdapter_spec.js | 4 +- test/spec/modules/atsAnalyticsAdapter_spec.js | 16 +- .../modules/automatadAnalyticsAdapter_spec.js | 4 +- test/spec/modules/bidViewabilityIO_spec.js | 4 +- test/spec/modules/bidViewability_spec.js | 8 +- .../modules/bidwatchAnalyticsAdapter_spec.js | 13 +- .../modules/byDataAnalyticsAdapter_spec.js | 9 +- test/spec/modules/cleanioRtdProvider_spec.js | 12 +- .../modules/concertAnalyticsAdapter_spec.js | 13 +- test/spec/modules/confiantRtdProvider_spec.js | 4 +- .../conversantAnalyticsAdapter_spec.js | 122 +++++------ test/spec/modules/currency_spec.js | 12 +- test/spec/modules/dsaControl_spec.js | 8 +- .../modules/eplanningAnalyticsAdapter_spec.js | 33 +-- .../modules/fintezaAnalyticsAdapter_spec.js | 10 +- .../modules/genericAnalyticsAdapter_spec.js | 4 +- test/spec/modules/geoedgeRtdProvider_spec.js | 74 +++---- .../modules/greenbidsAnalyticsAdapter_spec.js | 2 +- .../spec/modules/greenbidsRtdProvider_spec.js | 4 +- .../growthCodeAnalyticsAdapter_spec.js | 4 +- .../modules/hadronAnalyticsAdapter_spec.js | 6 +- test/spec/modules/id5AnalyticsAdapter_spec.js | 10 +- test/spec/modules/id5IdSystem_spec.js | 4 +- .../modules/invisiblyAnalyticsAdapter_spec.js | 80 +++---- .../modules/kargoAnalyticsAdapter_spec.js | 6 +- .../modules/konduitAnalyticsAdapter_spec.js | 26 +-- .../modules/lemmaDigitalBidAdapter_spec.js | 2 +- .../liveIntentAnalyticsAdapter_spec.js | 6 +- .../livewrappedAnalyticsAdapter_spec.js | 35 ++-- .../modules/magniteAnalyticsAdapter_spec.js | 26 ++- .../modules/malltvAnalyticsAdapter_spec.js | 6 +- .../modules/mediafilterRtdProvider_spec.js | 4 +- .../modules/medianetAnalyticsAdapter_spec.js | 6 +- .../modules/nobidAnalyticsAdapter_spec.js | 46 ++-- .../spec/modules/ooloAnalyticsAdapter_spec.js | 66 +++--- .../modules/optimonAnalyticsAdapter_spec.js | 1 - .../modules/oxxionAnalyticsAdapter_spec.js | 14 +- test/spec/modules/paapi_spec.js | 22 +- .../modules/pianoDmpAnalyticsAdapter_spec.js | 18 +- .../modules/prebidServerBidAdapter_spec.js | 14 +- .../prebidmanagerAnalyticsAdapter_spec.js | 4 +- test/spec/modules/priceFloors_spec.js | 11 +- .../modules/pubmaticAnalyticsAdapter_spec.js | 26 ++- test/spec/modules/pubmaticBidAdapter_spec.js | 2 +- .../modules/pubstackAnalyticsAdapter_spec.js | 1 - .../modules/pubwiseAnalyticsAdapter_spec.js | 28 +-- .../modules/pubxaiAnalyticsAdapter_spec.js | 14 +- test/spec/modules/qortexRtdProvider_spec.js | 4 +- test/spec/modules/realTimeDataModule_spec.js | 18 +- .../modules/relevantAnalyticsAdapter_spec.js | 6 +- .../modules/relevantdigitalBidAdapter_spec.js | 4 +- .../spec/modules/rivrAnalyticsAdapter_spec.js | 8 +- .../modules/roxotAnalyticsAdapter_spec.js | 50 ++--- .../modules/scaleableAnalyticsAdapter_spec.js | 10 +- .../modules/sigmoidAnalyticsAdapter_spec.js | 1 - .../modules/sonobiAnalyticsAdapter_spec.js | 15 +- .../modules/sovrnAnalyticsAdapter_spec.js | 4 +- .../spec/modules/staqAnalyticsAdapter_spec.js | 14 +- .../modules/terceptAnalyticsAdapter_spec.js | 14 +- test/spec/modules/trionBidAdapter_spec.js | 2 +- .../modules/ucfunnelAnalyticsAdapter_spec.js | 2 +- test/spec/modules/userId_spec.js | 8 +- test/spec/modules/videoModule/pbVideo_spec.js | 6 +- .../modules/yieldoneAnalyticsAdapter_spec.js | 43 ++-- .../yuktamediaAnalyticsAdapter_spec.js | 65 +++--- .../zeta_global_sspAnalyticsAdapter_spec.js | 16 +- test/spec/native_spec.js | 38 ++-- test/spec/unit/adRendering_spec.js | 28 +-- test/spec/unit/core/adapterManager_spec.js | 30 +-- test/spec/unit/core/bidderFactory_spec.js | 12 +- test/spec/unit/core/targeting_spec.js | 94 ++++----- test/spec/unit/pbjs_api_spec.js | 162 +++++++-------- test/spec/unit/secureCreatives_spec.js | 54 ++--- test/spec/utils_spec.js | 4 +- 192 files changed, 1836 insertions(+), 1866 deletions(-) create mode 100644 src/constants.js delete mode 100644 src/constants.json diff --git a/README.md b/README.md index e6d25a5cb5a..70e058d122b 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,12 @@ To lint the code: gulp lint ``` +To lint and only show errors + +```bash +gulp lint --no-lint-warnings +``` + To run the unit tests: ```bash @@ -245,7 +251,7 @@ gulp test To run the unit tests for a particular file (example for pubmaticBidAdapter_spec.js): ```bash -gulp test --file "test/spec/modules/pubmaticBidAdapter_spec.js" +gulp test --file "test/spec/modules/pubmaticBidAdapter_spec.js" --nolint ``` To generate and view the code coverage reports: diff --git a/creative/constants.js b/creative/constants.js index 6bb92cfe3c2..d02c4c9d5e4 100644 --- a/creative/constants.js +++ b/creative/constants.js @@ -1,9 +1,9 @@ // eslint-disable-next-line prebid/validate-imports -import CONSTANTS from '../src/constants.json'; +import { AD_RENDER_FAILED_REASON, EVENTS, MESSAGES } from '../src/constants.js'; -export const MESSAGE_REQUEST = CONSTANTS.MESSAGES.REQUEST; -export const MESSAGE_RESPONSE = CONSTANTS.MESSAGES.RESPONSE; -export const MESSAGE_EVENT = CONSTANTS.MESSAGES.EVENT; -export const EVENT_AD_RENDER_FAILED = CONSTANTS.EVENTS.AD_RENDER_FAILED; -export const EVENT_AD_RENDER_SUCCEEDED = CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED; -export const ERROR_EXCEPTION = CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION; +export const MESSAGE_REQUEST = MESSAGES.REQUEST; +export const MESSAGE_RESPONSE = MESSAGES.RESPONSE; +export const MESSAGE_EVENT = MESSAGES.EVENT; +export const EVENT_AD_RENDER_FAILED = EVENTS.AD_RENDER_FAILED; +export const EVENT_AD_RENDER_SUCCEEDED = EVENTS.AD_RENDER_SUCCEEDED; +export const ERROR_EXCEPTION = AD_RENDER_FAILED_REASON.EXCEPTION; diff --git a/creative/renderers/display/constants.js b/creative/renderers/display/constants.js index d291c79bb34..2493fb2d163 100644 --- a/creative/renderers/display/constants.js +++ b/creative/renderers/display/constants.js @@ -1,4 +1,4 @@ // eslint-disable-next-line prebid/validate-imports -import CONSTANTS from '../../../src/constants.json'; +import { AD_RENDER_FAILED_REASON } from '../../../src/constants.js'; -export const ERROR_NO_AD = CONSTANTS.AD_RENDER_FAILED_REASON.NO_AD; +export const ERROR_NO_AD = AD_RENDER_FAILED_REASON.NO_AD; diff --git a/creative/renderers/native/constants.js b/creative/renderers/native/constants.js index ac20275fca8..b82e2d1d54e 100644 --- a/creative/renderers/native/constants.js +++ b/creative/renderers/native/constants.js @@ -1,7 +1,7 @@ // eslint-disable-next-line prebid/validate-imports -import CONSTANTS from '../../../src/constants.json'; +import { MESSAGES } from '../../../src/constants.js'; -export const MESSAGE_NATIVE = CONSTANTS.MESSAGES.NATIVE; +export const MESSAGE_NATIVE = MESSAGES.NATIVE; export const ACTION_RESIZE = 'resizeNativeHeight'; export const ACTION_CLICK = 'click'; export const ACTION_IMP = 'fireNativeImpressionTrackers'; diff --git a/libraries/analyticsAdapter/AnalyticsAdapter.js b/libraries/analyticsAdapter/AnalyticsAdapter.js index e1933d215e4..395a21e5571 100644 --- a/libraries/analyticsAdapter/AnalyticsAdapter.js +++ b/libraries/analyticsAdapter/AnalyticsAdapter.js @@ -1,4 +1,4 @@ -import CONSTANTS from '../../src/constants.json'; +import { EVENTS } from '../../src/constants.js'; import {ajax} from '../../src/ajax.js'; import {logError, logMessage} from '../../src/utils.js'; import * as events from '../../src/events.js'; @@ -9,8 +9,8 @@ export const _internal = { const ENDPOINT = 'endpoint'; const BUNDLE = 'bundle'; -export const DEFAULT_INCLUDE_EVENTS = Object.values(CONSTANTS.EVENTS) - .filter(ev => ev !== CONSTANTS.EVENTS.AUCTION_DEBUG); +export const DEFAULT_INCLUDE_EVENTS = Object.values(EVENTS) + .filter(ev => ev !== EVENTS.AUCTION_DEBUG); let debounceDelay = 100; @@ -114,7 +114,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } const trackedEvents = (() => { const {includeEvents = DEFAULT_INCLUDE_EVENTS, excludeEvents = []} = (config || {}); return new Set( - Object.values(CONSTANTS.EVENTS) + Object.values(EVENTS) .filter(ev => includeEvents.includes(ev)) .filter(ev => !excludeEvents.includes(ev)) ); diff --git a/modules/33acrossAnalyticsAdapter.js b/modules/33acrossAnalyticsAdapter.js index e3539906b13..890c963fa71 100644 --- a/modules/33acrossAnalyticsAdapter.js +++ b/modules/33acrossAnalyticsAdapter.js @@ -1,12 +1,10 @@ import { deepAccess, logInfo, logWarn, logError, deepClone } from '../src/utils.js'; import buildAdapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager, { coppaDataHandler, gdprDataHandler, gppDataHandler, uspDataHandler } from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; - /** - * @typedef {typeof import('../src/constants.json').EVENTS} EVENTS + * @typedef {typeof import('../src/constants.js').EVENTS} EVENTS */ -const { EVENTS } = CONSTANTS; +import { EVENTS } from '../src/constants.js'; /** @typedef {'pending'|'available'|'targetingSet'|'rendered'|'timeout'|'rejected'|'noBid'|'error'} BidStatus */ /** diff --git a/modules/adWMGAnalyticsAdapter.js b/modules/adWMGAnalyticsAdapter.js index dd0340071d1..ed1ac46363c 100644 --- a/modules/adWMGAnalyticsAdapter.js +++ b/modules/adWMGAnalyticsAdapter.js @@ -1,20 +1,18 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { ajax } from '../src/ajax.js'; const analyticsType = 'endpoint'; const url = 'https://analytics.wmgroup.us/analytic/collection'; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_WON, - BID_TIMEOUT, - NO_BID, - BID_RESPONSE - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_WON, + BID_TIMEOUT, + NO_BID, + BID_RESPONSE +} = EVENTS; let timestampInit = null; diff --git a/modules/adagioAnalyticsAdapter.js b/modules/adagioAnalyticsAdapter.js index 82b3b356c81..bb5de41d3ce 100644 --- a/modules/adagioAnalyticsAdapter.js +++ b/modules/adagioAnalyticsAdapter.js @@ -4,7 +4,7 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { ajax } from '../src/ajax.js'; import { BANNER } from '../src/mediaTypes.js'; import { getWindowTop, getWindowSelf, deepAccess, logInfo, logError } from '../src/utils.js'; @@ -12,7 +12,7 @@ import { getGlobal } from '../src/prebidGlobal.js'; const emptyUrl = ''; const analyticsType = 'endpoint'; -const events = Object.keys(CONSTANTS.EVENTS).map(key => CONSTANTS.EVENTS[key]); +const events = Object.keys(EVENTS).map(key => EVENTS[key]); const ADAGIO_GVLID = 617; const VERSION = '3.0.0'; const PREBID_VERSION = '$prebid.version$'; @@ -383,22 +383,22 @@ let adagioAdapter = Object.assign(adapter({ emptyUrl, analyticsType }), { try { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: handlerAuctionInit(args); break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: handlerBidResponse(args); break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: handlerAuctionEnd(args); break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: handlerBidWon(args); break; // AD_RENDER_SUCCEEDED seems redundant with BID_WON. // case CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED: - case CONSTANTS.EVENTS.AD_RENDER_FAILED: - handlerAdRender(args, eventType === CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED); + case EVENTS.AD_RENDER_FAILED: + handlerAdRender(args, eventType === EVENTS.AD_RENDER_SUCCEEDED); break; } } catch (error) { diff --git a/modules/adkernelAdnAnalyticsAdapter.js b/modules/adkernelAdnAnalyticsAdapter.js index 48897f8516b..a32a97af3c6 100644 --- a/modules/adkernelAdnAnalyticsAdapter.js +++ b/modules/adkernelAdnAnalyticsAdapter.js @@ -1,5 +1,5 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { logError, parseUrl, _each } from '../src/utils.js'; import {ajax} from '../src/ajax.js'; @@ -51,26 +51,26 @@ let analyticsAdapter = Object.assign(adapter({analyticsType: 'endpoint'}), } let handler = null; switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: if (analyticsAdapter.context.queue) { analyticsAdapter.context.queue.init(); } initPrivacy(analyticsAdapter.context.requestTemplate, args.bidderRequests); handler = trackAuctionInit; break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: handler = trackBidRequest; break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: handler = trackBidResponse; break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: handler = trackBidWon; break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: handler = trackBidTimeout; break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: handler = trackAuctionEnd; break; } @@ -79,7 +79,7 @@ let analyticsAdapter = Object.assign(adapter({analyticsType: 'endpoint'}), if (analyticsAdapter.context.queue) { analyticsAdapter.context.queue.push(events); } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { sendAll(); } } diff --git a/modules/adlooxAdServerVideo.js b/modules/adlooxAdServerVideo.js index bd715cb34f3..199fecafd13 100644 --- a/modules/adlooxAdServerVideo.js +++ b/modules/adlooxAdServerVideo.js @@ -9,7 +9,7 @@ import { registerVideoSupport } from '../src/adServerManager.js'; import { command as analyticsCommand, COMMAND } from './adlooxAnalyticsAdapter.js'; import { ajax } from '../src/ajax.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { targeting } from '../src/targeting.js'; import { logInfo, isFn, logError, isPlainObject, isStr, isBoolean, deepSetValue, deepClone, timestamp, logWarn } from '../src/utils.js'; @@ -74,7 +74,7 @@ function track(options, callback) { bid.ext.adloox.video.adserver = false; analyticsCommand(COMMAND.TRACK, { - eventType: CONSTANTS.EVENTS.BID_WON, + eventType: EVENTS.BID_WON, args: bid }); } diff --git a/modules/adlooxAnalyticsAdapter.js b/modules/adlooxAnalyticsAdapter.js index 9284d543298..e31ea290e11 100644 --- a/modules/adlooxAnalyticsAdapter.js +++ b/modules/adlooxAnalyticsAdapter.js @@ -9,7 +9,7 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import {loadExternalScript} from '../src/adloader.js'; import {auctionManager} from '../src/auctionManager.js'; import {AUCTION_COMPLETED} from '../src/auction.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; import {find} from '../src/polyfill.js'; import {getRefererInfo} from '../src/refererDetection.js'; import { @@ -220,9 +220,9 @@ analyticsAdapter.url = function(url, args, bid) { return url + a2qs(args); } -analyticsAdapter[`handle_${CONSTANTS.EVENTS.AUCTION_END}`] = function(auctionDetails) { +analyticsAdapter[`handle_${EVENTS.AUCTION_END}`] = function(auctionDetails) { if (!(auctionDetails.auctionStatus == AUCTION_COMPLETED && auctionDetails.bidsReceived.length > 0)) return; - analyticsAdapter[`handle_${CONSTANTS.EVENTS.AUCTION_END}`] = NOOP; + analyticsAdapter[`handle_${EVENTS.AUCTION_END}`] = NOOP; logMessage(MODULE, 'preloading verification JS'); @@ -235,7 +235,7 @@ analyticsAdapter[`handle_${CONSTANTS.EVENTS.AUCTION_END}`] = function(auctionDet insertElement(link); } -analyticsAdapter[`handle_${CONSTANTS.EVENTS.BID_WON}`] = function(bid) { +analyticsAdapter[`handle_${EVENTS.BID_WON}`] = function(bid) { if (deepAccess(bid, 'ext.adloox.video.adserver')) { logMessage(MODULE, `measuring '${bid.mediaType}' ad unit code '${bid.adUnitCode}' via Ad Server module`); return; diff --git a/modules/adomikAnalyticsAdapter.js b/modules/adomikAnalyticsAdapter.js index 27a6821d9f5..d6e1547cce8 100644 --- a/modules/adomikAnalyticsAdapter.js +++ b/modules/adomikAnalyticsAdapter.js @@ -1,16 +1,16 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {logInfo} from '../src/utils.js'; import {find, findIndex} from '../src/polyfill.js'; // Events used in adomik analytics adapter. -const auctionInit = CONSTANTS.EVENTS.AUCTION_INIT; -const auctionEnd = CONSTANTS.EVENTS.AUCTION_END; -const bidRequested = CONSTANTS.EVENTS.BID_REQUESTED; -const bidResponse = CONSTANTS.EVENTS.BID_RESPONSE; -const bidWon = CONSTANTS.EVENTS.BID_WON; -const bidTimeout = CONSTANTS.EVENTS.BID_TIMEOUT; +const auctionInit = EVENTS.AUCTION_INIT; +const auctionEnd = EVENTS.AUCTION_END; +const bidRequested = EVENTS.BID_REQUESTED; +const bidResponse = EVENTS.BID_RESPONSE; +const bidWon = EVENTS.BID_WON; +const bidTimeout = EVENTS.BID_TIMEOUT; const ua = navigator.userAgent; var _sampled = true; diff --git a/modules/adpod.js b/modules/adpod.js index f6d8309cd9f..b6d13673178 100644 --- a/modules/adpod.js +++ b/modules/adpod.js @@ -38,7 +38,7 @@ import {config} from '../src/config.js'; import {ADPOD} from '../src/mediaTypes.js'; import {find, arrayFrom as from} from '../src/polyfill.js'; import {auctionManager} from '../src/auctionManager.js'; -import CONSTANTS from '../src/constants.json'; +import { TARGETING_KEYS } from '../src/constants.js'; const TARGETING_KEY_PB_CAT_DUR = 'hb_pb_cat_dur'; const TARGETING_KEY_CACHE_ID = 'hb_cache_id'; @@ -454,10 +454,10 @@ export function callPrebidCacheAfterAuction(bids, callback) { * @param {Object} bid */ export function sortByPricePerSecond(a, b) { - if (a.adserverTargeting[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket < b.adserverTargeting[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { + if (a.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket < b.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { return 1; } - if (a.adserverTargeting[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket > b.adserverTargeting[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { + if (a.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket > b.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) { return -1; } return 0; diff --git a/modules/adxcgAnalyticsAdapter.js b/modules/adxcgAnalyticsAdapter.js index 21b6c1be783..7ad95121209 100644 --- a/modules/adxcgAnalyticsAdapter.js +++ b/modules/adxcgAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { parseSizesInput, uniques, buildUrl, logError } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getGlobal} from '../src/prebidGlobal.js'; /** @@ -22,29 +22,29 @@ var adxcgAnalyticsAdapter = Object.assign(adapter( }), { track ({eventType, args}) { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: adxcgAnalyticsAdapter.context.events.auctionInit = mapAuctionInit(args); adxcgAnalyticsAdapter.context.auctionTimestamp = args.timestamp; break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: adxcgAnalyticsAdapter.context.auctionId = args.auctionId; adxcgAnalyticsAdapter.context.events.bidRequests.push(mapBidRequested(args)); break; - case CONSTANTS.EVENTS.BID_ADJUSTMENT: + case EVENTS.BID_ADJUSTMENT: break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: adxcgAnalyticsAdapter.context.events.bidTimeout = args.map(item => item.bidder).filter(uniques); break; - case CONSTANTS.EVENTS.BIDDER_DONE: + case EVENTS.BIDDER_DONE: break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: adxcgAnalyticsAdapter.context.events.bidResponses.push(mapBidResponse(args, eventType)); break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: let outData2 = {bidWons: mapBidWon(args)}; send(outData2); break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: send(adxcgAnalyticsAdapter.context.events); break; } @@ -87,7 +87,7 @@ function mapBidResponse (bidResponse, eventType) { currency: bidResponse.currency, netRevenue: bidResponse.netRevenue, timeToRespond: bidResponse.timeToRespond, - bidId: eventType === CONSTANTS.EVENTS.BID_TIMEOUT ? bidResponse.bidId : bidResponse.requestId, + bidId: eventType === EVENTS.BID_TIMEOUT ? bidResponse.bidId : bidResponse.requestId, dealId: bidResponse.dealId, status: bidResponse.status, creativeId: bidResponse.creativeId.toString() diff --git a/modules/adxpremiumAnalyticsAdapter.js b/modules/adxpremiumAnalyticsAdapter.js index 9161c6338f4..e3f77e96725 100644 --- a/modules/adxpremiumAnalyticsAdapter.js +++ b/modules/adxpremiumAnalyticsAdapter.js @@ -2,7 +2,7 @@ import {deepClone, logError, logInfo} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {includes} from '../src/polyfill.js'; const analyticsType = 'endpoint'; @@ -12,15 +12,13 @@ let reqCountry = window.reqCountry || null; // Events needed const { - EVENTS: { - AUCTION_INIT, - BID_REQUESTED, - BID_TIMEOUT, - BID_RESPONSE, - BID_WON, - AUCTION_END - } -} = CONSTANTS; + AUCTION_INIT, + BID_REQUESTED, + BID_TIMEOUT, + BID_RESPONSE, + BID_WON, + AUCTION_END +} = EVENTS; let timeoutBased = false; let requestSent = false; diff --git a/modules/agmaAnalyticsAdapter.js b/modules/agmaAnalyticsAdapter.js index f3933cc7625..e2e01fb4d03 100644 --- a/modules/agmaAnalyticsAdapter.js +++ b/modules/agmaAnalyticsAdapter.js @@ -9,7 +9,7 @@ import { } from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager, { gdprDataHandler } from '../src/adapterManager.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { config } from '../src/config.js'; @@ -22,10 +22,6 @@ const batchDelayInMs = 1000; const agmaURL = 'https://pbc.agma-analytics.de/v1'; const pageViewId = generateUUID(); -const { - EVENTS: { AUCTION_INIT }, -} = CONSTANTS; - // Helper functions const getScreen = () => { const w = window; @@ -212,7 +208,7 @@ agmaAnalytics.enableAnalytics = function (config = {}) { } agmaAnalytics.options = { - triggerEvent: AUCTION_INIT, + triggerEvent: EVENTS.AUCTION_INIT, ...options, }; diff --git a/modules/appierAnalyticsAdapter.js b/modules/appierAnalyticsAdapter.js index b4081feaf92..3664c49c424 100644 --- a/modules/appierAnalyticsAdapter.js +++ b/modules/appierAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {logError, logInfo, deepClone} from '../src/utils.js'; @@ -12,12 +12,10 @@ export const ANALYTICS_VERSION = '1.0.0'; const DEFAULT_SERVER = 'https://prebid-analytics.c.appier.net/v1'; const { - EVENTS: { - AUCTION_END, - BID_WON, - BID_TIMEOUT - } -} = CONSTANTS; + AUCTION_END, + BID_WON, + BID_TIMEOUT +} = EVENTS; export const BIDDER_STATUS = { BID: 'bid', diff --git a/modules/asteriobidAnalyticsAdapter.js b/modules/asteriobidAnalyticsAdapter.js index 516a3a65667..d5b6c0b4cf7 100644 --- a/modules/asteriobidAnalyticsAdapter.js +++ b/modules/asteriobidAnalyticsAdapter.js @@ -3,7 +3,7 @@ import { ajaxBuilder } from '../src/ajax.js' import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js' import adapterManager from '../src/adapterManager.js' import { getStorageManager } from '../src/storageManager.js' -import CONSTANTS from '../src/constants.json' +import { EVENTS } from '../src/constants.js' import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js' import {getRefererInfo} from '../src/refererDetection.js'; @@ -203,7 +203,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.eventType = eventType switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { pmEvent.auctionId = eventArgs.auctionId pmEvent.timeout = eventArgs.timeout pmEvent.adUnits = eventArgs.adUnits && eventArgs.adUnits.map(trimAdUnit) @@ -212,7 +212,7 @@ function handleEvent(eventType, eventArgs) { auctionTimeouts[pmEvent.auctionId] = pmEvent.timeout break } - case CONSTANTS.EVENTS.AUCTION_END: { + case EVENTS.AUCTION_END: { pmEvent.auctionId = eventArgs.auctionId pmEvent.end = eventArgs.end pmEvent.start = eventArgs.start @@ -222,15 +222,15 @@ function handleEvent(eventType, eventArgs) { pmEvent.end = Date.now() break } - case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + case EVENTS.BID_ADJUSTMENT: { break } - case CONSTANTS.EVENTS.BID_TIMEOUT: { + case EVENTS.BID_TIMEOUT: { pmEvent.bidders = eventArgs && eventArgs.map ? eventArgs.map(trimBid) : eventArgs pmEvent.duration = auctionTimeouts[pmEvent.auctionId] break } - case CONSTANTS.EVENTS.BID_REQUESTED: { + case EVENTS.BID_REQUESTED: { pmEvent.auctionId = eventArgs.auctionId pmEvent.bidderCode = eventArgs.bidderCode pmEvent.doneCbCallCount = eventArgs.doneCbCallCount @@ -241,7 +241,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.timeout = eventArgs.timeout break } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { pmEvent.bidderCode = eventArgs.bidderCode pmEvent.width = eventArgs.width pmEvent.height = eventArgs.height @@ -260,7 +260,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.adserverTargeting = eventArgs.adserverTargeting break } - case CONSTANTS.EVENTS.BID_WON: { + case EVENTS.BID_WON: { pmEvent.auctionId = eventArgs.auctionId pmEvent.adId = eventArgs.adId pmEvent.adserverTargeting = eventArgs.adserverTargeting @@ -278,7 +278,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.bidder = eventArgs.bidder break } - case CONSTANTS.EVENTS.BIDDER_DONE: { + case EVENTS.BIDDER_DONE: { pmEvent.auctionId = eventArgs.auctionId pmEvent.auctionStart = eventArgs.auctionStart pmEvent.bidderCode = eventArgs.bidderCode @@ -291,16 +291,16 @@ function handleEvent(eventType, eventArgs) { pmEvent.src = eventArgs.src break } - case CONSTANTS.EVENTS.SET_TARGETING: { + case EVENTS.SET_TARGETING: { break } - case CONSTANTS.EVENTS.REQUEST_BIDS: { + case EVENTS.REQUEST_BIDS: { break } - case CONSTANTS.EVENTS.ADD_AD_UNITS: { + case EVENTS.ADD_AD_UNITS: { break } - case CONSTANTS.EVENTS.AD_RENDER_FAILED: { + case EVENTS.AD_RENDER_FAILED: { pmEvent.bid = eventArgs.bid pmEvent.message = eventArgs.message pmEvent.reason = eventArgs.reason @@ -317,7 +317,7 @@ function sendEvent(event) { eventQueue.push(event) logInfo(`${analyticsName} Event ${event.eventType}:`, event) - if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (event.eventType === EVENTS.AUCTION_END) { flush() } } diff --git a/modules/atsAnalyticsAdapter.js b/modules/atsAnalyticsAdapter.js index 8e92146694f..d94e68b7e55 100644 --- a/modules/atsAnalyticsAdapter.js +++ b/modules/atsAnalyticsAdapter.js @@ -1,6 +1,6 @@ import { logError, logInfo } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adaptermanager from '../src/adapterManager.js'; import {ajax} from '../src/ajax.js'; import {getStorageManager} from '../src/storageManager.js'; @@ -346,12 +346,12 @@ atsAnalyticsAdapter.enableAnalytics = function (config) { }; atsAnalyticsAdapter.callHandler = function (evtype, args) { - if (evtype === CONSTANTS.EVENTS.BID_REQUESTED) { + if (evtype === EVENTS.BID_REQUESTED) { handlerRequest = handlerRequest.concat(bidRequestedHandler(args)); - } else if (evtype === CONSTANTS.EVENTS.BID_RESPONSE) { + } else if (evtype === EVENTS.BID_RESPONSE) { handlerResponse.push(bidResponseHandler(args)); } - if (evtype === CONSTANTS.EVENTS.AUCTION_END) { + if (evtype === EVENTS.AUCTION_END) { let bidWonTimeout = atsAnalyticsAdapter.context.bidWonTimeout ? atsAnalyticsAdapter.context.bidWonTimeout : 2000; let events = []; setTimeout(() => { diff --git a/modules/automatadAnalyticsAdapter.js b/modules/automatadAnalyticsAdapter.js index 436418e7597..523e8d558ca 100644 --- a/modules/automatadAnalyticsAdapter.js +++ b/modules/automatadAnalyticsAdapter.js @@ -4,7 +4,7 @@ import { logMessage } from '../src/utils.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import { config } from '../src/config.js' @@ -57,49 +57,49 @@ const processEvents = () => { try { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: if (window.atmtdAnalytics && window.atmtdAnalytics.auctionInitHandler) { window.atmtdAnalytics.auctionInitHandler(args); } else { shouldTryAgain = true } break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: if (window.atmtdAnalytics && window.atmtdAnalytics.bidRequestedHandler) { window.atmtdAnalytics.bidRequestedHandler(args); } break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: if (window.atmtdAnalytics && window.atmtdAnalytics.bidResponseHandler) { window.atmtdAnalytics.bidResponseHandler(args); } break; - case CONSTANTS.EVENTS.BID_REJECTED: + case EVENTS.BID_REJECTED: if (window.atmtdAnalytics && window.atmtdAnalytics.bidRejectedHandler) { window.atmtdAnalytics.bidRejectedHandler(args); } break; - case CONSTANTS.EVENTS.BIDDER_DONE: + case EVENTS.BIDDER_DONE: if (window.atmtdAnalytics && window.atmtdAnalytics.bidderDoneHandler) { window.atmtdAnalytics.bidderDoneHandler(args); } break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: if (window.atmtdAnalytics && window.atmtdAnalytics.bidWonHandler) { window.atmtdAnalytics.bidWonHandler(args); } break; - case CONSTANTS.EVENTS.NO_BID: + case EVENTS.NO_BID: if (window.atmtdAnalytics && window.atmtdAnalytics.noBidHandler) { window.atmtdAnalytics.noBidHandler(args); } break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: if (window.atmtdAnalytics && window.atmtdAnalytics.bidderTimeoutHandler) { window.atmtdAnalytics.bidderTimeoutHandler(args); } break; - case CONSTANTS.EVENTS.AUCTION_DEBUG: + case EVENTS.AUCTION_DEBUG: if (window.atmtdAnalytics && window.atmtdAnalytics.auctionDebugHandler) { window.atmtdAnalytics.auctionDebugHandler(args); } @@ -173,7 +173,7 @@ const initializeQueue = () => { timer = null; } - if (args[0] === CONSTANTS.EVENTS.AUCTION_INIT) { + if (args[0] === EVENTS.AUCTION_INIT) { const timeout = parseInt(config.getConfig('bidderTimeout')) + 1500 timer = setTimeout(() => { self.processEvents() @@ -198,7 +198,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { track({eventType, args}) { const shouldNotPushToQueue = !self.qBeingUsed switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: if (window.atmtdAnalytics && window.atmtdAnalytics.auctionInitHandler && shouldNotPushToQueue) { self.prettyLog('status', 'Aggregator loaded, initialising auction through handlers'); window.atmtdAnalytics.auctionInitHandler(args); @@ -207,7 +207,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: if (window.atmtdAnalytics && window.atmtdAnalytics.bidRequestedHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidRequestedHandler(args); } else { @@ -215,7 +215,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BID_REJECTED: + case EVENTS.BID_REJECTED: if (window.atmtdAnalytics && window.atmtdAnalytics.bidRejectedHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidRejectedHandler(args); } else { @@ -223,7 +223,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: if (window.atmtdAnalytics && window.atmtdAnalytics.bidResponseHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidResponseHandler(args); } else { @@ -231,7 +231,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BIDDER_DONE: + case EVENTS.BIDDER_DONE: if (window.atmtdAnalytics && window.atmtdAnalytics.bidderDoneHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidderDoneHandler(args); } else { @@ -239,7 +239,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: if (window.atmtdAnalytics && window.atmtdAnalytics.bidWonHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidWonHandler(args); } else { @@ -247,7 +247,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.NO_BID: + case EVENTS.NO_BID: if (window.atmtdAnalytics && window.atmtdAnalytics.noBidHandler && shouldNotPushToQueue) { window.atmtdAnalytics.noBidHandler(args); } else { @@ -255,7 +255,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.AUCTION_DEBUG: + case EVENTS.AUCTION_DEBUG: if (window.atmtdAnalytics && window.atmtdAnalytics.auctionDebugHandler && shouldNotPushToQueue) { window.atmtdAnalytics.auctionDebugHandler(args); } else { @@ -263,7 +263,7 @@ let atmtdAdapter = Object.assign({}, baseAdapter, { self.__atmtdAnalyticsQueue.push([eventType, args]) } break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: if (window.atmtdAnalytics && window.atmtdAnalytics.bidderTimeoutHandler && shouldNotPushToQueue) { window.atmtdAnalytics.bidderTimeoutHandler(args); } else { diff --git a/modules/bidViewability.js b/modules/bidViewability.js index be18095e369..c1aab83b7e6 100644 --- a/modules/bidViewability.js +++ b/modules/bidViewability.js @@ -4,7 +4,7 @@ import {config} from '../src/config.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {isFn, logWarn, triggerPixel} from '../src/utils.js'; import {getGlobal} from '../src/prebidGlobal.js'; import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../src/adapterManager.js'; @@ -82,12 +82,12 @@ export let impressionViewableHandler = (globalModuleConfig, slot, event) => { } // emit the BID_VIEWABLE event with bid details, this event can be consumed by bidders and analytics pixels - events.emit(CONSTANTS.EVENTS.BID_VIEWABLE, respectiveBid); + events.emit(EVENTS.BID_VIEWABLE, respectiveBid); } }; export let init = () => { - events.on(CONSTANTS.EVENTS.AUCTION_INIT, () => { + events.on(EVENTS.AUCTION_INIT, () => { // read the config for the module const globalModuleConfig = config.getConfig(MODULE_NAME) || {}; // do nothing if module-config.enabled is not set to true diff --git a/modules/bidViewabilityIO.js b/modules/bidViewabilityIO.js index ff7ec70e32c..61b8af66bf8 100644 --- a/modules/bidViewabilityIO.js +++ b/modules/bidViewabilityIO.js @@ -1,7 +1,7 @@ import { logMessage } from '../src/utils.js'; import { config } from '../src/config.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; const MODULE_NAME = 'bidViewabilityIO'; const CONFIG_ENABLED = 'enabled'; @@ -42,7 +42,7 @@ export let getViewableOptions = (bid) => { export let markViewed = (bid, entry, observer) => { return () => { observer.unobserve(entry.target); - events.emit(CONSTANTS.EVENTS.BID_VIEWABLE, bid); + events.emit(EVENTS.BID_VIEWABLE, bid); _logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} was viewed`); } } @@ -77,7 +77,7 @@ export let init = () => { if (conf[MODULE_NAME][CONFIG_ENABLED] && CLIENT_SUPPORTS_IO) { // if the module is enabled and the browser supports Intersection Observer, // then listen to AD_RENDER_SUCCEEDED to setup IO's for supported mediaTypes - events.on(CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, ({doc, bid, id}) => { + events.on(EVENTS.AD_RENDER_SUCCEEDED, ({doc, bid, id}) => { if (isSupportedMediaType(bid)) { let viewable = new IntersectionObserver(viewCallbackFactory(bid), getViewableOptions(bid)); let element = document.getElementById(bid.adUnitCode); diff --git a/modules/bidwatchAnalyticsAdapter.js b/modules/bidwatchAnalyticsAdapter.js index 289e607686f..ffbd125eeab 100644 --- a/modules/bidwatchAnalyticsAdapter.js +++ b/modules/bidwatchAnalyticsAdapter.js @@ -1,6 +1,6 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { ajax } from '../src/ajax.js'; import { getRefererInfo } from '../src/refererDetection.js'; @@ -8,14 +8,12 @@ const analyticsType = 'endpoint'; const url = 'URL_TO_SERVER_ENDPOINT'; const { - EVENTS: { - AUCTION_END, - BID_WON, - BID_RESPONSE, - BID_REQUESTED, - BID_TIMEOUT, - } -} = CONSTANTS; + AUCTION_END, + BID_WON, + BID_RESPONSE, + BID_REQUESTED, + BID_TIMEOUT, +} = EVENTS; let saveEvents = {} let allEvents = {} diff --git a/modules/brandmetricsRtdProvider.js b/modules/brandmetricsRtdProvider.js index 2d9dcdfdf48..b463a5480f8 100644 --- a/modules/brandmetricsRtdProvider.js +++ b/modules/brandmetricsRtdProvider.js @@ -5,11 +5,11 @@ * @module modules/brandmetricsRtdProvider * @requires module:modules/realTimeData */ -import {submodule} from '../src/hook.js'; -import {deepAccess, deepSetValue, logError, mergeDeep, generateUUID} from '../src/utils.js'; -import {loadExternalScript} from '../src/adloader.js'; +import { submodule } from '../src/hook.js'; +import { deepAccess, deepSetValue, logError, mergeDeep, generateUUID } from '../src/utils.js'; +import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -156,7 +156,7 @@ function initializeBillableEvents() { handler: (ev) => { if (ev.source && ev.source.type === 'pbj') { const bid = ev.source.data; - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { vendor: 'brandmetrics', type: 'creative_in_view', measurementId: ev.mid, @@ -202,7 +202,7 @@ export const brandmetricsSubmodule = { logError(e) } }, - init: init + init } submodule('realTimeData', brandmetricsSubmodule) diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index ab3db2a5d20..ad4019ed03c 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -23,7 +23,7 @@ import {getStorageManager} from '../src/storageManager.js'; import {find, includes} from '../src/polyfill.js'; import {getGlobal} from '../src/prebidGlobal.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; /** @@ -67,7 +67,7 @@ export function addBrowsiTag(data) { export function sendPageviewEvent(eventType) { if (eventType === 'PAGEVIEW') { window.addEventListener('browsi_pageview', () => { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { vendor: 'browsi', type: 'pageview', billingId: generateUUID() @@ -363,7 +363,7 @@ function getTargetingData(uc, c, us, a) { } if (sendAdRequestEvent) { const transactionId = a.adUnits.find(adUnit => adUnit.code === auc).transactionId; - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { vendor: 'browsi', type: 'adRequest', billingId: generateUUID(), diff --git a/modules/byDataAnalyticsAdapter.js b/modules/byDataAnalyticsAdapter.js index 81fd4388c7d..508a5593f58 100644 --- a/modules/byDataAnalyticsAdapter.js +++ b/modules/byDataAnalyticsAdapter.js @@ -3,7 +3,7 @@ import Base64 from 'crypto-js/enc-base64'; import hmacSHA512 from 'crypto-js/hmac-sha512'; import enc from 'crypto-js/enc-utf8'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, BID_STATUS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; import { auctionManager } from '../src/auctionManager.js'; @@ -12,7 +12,7 @@ import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; const versionCode = '4.4.1' const secretKey = 'bydata@123456' -const { EVENTS: { NO_BID, BID_TIMEOUT, AUCTION_END, AUCTION_INIT, BID_WON } } = CONSTANTS +const { NO_BID, BID_TIMEOUT, AUCTION_END, AUCTION_INIT, BID_WON } = EVENTS const DEFAULT_EVENT_URL = 'https://pbjs-stream.bydata.com/topics/prebid' const analyticsType = 'endpoint' const isBydata = isKeyInUrl('bydata_debug') @@ -342,7 +342,7 @@ ascAdapter.dataProcess = function (t) { }) }); - var prebidWinningBids = auctionManager.getBidsReceived().filter(bid => bid.status === CONSTANTS.BID_STATUS.BID_TARGETING_SET); + var prebidWinningBids = auctionManager.getBidsReceived().filter(bid => bid.status === BID_STATUS.BID_TARGETING_SET); prebidWinningBids && prebidWinningBids.length > 0 && prebidWinningBids.forEach(pbbid => { payload['auctionData'] && payload['auctionData'].forEach(rwData => { if (rwData['bid'] === pbbid.requestId && rwData['brs'] === pbbid.size) { diff --git a/modules/cleanioRtdProvider.js b/modules/cleanioRtdProvider.js index f9bed5357ee..c3f3dd51a61 100644 --- a/modules/cleanioRtdProvider.js +++ b/modules/cleanioRtdProvider.js @@ -10,7 +10,7 @@ import { submodule } from '../src/hook.js'; import { loadExternalScript } from '../src/adloader.js'; import { logError, generateUUID, insertElement } from '../src/utils.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -158,8 +158,8 @@ function readConfig(config) { let startBillableEvents = function() { // Upon clean.io submodule initialization, every winner bid is considered to be protected // and therefore, subjected to billing - events.on(CONSTANTS.EVENTS.BID_WON, winnerBidResponse => { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.on(EVENTS.BID_WON, winnerBidResponse => { + events.emit(EVENTS.BILLABLE_EVENT, { vendor: 'clean.io', billingId: generateUUID(), type: 'impression', diff --git a/modules/concertAnalyticsAdapter.js b/modules/concertAnalyticsAdapter.js index 210d1898338..742646960f3 100644 --- a/modules/concertAnalyticsAdapter.js +++ b/modules/concertAnalyticsAdapter.js @@ -1,7 +1,7 @@ import { logMessage } from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; const analyticsType = 'endpoint'; @@ -13,12 +13,10 @@ const pageIncludedInSample = sampleAnalytics(); const url = 'https://bids.concert.io/analytics'; const { - EVENTS: { - BID_RESPONSE, - BID_WON, - AUCTION_END - } -} = CONSTANTS; + BID_RESPONSE, + BID_WON, + AUCTION_END +} = EVENTS; let queue = []; diff --git a/modules/confiantRtdProvider.js b/modules/confiantRtdProvider.js index 6b1066a20f1..4c5475421bb 100644 --- a/modules/confiantRtdProvider.js +++ b/modules/confiantRtdProvider.js @@ -12,7 +12,7 @@ import { submodule } from '../src/hook.js'; import { logError, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; /** * Injects the Confiant Inc. configuration script into the page, based on proprtyId provided @@ -89,7 +89,7 @@ function setUpMutationObserver() { function getEventHandlerFunction(propertyId) { return function reportBillableEvent(e) { if (e.data.type.indexOf('cnft:reportBillableEvent:' + propertyId) > -1) { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { auctionId: e.data.auctionId, billingId: generateUUID(), transactionId: e.data.transactionId, diff --git a/modules/conversantAnalyticsAdapter.js b/modules/conversantAnalyticsAdapter.js index 0c58402ca87..44e712d54f7 100644 --- a/modules/conversantAnalyticsAdapter.js +++ b/modules/conversantAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getGlobal} from '../src/prebidGlobal.js'; import adapterManager from '../src/adapterManager.js'; import {logInfo, logWarn, logError, logMessage, deepAccess, isInteger} from '../src/utils.js'; @@ -8,9 +8,7 @@ import {getRefererInfo} from '../src/refererDetection.js'; // Maintainer: mediapsr@epsilon.com -const { - EVENTS: { AUCTION_END, AD_RENDER_FAILED, BID_TIMEOUT, BID_WON, BIDDER_ERROR } -} = CONSTANTS; +const { AUCTION_END, AD_RENDER_FAILED, BID_TIMEOUT, BID_WON, BIDDER_ERROR } = EVENTS; // STALE_RENDER, TCF2_ENFORCEMENT would need to add extra calls for these as they likely occur after AUCTION_END? const GVLID = 24; const ANALYTICS_TYPE = 'endpoint'; diff --git a/modules/currency.js b/modules/currency.js index eaed4c50df2..c26e64a9400 100644 --- a/modules/currency.js +++ b/modules/currency.js @@ -1,6 +1,6 @@ import {logError, logInfo, logMessage, logWarn} from '../src/utils.js'; import {getGlobal} from '../src/prebidGlobal.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, REJECTION_REASON } from '../src/constants.js'; import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; import {getHook} from '../src/hook.js'; @@ -163,8 +163,8 @@ function initCurrency() { getGlobal().convertCurrency = (cpm, fromCurrency, toCurrency) => parseFloat(cpm) * getCurrencyConversion(fromCurrency, toCurrency); getHook('addBidResponse').before(addBidResponseHook, 100); getHook('responsesReady').before(responsesReadyHook); - onEvent(CONSTANTS.EVENTS.AUCTION_TIMEOUT, rejectOnAuctionTimeout); - onEvent(CONSTANTS.EVENTS.AUCTION_INIT, loadRates); + onEvent(EVENTS.AUCTION_TIMEOUT, rejectOnAuctionTimeout); + onEvent(EVENTS.AUCTION_INIT, loadRates); loadRates(); } @@ -173,8 +173,8 @@ function resetCurrency() { getHook('addBidResponse').getHooks({hook: addBidResponseHook}).remove(); getHook('responsesReady').getHooks({hook: responsesReadyHook}).remove(); - offEvent(CONSTANTS.EVENTS.AUCTION_TIMEOUT, rejectOnAuctionTimeout); - offEvent(CONSTANTS.EVENTS.AUCTION_INIT, loadRates); + offEvent(EVENTS.AUCTION_TIMEOUT, rejectOnAuctionTimeout); + offEvent(EVENTS.AUCTION_INIT, loadRates); delete getGlobal().convertCurrency; adServerCurrency = 'USD'; @@ -230,7 +230,7 @@ export const addBidResponseHook = timedBidResponseHook('currency', function addB function rejectOnAuctionTimeout({auctionId}) { bidResponseQueue = bidResponseQueue.filter(([fn, ctx, adUnitCode, bid, reject]) => { if (bid.auctionId === auctionId) { - reject(CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY) + reject(REJECTION_REASON.CANNOT_CONVERT_CURRENCY) } else { return true; } @@ -250,7 +250,7 @@ function processBidResponseQueue() { } } catch (e) { logWarn('getCurrencyConversion threw error: ', e); - reject(CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY); + reject(REJECTION_REASON.CANNOT_CONVERT_CURRENCY); continue; } } diff --git a/modules/datawrkzBidAdapter.js b/modules/datawrkzBidAdapter.js index db795c89155..b5a096521a1 100644 --- a/modules/datawrkzBidAdapter.js +++ b/modules/datawrkzBidAdapter.js @@ -12,7 +12,7 @@ import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { createBid } from '../src/bidfactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; -import CONSTANTS from '../src/constants.json'; +import { STATUS } from '../src/constants.js'; import { OUTSTREAM, INSTREAM } from '../src/video.js'; /** @@ -416,7 +416,7 @@ function buildBannerResponse(bidRequest, bidResponse) { if (bidRequest) { let bidResponse = createBid(1); placementCode = bidRequest.placementCode; - bidRequest.status = CONSTANTS.STATUS.GOOD; + bidRequest.status = STATUS.GOOD; responseCPM = parseFloat(bidderBid.price); if (responseCPM === 0 || isNaN(responseCPM)) { let bid = createBid(2); @@ -457,7 +457,7 @@ function buildNativeResponse(bidRequest, response) { if (bidRequest) { let bidResponse = createBid(1); placementCode = bidRequest.placementCode; - bidRequest.status = CONSTANTS.STATUS.GOOD; + bidRequest.status = STATUS.GOOD; responseCPM = parseFloat(bidderBid.price); if (responseCPM === 0 || isNaN(responseCPM)) { let bid = createBid(2); @@ -506,7 +506,7 @@ function buildVideoResponse(bidRequest, response) { if (bidRequest) { let bidResponse = createBid(1); placementCode = bidRequest.placementCode; - bidRequest.status = CONSTANTS.STATUS.GOOD; + bidRequest.status = STATUS.GOOD; responseCPM = parseFloat(bidderBid.price); if (responseCPM === 0 || isNaN(responseCPM)) { let bid = createBid(2); diff --git a/modules/debugging/pbsInterceptor.js b/modules/debugging/pbsInterceptor.js index 73df01bf205..5c2eb458b18 100644 --- a/modules/debugging/pbsInterceptor.js +++ b/modules/debugging/pbsInterceptor.js @@ -1,5 +1,5 @@ import {deepClone, delayExecution} from '../../src/utils.js'; -import CONSTANTS from '../../src/constants.json'; +import { STATUS } from '../../src/constants.js'; export function makePbsInterceptor({createBid}) { return function pbsBidInterceptor(next, interceptBids, s2sBidRequest, bidRequests, ajax, { @@ -17,7 +17,7 @@ export function makePbsInterceptor({createBid}) { function addBid(bid, bidRequest) { onBid({ adUnit: bidRequest.adUnitCode, - bid: Object.assign(createBid(CONSTANTS.STATUS.GOOD, bidRequest), bid) + bid: Object.assign(createBid(STATUS.GOOD, bidRequest), bid) }) } bidRequests = bidRequests diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 7f275992210..abf58aceb45 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -20,7 +20,7 @@ import {getHook, submodule} from '../src/hook.js'; import {auctionManager} from '../src/auctionManager.js'; import {gdprDataHandler} from '../src/adapterManager.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getPPID} from '../src/adserver.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {CLIENT_SECTIONS} from '../src/fpd/oneClient.js'; @@ -360,7 +360,7 @@ function getCustParams(bid, options, urlCustParams) { ); // TODO: WTF is this? just firing random events, guessing at the argument, hoping noone notices? - events.emit(CONSTANTS.EVENTS.SET_TARGETING, {[adUnit.code]: prebidTargetingSet}); + events.emit(EVENTS.SET_TARGETING, {[adUnit.code]: prebidTargetingSet}); // merge the prebid + publisher targeting sets const publisherTargetingSet = deepAccess(options, 'params.cust_params'); diff --git a/modules/dsaControl.js b/modules/dsaControl.js index b08a6ea1f4e..73a1dd19cd4 100644 --- a/modules/dsaControl.js +++ b/modules/dsaControl.js @@ -1,7 +1,7 @@ import {config} from '../src/config.js'; import {auctionManager} from '../src/auctionManager.js'; import {timedBidResponseHook} from '../src/utils/perfMetrics.js'; -import CONSTANTS from '../src/constants.json'; +import { REJECTION_REASON } from '../src/constants.js'; import {getHook} from '../src/hook.js'; import {logInfo, logWarn} from '../src/utils.js'; @@ -18,18 +18,18 @@ export const addBidResponseHook = timedBidResponseHook('dsa', function (fn, adUn if (!bid.meta?.dsa) { if (dsaRequest.dsarequired === 1) { // request says dsa is supported; response does not have dsa info; warn about it - logWarn(`dsaControl: ${CONSTANTS.REJECTION_REASON.DSA_REQUIRED}; will still be accepted as regs.ext.dsa.dsarequired = 1`, bid); + logWarn(`dsaControl: ${REJECTION_REASON.DSA_REQUIRED}; will still be accepted as regs.ext.dsa.dsarequired = 1`, bid); } else if ([2, 3].includes(dsaRequest.dsarequired)) { // request says dsa is required; response does not have dsa info; reject it - rejectReason = CONSTANTS.REJECTION_REASON.DSA_REQUIRED; + rejectReason = REJECTION_REASON.DSA_REQUIRED; } } else { if (dsaRequest.pubrender === 0 && bid.meta.dsa.adrender === 0) { // request says publisher can't render; response says advertiser won't; reject it - rejectReason = CONSTANTS.REJECTION_REASON.DSA_MISMATCH; + rejectReason = REJECTION_REASON.DSA_MISMATCH; } else if (dsaRequest.pubrender === 2 && bid.meta.dsa.adrender === 1) { // request says publisher will render; response says advertiser will; reject it - rejectReason = CONSTANTS.REJECTION_REASON.DSA_MISMATCH; + rejectReason = REJECTION_REASON.DSA_MISMATCH; } } } diff --git a/modules/eplanningAnalyticsAdapter.js b/modules/eplanningAnalyticsAdapter.js index 9eb701b8ecc..45a0be54715 100644 --- a/modules/eplanningAnalyticsAdapter.js +++ b/modules/eplanningAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { logError } from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; const analyticsType = 'endpoint'; const EPL_HOST = 'https://ads.us.e-planning.net/hba/1/'; @@ -64,18 +64,18 @@ function bidTimeoutHandler(args) { function callHandler(evtype, args) { let handler = null; - if (evtype === CONSTANTS.EVENTS.AUCTION_INIT) { + if (evtype === EVENTS.AUCTION_INIT) { handler = auctionInitHandler; eplAnalyticsAdapter.context.events = []; - } else if (evtype === CONSTANTS.EVENTS.AUCTION_END) { + } else if (evtype === EVENTS.AUCTION_END) { handler = auctionEndHandler; - } else if (evtype === CONSTANTS.EVENTS.BID_REQUESTED) { + } else if (evtype === EVENTS.BID_REQUESTED) { handler = bidRequestedHandler; - } else if (evtype === CONSTANTS.EVENTS.BID_RESPONSE) { + } else if (evtype === EVENTS.BID_RESPONSE) { handler = bidResponseHandler - } else if (evtype === CONSTANTS.EVENTS.BID_TIMEOUT) { + } else if (evtype === EVENTS.BID_TIMEOUT) { handler = bidTimeoutHandler; - } else if (evtype === CONSTANTS.EVENTS.BID_WON) { + } else if (evtype === EVENTS.BID_WON) { handler = bidWonHandler; } @@ -95,7 +95,7 @@ var eplAnalyticsAdapter = Object.assign(adapter( callHandler(eventType, args); } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { try { let strjson = JSON.stringify(eplAnalyticsAdapter.context.events); ajax(eplAnalyticsAdapter.context.host + eplAnalyticsAdapter.context.ci + '?d=' + encodeURIComponent(strjson)); diff --git a/modules/fintezaAnalyticsAdapter.js b/modules/fintezaAnalyticsAdapter.js index be661c96061..ab41272c85f 100644 --- a/modules/fintezaAnalyticsAdapter.js +++ b/modules/fintezaAnalyticsAdapter.js @@ -3,7 +3,7 @@ import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; const MODULE_CODE = 'finteza'; @@ -330,16 +330,16 @@ function prepareTrackData(evtype, args) { let prepareParams = null; switch (evtype) { - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: prepareParams = prepareBidRequestedParams; break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: prepareParams = prepareBidResponseParams; break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: prepareParams = prepareBidWonParams; break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: prepareParams = prepareBidTimeoutParams; break; } diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js index 5b73ec19e08..caa498c7364 100644 --- a/modules/gdprEnforcement.js +++ b/modules/gdprEnforcement.js @@ -6,7 +6,7 @@ import {deepAccess, logError, logWarn} from '../src/utils.js'; import {config} from '../src/config.js'; import adapterManager, {gdprDataHandler} from '../src/adapterManager.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {GDPR_GVLIDS, VENDORLESS_GVLID, FIRST_PARTY_GVLID} from '../src/consentHandler.js'; import { MODULE_TYPE_ANALYTICS, @@ -292,11 +292,11 @@ function emitTCF2FinalResults() { geoBlocked: formatSet(geoBlocked) }; - events.emit(CONSTANTS.EVENTS.TCF2_ENFORCEMENT, tcf2FinalResults); + events.emit(EVENTS.TCF2_ENFORCEMENT, tcf2FinalResults); [storageBlocked, biddersBlocked, analyticsBlocked, ufpdBlocked, eidsBlocked, geoBlocked].forEach(el => el.clear()); } -events.on(CONSTANTS.EVENTS.AUCTION_END, emitTCF2FinalResults); +events.on(EVENTS.AUCTION_END, emitTCF2FinalResults); /** * A configuration function that initializes some module variables, as well as adds hooks diff --git a/modules/geoedgeRtdProvider.js b/modules/geoedgeRtdProvider.js index 0b0d9027c03..46f7e7f7d6d 100644 --- a/modules/geoedgeRtdProvider.js +++ b/modules/geoedgeRtdProvider.js @@ -19,7 +19,7 @@ import { submodule } from '../src/hook.js'; import { ajax } from '../src/ajax.js'; import { generateUUID, createInvisibleIframe, insertElement, isEmpty, logError } from '../src/utils.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { loadExternalScript } from '../src/adloader.js'; import { auctionManager } from '../src/auctionManager.js'; import { getRefererInfo } from '../src/refererDetection.js'; @@ -237,7 +237,7 @@ function fireBillableEventsForApplicableBids(params) { let data = message.data; if (isBillingMessage(data, params)) { let winningBid = auctionManager.findBidByAdId(data.adId); - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { vendor: SUBMODULE_NAME, billingId: data.impressionId, type: winningBid ? 'impression' : data.type, diff --git a/modules/greenbidsAnalyticsAdapter.js b/modules/greenbidsAnalyticsAdapter.js index b881e868bf3..fd2bc1c25ea 100644 --- a/modules/greenbidsAnalyticsAdapter.js +++ b/modules/greenbidsAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {deepClone, generateUUID, logError, logInfo, logWarn} from '../src/utils.js'; @@ -11,13 +11,11 @@ export const ANALYTICS_VERSION = '2.2.0'; const ANALYTICS_SERVER = 'https://a.greenbids.ai'; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_TIMEOUT, - BILLABLE_EVENT, - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_TIMEOUT, + BILLABLE_EVENT, +} = EVENTS; export const BIDDER_STATUS = { BID: 'bid', diff --git a/modules/greenbidsRtdProvider.js b/modules/greenbidsRtdProvider.js index 7fcd163a7c2..5496fc71c4e 100644 --- a/modules/greenbidsRtdProvider.js +++ b/modules/greenbidsRtdProvider.js @@ -2,7 +2,7 @@ import { logError, deepClone, generateUUID, deepSetValue, deepAccess } from '../ import { ajax } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; const MODULE_NAME = 'greenbidsRtdProvider'; const MODULE_VERSION = '2.0.0'; @@ -28,7 +28,7 @@ function onAuctionInitEvent(auctionDetails) { let greenbidsId = deepAccess(auctionDetails.adUnits[0], 'ortb2Imp.ext.greenbids.greenbidsId', defaultId); /* greenbids was successfully called so we emit the event */ if (greenbidsId !== defaultId) { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { type: 'auction', billingId: generateUUID(), auctionId: auctionDetails.auctionId, diff --git a/modules/growthCodeAnalyticsAdapter.js b/modules/growthCodeAnalyticsAdapter.js index 5c7cc254f1d..d2cd160a364 100644 --- a/modules/growthCodeAnalyticsAdapter.js +++ b/modules/growthCodeAnalyticsAdapter.js @@ -5,7 +5,7 @@ import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import * as utils from '../src/utils.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getStorageManager} from '../src/storageManager.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {logError, logInfo} from '../src/utils.js'; @@ -35,70 +35,70 @@ let growthCodeAnalyticsAdapter = Object.assign(adapter({url: url, analyticsType} let data = {}; if (!trackEvents.includes(eventType)) return; switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { data = eventData; startAuction = data.timestamp; bidRequestTimeout = data.timeout; break; } - case CONSTANTS.EVENTS.AUCTION_END: { + case EVENTS.AUCTION_END: { data = eventData; data.start = startAuction; data.end = Date.now(); break; } - case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + case EVENTS.BID_ADJUSTMENT: { data.bidders = eventData; break; } - case CONSTANTS.EVENTS.BID_TIMEOUT: { + case EVENTS.BID_TIMEOUT: { data.bidders = eventData; data.duration = bidRequestTimeout; break; } - case CONSTANTS.EVENTS.BID_REQUESTED: { + case EVENTS.BID_REQUESTED: { data = eventData; break; } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { data = eventData; delete data.ad; break; } - case CONSTANTS.EVENTS.BID_WON: { + case EVENTS.BID_WON: { data = eventData; delete data.ad; delete data.adUrl; break; } - case CONSTANTS.EVENTS.BIDDER_DONE: { + case EVENTS.BIDDER_DONE: { data = eventData; break; } - case CONSTANTS.EVENTS.SET_TARGETING: { + case EVENTS.SET_TARGETING: { data.targetings = eventData; break; } - case CONSTANTS.EVENTS.REQUEST_BIDS: { + case EVENTS.REQUEST_BIDS: { data = eventData; break; } - case CONSTANTS.EVENTS.ADD_AD_UNITS: { + case EVENTS.ADD_AD_UNITS: { data = eventData; break; } - case CONSTANTS.EVENTS.NO_BID: { + case EVENTS.NO_BID: { data = eventData break; } @@ -170,7 +170,7 @@ function sendEvent(event) { eventQueue.push(event); logInfo(MODULE_NAME + 'Analytics Event: ' + event); - if ((event.eventType === CONSTANTS.EVENTS.AUCTION_END) || (event.eventType === CONSTANTS.EVENTS.BID_WON)) { + if ((event.eventType === EVENTS.AUCTION_END) || (event.eventType === EVENTS.BID_WON)) { logToServer(); } } diff --git a/modules/hadronAnalyticsAdapter.js b/modules/hadronAnalyticsAdapter.js index e4c09c5b6c9..d9fd4fa6f19 100644 --- a/modules/hadronAnalyticsAdapter.js +++ b/modules/hadronAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import * as utils from '../src/utils.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getStorageManager} from '../src/storageManager.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; @@ -57,70 +57,70 @@ let hadronAnalyticsAdapter = Object.assign(adapter({url: HADRON_ANALYTICS_URL, a var data = {}; if (!eventsToTrack.includes(eventType)) return; switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { data = args; startAuction = data.timestamp; bidRequestTimeout = data.timeout; break; } - case CONSTANTS.EVENTS.AUCTION_END: { + case EVENTS.AUCTION_END: { data = args; data.start = startAuction; data.end = Date.now(); break; } - case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + case EVENTS.BID_ADJUSTMENT: { data.bidders = args; break; } - case CONSTANTS.EVENTS.BID_TIMEOUT: { + case EVENTS.BID_TIMEOUT: { data.bidders = args; data.duration = bidRequestTimeout; break; } - case CONSTANTS.EVENTS.BID_REQUESTED: { + case EVENTS.BID_REQUESTED: { data = args; break; } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { data = args; delete data.ad; break; } - case CONSTANTS.EVENTS.BID_WON: { + case EVENTS.BID_WON: { data = args; delete data.ad; delete data.adUrl; break; } - case CONSTANTS.EVENTS.BIDDER_DONE: { + case EVENTS.BIDDER_DONE: { data = args; break; } - case CONSTANTS.EVENTS.SET_TARGETING: { + case EVENTS.SET_TARGETING: { data.targetings = args; break; } - case CONSTANTS.EVENTS.REQUEST_BIDS: { + case EVENTS.REQUEST_BIDS: { data = args; break; } - case CONSTANTS.EVENTS.ADD_AD_UNITS: { + case EVENTS.ADD_AD_UNITS: { data = args; break; } - case CONSTANTS.EVENTS.AD_RENDER_FAILED: { + case EVENTS.AD_RENDER_FAILED: { data = args; break; } @@ -186,7 +186,7 @@ function sendEvent(event) { eventQueue.push(event); utils.logInfo(`HADRON_ANALYTICS_EVENT ${event.eventType} `, event); - if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (event.eventType === EVENTS.AUCTION_END) { flush(); } } diff --git a/modules/holidBidAdapter.js b/modules/holidBidAdapter.js index fbcbb9492c7..f046c860562 100644 --- a/modules/holidBidAdapter.js +++ b/modules/holidBidAdapter.js @@ -6,7 +6,7 @@ import { triggerPixel, } from '../src/utils.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {BANNER} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; @@ -19,7 +19,7 @@ const TIME_TO_LIVE = 300 const TMAX = 500 let wurlMap = {} -events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler) +events.on(EVENTS.BID_WON, bidWonHandler) export const spec = { code: BIDDER_CODE, diff --git a/modules/id5AnalyticsAdapter.js b/modules/id5AnalyticsAdapter.js index d0f3198e03d..70da467ff7c 100644 --- a/modules/id5AnalyticsAdapter.js +++ b/modules/id5AnalyticsAdapter.js @@ -1,5 +1,5 @@ import buildAdapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { ajax } from '../src/ajax.js'; import { logInfo, logError } from '../src/utils.js'; @@ -7,14 +7,12 @@ import * as events from '../src/events.js'; import {getGlobal} from '../src/prebidGlobal.js'; const { - EVENTS: { - AUCTION_END, - TCF2_ENFORCEMENT, - BID_WON, - BID_VIEWABLE, - AD_RENDER_FAILED - } -} = CONSTANTS + AUCTION_END, + TCF2_ENFORCEMENT, + BID_WON, + BID_VIEWABLE, + AD_RENDER_FAILED +} = EVENTS const GVLID = 131; diff --git a/modules/instreamTracking.js b/modules/instreamTracking.js index ece556d0fd2..2686feab679 100644 --- a/modules/instreamTracking.js +++ b/modules/instreamTracking.js @@ -3,7 +3,7 @@ import { config } from '../src/config.js'; import { auctionManager } from '../src/auctionManager.js'; import { INSTREAM } from '../src/video.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json' +import { EVENTS, TARGETING_KEYS, BID_STATUS } from '../src/constants.js' /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -11,9 +11,9 @@ import CONSTANTS from '../src/constants.json' * @typedef {import('../src/adapters/bidderFactory.js').AdUnit} AdUnit */ -const {CACHE_ID, UUID} = CONSTANTS.TARGETING_KEYS; -const {BID_WON, AUCTION_END} = CONSTANTS.EVENTS; -const {RENDERED} = CONSTANTS.BID_STATUS; +const { CACHE_ID, UUID } = TARGETING_KEYS; +const { BID_WON, AUCTION_END } = EVENTS; +const { RENDERED } = BID_STATUS; const INSTREAM_TRACKING_DEFAULT_CONFIG = { enabled: false, diff --git a/modules/invisiblyAnalyticsAdapter.js b/modules/invisiblyAnalyticsAdapter.js index a4f4eba271c..24c2c452402 100644 --- a/modules/invisiblyAnalyticsAdapter.js +++ b/modules/invisiblyAnalyticsAdapter.js @@ -6,7 +6,7 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import { generateUUID, logInfo } from '../src/utils.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; const DEFAULT_EVENT_URL = 'https://api.pymx5.com/v1/' + 'sites/events'; const analyticsType = 'endpoint'; @@ -15,22 +15,20 @@ const ajax = ajaxBuilder(0); // Events needed const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_ADJUSTMENT, - BID_TIMEOUT, - BID_REQUESTED, - BID_RESPONSE, - NO_BID, - BID_WON, - BIDDER_DONE, - SET_TARGETING, - REQUEST_BIDS, - ADD_AD_UNITS, - AD_RENDER_FAILED, - }, -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_ADJUSTMENT, + BID_TIMEOUT, + BID_REQUESTED, + BID_RESPONSE, + NO_BID, + BID_WON, + BIDDER_DONE, + SET_TARGETING, + REQUEST_BIDS, + ADD_AD_UNITS, + AD_RENDER_FAILED, +} = EVENTS; const _VERSION = 1; const _pageViewId = generateUUID(); diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index a29c1a39bff..248dbea0046 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -18,7 +18,7 @@ import { } from '../src/utils.js'; import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { getStorageManager } from '../src/storageManager.js'; import * as events from '../src/events.js'; import { find } from '../src/polyfill.js'; @@ -1739,8 +1739,8 @@ export const spec = { */ isBidRequestValid: function (bid) { if (!hasRegisteredHandler) { - events.on(CONSTANTS.EVENTS.AUCTION_DEBUG, localStorageHandler); - events.on(CONSTANTS.EVENTS.AD_RENDER_FAILED, localStorageHandler); + events.on(EVENTS.AUCTION_DEBUG, localStorageHandler); + events.on(EVENTS.AD_RENDER_FAILED, localStorageHandler); hasRegisteredHandler = true; } diff --git a/modules/kargoAnalyticsAdapter.js b/modules/kargoAnalyticsAdapter.js index 652e105167d..f8b088eefe8 100644 --- a/modules/kargoAnalyticsAdapter.js +++ b/modules/kargoAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { logError } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; const EVENT_URL = 'https://krk.kargo.com/api/v1/event'; const KARGO_BIDDER_CODE = 'kargo'; @@ -23,11 +23,11 @@ var kargoAnalyticsAdapter = Object.assign( adapter({ analyticsType }), { track({ eventType, args }) { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { _logBidResponseData.auctionTimeout = args.timeout; break; } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { handleBidResponseData(args); break; } diff --git a/modules/konduitAnalyticsAdapter.js b/modules/konduitAnalyticsAdapter.js index a1a586b25db..5316d5b22a4 100644 --- a/modules/konduitAnalyticsAdapter.js +++ b/modules/konduitAnalyticsAdapter.js @@ -4,7 +4,7 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import { targeting } from '../src/targeting.js'; import { config } from '../src/config.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; const TRACKER_HOST = 'tracker.konduit.me'; const KONDUIT_PREBID_MODULE_VERSION = '1.0.0'; @@ -12,13 +12,13 @@ const KONDUIT_PREBID_MODULE_VERSION = '1.0.0'; const analyticsType = 'endpoint'; const eventDataComposerMap = { - [CONSTANTS.EVENTS.AUCTION_INIT]: obtainAuctionInfo, - [CONSTANTS.EVENTS.AUCTION_END]: obtainAuctionInfo, - [CONSTANTS.EVENTS.BID_REQUESTED]: obtainBidRequestsInfo, - [CONSTANTS.EVENTS.BID_TIMEOUT]: obtainBidTimeoutInfo, - [CONSTANTS.EVENTS.BID_RESPONSE]: obtainBidResponseInfo, - [CONSTANTS.EVENTS.BID_WON]: obtainWinnerBidInfo, - [CONSTANTS.EVENTS.NO_BID]: obtainNoBidInfo, + [EVENTS.AUCTION_INIT]: obtainAuctionInfo, + [EVENTS.AUCTION_END]: obtainAuctionInfo, + [EVENTS.BID_REQUESTED]: obtainBidRequestsInfo, + [EVENTS.BID_TIMEOUT]: obtainBidTimeoutInfo, + [EVENTS.BID_RESPONSE]: obtainBidResponseInfo, + [EVENTS.BID_WON]: obtainWinnerBidInfo, + [EVENTS.NO_BID]: obtainNoBidInfo, }; // This function is copy from prebid core @@ -43,7 +43,7 @@ function buildUrl(obj) { const getWinnerBidFromAggregatedEvents = () => { return konduitAnalyticsAdapter.context.aggregatedEvents - .filter(evt => evt.eventType === CONSTANTS.EVENTS.BID_WON)[0]; + .filter(evt => evt.eventType === EVENTS.BID_WON)[0]; }; const isWinnerBidDetected = () => { @@ -57,7 +57,7 @@ const konduitAnalyticsAdapter = Object.assign( adapter({ analyticsType }), { track ({ eventType, args }) { - if (CONSTANTS.EVENTS.AUCTION_INIT === eventType) { + if (EVENTS.AUCTION_INIT === eventType) { konduitAnalyticsAdapter.context.aggregatedEvents.splice(0); } @@ -68,12 +68,12 @@ const konduitAnalyticsAdapter = Object.assign( }); } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { if (!isWinnerBidDetected() && isWinnerBidExist()) { - const bidWonData = eventDataComposerMap[CONSTANTS.EVENTS.BID_WON](targeting.getWinningBids()[0]); + const bidWonData = eventDataComposerMap[EVENTS.BID_WON](targeting.getWinningBids()[0]); konduitAnalyticsAdapter.context.aggregatedEvents.push({ - eventType: CONSTANTS.EVENTS.BID_WON, + eventType: EVENTS.BID_WON, data: bidWonData, }); } diff --git a/modules/liveIntentAnalyticsAdapter.js b/modules/liveIntentAnalyticsAdapter.js index 54402bcafc6..04b9e333e8a 100644 --- a/modules/liveIntentAnalyticsAdapter.js +++ b/modules/liveIntentAnalyticsAdapter.js @@ -1,7 +1,7 @@ import {ajax} from '../src/ajax.js'; import { generateUUID, logInfo, logWarn } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { auctionManager } from '../src/auctionManager.js'; import { getRefererInfo } from '../src/refererDetection.js'; @@ -11,7 +11,7 @@ const URL = 'https://wba.liadm.com/analytic-events'; const GVL_ID = 148; const ADAPTER_CODE = 'liveintent'; const DEFAULT_BID_WON_TIMEOUT = 2000; -const { EVENTS: { AUCTION_END } } = CONSTANTS; +const { AUCTION_END } = EVENTS; let bidWonTimeout; function handleAuctionEnd(args) { diff --git a/modules/livewrappedAnalyticsAdapter.js b/modules/livewrappedAnalyticsAdapter.js index f3ee81cae7a..2797664e954 100644 --- a/modules/livewrappedAnalyticsAdapter.js +++ b/modules/livewrappedAnalyticsAdapter.js @@ -1,7 +1,7 @@ import { timestamp, logInfo, getWindowTop } from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, STATUS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { getGlobal } from '../src/prebidGlobal.js'; @@ -28,11 +28,11 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE logInfo('LIVEWRAPPED_EVENT:', [eventType, args]); switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: logInfo('LIVEWRAPPED_AUCTION_INIT:', args); cache.auctions[args.auctionId] = {bids: {}, bidAdUnits: {}}; break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: logInfo('LIVEWRAPPED_BID_REQUESTED:', args); cache.auctions[args.auctionId].timeStamp = args.start; @@ -73,11 +73,11 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE }); logInfo(livewrappedAnalyticsAdapter.requestEvents); break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: logInfo('LIVEWRAPPED_BID_RESPONSE:', args); let bidResponse = cache.auctions[args.auctionId].bids[args.requestId]; - bidResponse.isBid = args.getStatusCode() === CONSTANTS.STATUS.GOOD; + bidResponse.isBid = args.getStatusCode() === STATUS.GOOD; bidResponse.width = args.width; bidResponse.height = args.height; bidResponse.cpm = args.cpm; @@ -101,7 +101,7 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE }; } break; - case CONSTANTS.EVENTS.BIDDER_DONE: + case EVENTS.BIDDER_DONE: logInfo('LIVEWRAPPED_BIDDER_DONE:', args); args.bids.forEach(doneBid => { let bid = cache.auctions[doneBid.auctionId].bids[doneBid.bidId || doneBid.requestId]; @@ -111,7 +111,7 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE bid.readyToSend = 1; }); break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: logInfo('LIVEWRAPPED_BID_WON:', args); let wonBid = cache.auctions[args.auctionId].bids[args.requestId]; wonBid.won = true; @@ -123,7 +123,7 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE livewrappedAnalyticsAdapter.sendEvents(); } break; - case CONSTANTS.EVENTS.AD_RENDER_FAILED: + case EVENTS.AD_RENDER_FAILED: logInfo('LIVEWRAPPED_AD_RENDER_FAILED:', args); let adRenderFailedBid = cache.auctions[args.bid.auctionId].bids[args.bid.requestId]; adRenderFailedBid.adRenderFailed = true; @@ -133,13 +133,13 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE livewrappedAnalyticsAdapter.sendEvents(); } break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: logInfo('LIVEWRAPPED_BID_TIMEOUT:', args); args.forEach(timeout => { cache.auctions[timeout.auctionId].bids[timeout.bidId].timeout = true; }); break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: logInfo('LIVEWRAPPED_AUCTION_END:', args); setTimeout(() => { livewrappedAnalyticsAdapter.sendEvents(); diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index 5cc45e3adbf..6d45d05cd5c 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -19,7 +19,7 @@ import { } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, REJECTION_REASON } from '../src/constants.js'; import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; import {getGlobal} from '../src/prebidGlobal.js'; @@ -50,19 +50,17 @@ let cookieless; let prebidGlobal = getGlobal(); const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_RESPONSE, - BIDDER_DONE, - BID_TIMEOUT, - BID_WON, - BILLABLE_EVENT, - SEAT_NON_BID, - BID_REJECTED - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_TIMEOUT, + BID_WON, + BILLABLE_EVENT, + SEAT_NON_BID, + BID_REJECTED +} = EVENTS; // The saved state of rubicon specific setConfig controls export let rubiConf; @@ -921,7 +919,7 @@ magniteAdapter.track = ({ eventType, args }) => { handleBidResponse(args, 'success'); break; case BID_REJECTED: - const bidStatus = args.rejectionReason === CONSTANTS.REJECTION_REASON.FLOOR_NOT_MET ? BID_REJECTED_IPF : 'rejected'; + const bidStatus = args.rejectionReason === REJECTION_REASON.FLOOR_NOT_MET ? BID_REJECTED_IPF : 'rejected'; handleBidResponse(args, bidStatus); break; case SEAT_NON_BID: diff --git a/modules/malltvAnalyticsAdapter.js b/modules/malltvAnalyticsAdapter.js index af903795e49..b4fad0976fb 100644 --- a/modules/malltvAnalyticsAdapter.js +++ b/modules/malltvAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {ajax} from '../src/ajax.js' import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js' -import CONSTANTS from '../src/constants.json' +import { EVENTS } from '../src/constants.js' import adapterManager from '../src/adapterManager.js' import {getGlobal} from '../src/prebidGlobal.js' import {logInfo, logError, deepClone} from '../src/utils.js' @@ -10,11 +10,9 @@ export const ANALYTICS_VERSION = '1.0.0' export const DEFAULT_SERVER = 'https://central.mall.tv/analytics' const { - EVENTS: { - AUCTION_END, - BID_TIMEOUT - } -} = CONSTANTS + AUCTION_END, + BID_TIMEOUT +} = EVENTS export const BIDDER_STATUS = { BID: 1, diff --git a/modules/mediafilterRtdProvider.js b/modules/mediafilterRtdProvider.js index 8a082ad4d59..fae5c9e769b 100644 --- a/modules/mediafilterRtdProvider.js +++ b/modules/mediafilterRtdProvider.js @@ -14,7 +14,7 @@ import { submodule } from '../src/hook.js'; import { logError, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; /** The event type for Media Filter. */ export const MEDIAFILTER_EVENT_TYPE = 'com.mediatrust.pbjs.'; @@ -65,7 +65,7 @@ export const MediaFilter = { generateEventHandler: function(configurationHash) { return (windowEvent) => { if (windowEvent.data.type === MEDIAFILTER_EVENT_TYPE.concat('.', configurationHash)) { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { + events.emit(EVENTS.BILLABLE_EVENT, { 'billingId': generateUUID(), 'configurationHash': configurationHash, 'type': 'impression', diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index b902727a730..68927cc6b13 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -12,7 +12,7 @@ import { } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { BID_STATUS, EVENTS, TARGETING_KEYS } from '../src/constants.js'; import {ajax} from '../src/ajax.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {AUCTION_COMPLETED, AUCTION_IN_PROGRESS, getPriceGranularity} from '../src/auction.js'; @@ -590,7 +590,7 @@ function bidResponseHandler(bid) { dfpbd = bid[priceGranularityKey] || cpm; } bidObj.dfpbd = dfpbd; - if (bid.status === CONSTANTS.BID_STATUS.BID_REJECTED) { + if (bid.status === BID_STATUS.BID_REJECTED) { bidObj.status = BID_FLOOR_REJECTED; } else { bidObj.status = BID_SUCCESS; @@ -660,12 +660,12 @@ function setTargetingHandler(params) { adunitObj.targeting = params[adunit]; auctionObj.setTargetingTime = Date.now(); let targetingObj = Object.keys(params[adunit]).reduce((result, key) => { - if (key.indexOf(CONSTANTS.TARGETING_KEYS.AD_ID) !== -1) { + if (key.indexOf(TARGETING_KEYS.AD_ID) !== -1) { result[key] = params[adunit][key] } return result; }, {}); - const winnerAdId = params[adunit][CONSTANTS.TARGETING_KEYS.AD_ID]; + const winnerAdId = params[adunit][TARGETING_KEYS.AD_ID]; let winningBid; let bidAdIds = Object.keys(targetingObj).map(k => targetingObj[k]); auctionObj.bidWrapper.bidObjs.filter((bid) => bidAdIds.indexOf(bid.adId) !== -1).map(function(bid) { @@ -845,35 +845,35 @@ let medianetAnalytics = Object.assign(adapter({URL, analyticsType}), { logInfo(eventType, args); } switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { auctionInitHandler(args); break; } - case CONSTANTS.EVENTS.BID_REQUESTED: { + case EVENTS.BID_REQUESTED: { bidRequestedHandler(args); break; } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { bidResponseHandler(args); break; } - case CONSTANTS.EVENTS.BID_TIMEOUT: { + case EVENTS.BID_TIMEOUT: { bidTimeoutHandler(args); break; } - case CONSTANTS.EVENTS.NO_BID: { + case EVENTS.NO_BID: { noBidResponseHandler(args); break; } - case CONSTANTS.EVENTS.AUCTION_END: { + case EVENTS.AUCTION_END: { auctionEndHandler(args); break; } - case CONSTANTS.EVENTS.SET_TARGETING : { + case EVENTS.SET_TARGETING: { setTargetingHandler(args); break; } - case CONSTANTS.EVENTS.BID_WON: { + case EVENTS.BID_WON: { bidWonHandler(args); break; } diff --git a/modules/multibid/index.js b/modules/multibid/index.js index 27b88d47cf7..d0ce2ae159e 100644 --- a/modules/multibid/index.js +++ b/modules/multibid/index.js @@ -9,7 +9,7 @@ import { logWarn, deepAccess, getUniqueIdentifierStr, deepSetValue, groupBy } from '../../src/utils.js'; import * as events from '../../src/events.js'; -import CONSTANTS from '../../src/constants.json'; +import { EVENTS } from '../../src/constants.js'; import {addBidderRequests} from '../../src/auction.js'; import {getHighestCpmBidsFromBidPool, sortByDealAndPriceBucketOrCpm} from '../../src/targeting.js'; import {PBS, registerOrtbProcessor, REQUEST} from '../../src/pbjsORTB.js'; @@ -230,7 +230,7 @@ export const resetMultibidUnits = () => multibidUnits = {}; */ function init() { // TODO: does this reset logic make sense - what about simultaneous auctions? - events.on(CONSTANTS.EVENTS.AUCTION_INIT, resetMultibidUnits); + events.on(EVENTS.AUCTION_INIT, resetMultibidUnits); setupBeforeHookFnOnce(addBidderRequests, adjustBidderRequestsHook); getHook('addBidResponse').before(addBidResponseHook, 3); setupBeforeHookFnOnce(getHighestCpmBidsFromBidPool, targetBidPoolHook); diff --git a/modules/neuwoRtdProvider.js b/modules/neuwoRtdProvider.js index 7c594e2a1c3..a2c2249285b 100644 --- a/modules/neuwoRtdProvider.js +++ b/modules/neuwoRtdProvider.js @@ -3,7 +3,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; import { ajax } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; export const DATA_PROVIDER = 'neuwo.ai'; const SEGTAX_IAB = 6 // IAB - Content Taxonomy version 2 @@ -42,7 +42,7 @@ export function getBidRequestData(reqBidsConfigObj, callback, config, userConsen try { const jsonContent = JSON.parse(responseContent); if (jsonContent.marketing_categories) { - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, { type: 'request', billingId, vendor: neuwoRtdModule.name }) + events.emit(EVENTS.BILLABLE_EVENT, { type: 'request', billingId, vendor: neuwoRtdModule.name }) } injectTopics(jsonContent, reqBidsConfigObj, billingId) } catch (ex) { diff --git a/modules/nextMillenniumBidAdapter.js b/modules/nextMillenniumBidAdapter.js index de91b508125..65f530d9e58 100644 --- a/modules/nextMillenniumBidAdapter.js +++ b/modules/nextMillenniumBidAdapter.js @@ -14,7 +14,7 @@ import { } from '../src/utils.js'; import {getGlobal} from '../src/prebidGlobal.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; @@ -139,7 +139,7 @@ export const spec = { auctionId, }); - this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_REQUESTED, bid); + this.getUrlPixelMetric(EVENTS.BID_REQUESTED, bid); }); return requests; @@ -183,7 +183,7 @@ export const spec = { bidResponses.push(bidResponse); - this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_RESPONSE, bid); + this.getUrlPixelMetric(EVENTS.BID_RESPONSE, bid); }); }); @@ -263,7 +263,7 @@ export const spec = { onTimeout(bids) { for (const bid of bids) { - this.getUrlPixelMetric(CONSTANTS.EVENTS.BID_TIMEOUT, bid); + this.getUrlPixelMetric(EVENTS.BID_TIMEOUT, bid); }; }, }; diff --git a/modules/nobidAnalyticsAdapter.js b/modules/nobidAnalyticsAdapter.js index 3a272c3f796..5ae77f0cdc8 100644 --- a/modules/nobidAnalyticsAdapter.js +++ b/modules/nobidAnalyticsAdapter.js @@ -2,7 +2,7 @@ import {deepClone, logError, getParameterByName} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import {getStorageManager} from '../src/storageManager.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; @@ -17,16 +17,14 @@ const url = 'localhost:8383/event'; const GVLID = 816; const storage = getStorageManager({gvlid: GVLID, moduleName: MODULE_NAME, moduleType: MODULE_TYPE_ANALYTICS}); const { - EVENTS: { - AUCTION_INIT, - BID_REQUESTED, - BID_TIMEOUT, - BID_RESPONSE, - BID_WON, - AUCTION_END, - AD_RENDER_SUCCEEDED - } -} = CONSTANTS; + AUCTION_INIT, + BID_REQUESTED, + BID_TIMEOUT, + BID_RESPONSE, + BID_WON, + AUCTION_END, + AD_RENDER_SUCCEEDED +} = EVENTS; function log (msg) { // eslint-disable-next-line no-console console.log(`%cNoBid Analytics ${VERSION}`, 'padding: 2px 8px 2px 8px; background-color:#f50057; color: white', msg); diff --git a/modules/ooloAnalyticsAdapter.js b/modules/ooloAnalyticsAdapter.js index 9bc140f0536..8a6ef88a7fb 100644 --- a/modules/ooloAnalyticsAdapter.js +++ b/modules/ooloAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { _each, deepClone, pick, deepSetValue, logError, logInfo } from '../src/ import { getOrigin } from '../libraries/getOrigin/index.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js' import adapterManager from '../src/adapterManager.js' -import CONSTANTS from '../src/constants.json' +import { EVENTS } from '../src/constants.js' import { ajax } from '../src/ajax.js' import { config } from '../src/config.js' @@ -33,7 +33,7 @@ const { BID_WON, BID_TIMEOUT, AD_RENDER_FAILED -} = CONSTANTS.EVENTS +} = EVENTS const SERVER_EVENTS = { AUCTION: 'auction', diff --git a/modules/oxxionAnalyticsAdapter.js b/modules/oxxionAnalyticsAdapter.js index 25732d440ff..b3bc2d3479f 100644 --- a/modules/oxxionAnalyticsAdapter.js +++ b/modules/oxxionAnalyticsAdapter.js @@ -1,6 +1,6 @@ import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import { ajax } from '../src/ajax.js'; import { getRefererInfo } from '../src/refererDetection.js'; @@ -8,14 +8,12 @@ const analyticsType = 'endpoint'; const url = 'URL_TO_SERVER_ENDPOINT'; const { - EVENTS: { - AUCTION_END, - BID_WON, - BID_RESPONSE, - BID_REQUESTED, - BID_TIMEOUT, - } -} = CONSTANTS; + AUCTION_END, + BID_WON, + BID_RESPONSE, + BID_REQUESTED, + BID_TIMEOUT, +} = EVENTS; let saveEvents = {} let allEvents = {} diff --git a/modules/paapi.js b/modules/paapi.js index 720935bd3f5..5c76b2fb327 100644 --- a/modules/paapi.js +++ b/modules/paapi.js @@ -6,7 +6,7 @@ import {getHook, module} from '../src/hook.js'; import {deepSetValue, logInfo, logWarn, mergeDeep} from '../src/utils.js'; import {IMP, PBS, registerOrtbProcessor, RESPONSE} from '../src/pbjsORTB.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import {EVENTS} from '../src/constants.js'; import {currencyCompare} from '../libraries/currencyUtils/currency.js'; import {maximum, minimum} from '../src/utils/reducers.js'; import {auctionManager} from '../src/auctionManager.js'; @@ -67,7 +67,7 @@ export function init(cfg, configNamespace) { getHook('addComponentAuction').before(addComponentAuctionHook); getHook('makeBidRequests').after(markForFledge); -events.on(CONSTANTS.EVENTS.AUCTION_END, onAuctionEnd); +events.on(EVENTS.AUCTION_END, onAuctionEnd); function getSlotSignals(bidsReceived = [], bidRequests = []) { let bidfloor, bidfloorcur; diff --git a/modules/pirIdSystem.js b/modules/pirIdSystem.js index b891e1d362a..233176028d3 100644 --- a/modules/pirIdSystem.js +++ b/modules/pirIdSystem.js @@ -44,7 +44,7 @@ export const pirIdSubmodule = { * performs action to obtain id and return a value * @function * @returns {(IdResponse|undefined)} - */ + */ getId() { const pirIdToken = readId(); diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 6e4aec8ad92..037119d44a2 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -16,7 +16,7 @@ import { triggerPixel, uniques, } from '../../src/utils.js'; -import CONSTANTS from '../../src/constants.json'; +import { EVENTS, REJECTION_REASON, S2S } from '../../src/constants.js'; import adapterManager, {s2sActivityParams} from '../../src/adapterManager.js'; import {config} from '../../src/config.js'; import {addComponentAuction, isValid} from '../../src/adapters/bidderFactory.js'; @@ -33,7 +33,7 @@ import {ACTIVITY_TRANSMIT_UFPD} from '../../src/activities/activities.js'; const getConfig = config.getConfig; -const TYPE = CONSTANTS.S2S.SRC; +const TYPE = S2S.SRC; let _syncCount = 0; let _s2sConfigs; @@ -467,10 +467,10 @@ export function PrebidServer() { processPBSRequest(s2sBidRequest, bidRequests, ajax, { onResponse: function (isValid, requestedBidders, response) { if (isValid) { - bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest)); + bidRequests.forEach(bidderRequest => events.emit(EVENTS.BIDDER_DONE, bidderRequest)); } if (shouldEmitNonbids(s2sBidRequest.s2sConfig, response)) { - events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, { + events.emit(EVENTS.SEAT_NON_BID, { seatnonbid: response.ext.seatnonbid, auctionId: bidRequests[0].auctionId, requestedBidders, @@ -483,7 +483,7 @@ export function PrebidServer() { }, onError(msg, error) { logError(`Prebid server call failed: '${msg}'`, error); - bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_ERROR, {error, bidderRequest})); + bidRequests.forEach(bidderRequest => events.emit(EVENTS.BIDDER_ERROR, { error, bidderRequest })); done(error.timedOut); }, onBid: function ({adUnit, bid}) { @@ -491,7 +491,7 @@ export function PrebidServer() { metrics.checkpoint('addBidResponse'); if ((bid.requestId == null || bid.requestBidder == null) && !s2sBidRequest.s2sConfig.allowUnknownBidderCodes) { logWarn(`PBS adapter received bid from unknown bidder (${bid.bidder}), but 's2sConfig.allowUnknownBidderCodes' is not set. Ignoring bid.`); - addBidResponse.reject(adUnit, bid, CONSTANTS.REJECTION_REASON.BIDDER_DISALLOWED); + addBidResponse.reject(adUnit, bid, REJECTION_REASON.BIDDER_DISALLOWED); } else { if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnit, bid))) { addBidResponse(adUnit, bid); @@ -499,7 +499,7 @@ export function PrebidServer() { addWurl(bid.auctionId, bid.adId, bid.pbsWurl); } } else { - addBidResponse.reject(adUnit, bid, CONSTANTS.REJECTION_REASON.INVALID); + addBidResponse.reject(adUnit, bid, REJECTION_REASON.INVALID); } } }, @@ -511,7 +511,7 @@ export function PrebidServer() { }; // Listen for bid won to call wurl - events.on(CONSTANTS.EVENTS.BID_WON, bidWonHandler); + events.on(EVENTS.BID_WON, bidWonHandler); return Object.assign(this, { callBids: baseAdapter.callBids, diff --git a/modules/prebidServerBidAdapter/ortbConverter.js b/modules/prebidServerBidAdapter/ortbConverter.js index 1dd1532f423..e0f038767c2 100644 --- a/modules/prebidServerBidAdapter/ortbConverter.js +++ b/modules/prebidServerBidAdapter/ortbConverter.js @@ -11,7 +11,7 @@ import { timestamp } from '../../src/utils.js'; import {config} from '../../src/config.js'; -import CONSTANTS from '../../src/constants.json'; +import { STATUS, S2S } from '../../src/constants.js'; import {createBid} from '../../src/bidfactory.js'; import {pbsExtensions} from '../../libraries/pbsExtensions/pbsExtensions.js'; import {setImpBidParams} from '../../libraries/pbsExtensions/processors/params.js'; @@ -114,8 +114,8 @@ const PBS_CONVERTER = ortbConverter({ // because core has special treatment for PBS adapter responses, we need some additional processing bidResponse.requestTimestamp = context.requestTimestamp; return { - bid: Object.assign(createBid(CONSTANTS.STATUS.GOOD, { - src: CONSTANTS.S2S.SRC, + bid: Object.assign(createBid(STATUS.GOOD, { + src: S2S.SRC, bidId: bidRequest ? (bidRequest.bidId || bidRequest.bid_Id) : null, transactionId: context.adUnit.transactionId, adUnitId: context.adUnit.adUnitId, diff --git a/modules/prebidmanagerAnalyticsAdapter.js b/modules/prebidmanagerAnalyticsAdapter.js index b877918d16d..858e30068db 100644 --- a/modules/prebidmanagerAnalyticsAdapter.js +++ b/modules/prebidmanagerAnalyticsAdapter.js @@ -3,7 +3,7 @@ import {ajaxBuilder} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; /** @@ -208,7 +208,7 @@ function handleEvent(eventType, eventArgs) { const pmEvent = {}; switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: { + case EVENTS.AUCTION_INIT: { pmEvent.auctionId = eventArgs.auctionId; pmEvent.timeout = eventArgs.timeout; pmEvent.eventType = eventArgs.eventType; @@ -218,7 +218,7 @@ function handleEvent(eventType, eventArgs) { _bidRequestTimeout = pmEvent.timeout; break; } - case CONSTANTS.EVENTS.AUCTION_END: { + case EVENTS.AUCTION_END: { pmEvent.auctionId = eventArgs.auctionId; pmEvent.end = eventArgs.end; pmEvent.start = eventArgs.start; @@ -228,15 +228,15 @@ function handleEvent(eventType, eventArgs) { pmEvent.end = Date.now(); break; } - case CONSTANTS.EVENTS.BID_ADJUSTMENT: { + case EVENTS.BID_ADJUSTMENT: { break; } - case CONSTANTS.EVENTS.BID_TIMEOUT: { + case EVENTS.BID_TIMEOUT: { pmEvent.bidders = eventArgs && eventArgs.map ? eventArgs.map(trimBid) : eventArgs; pmEvent.duration = _bidRequestTimeout; break; } - case CONSTANTS.EVENTS.BID_REQUESTED: { + case EVENTS.BID_REQUESTED: { pmEvent.auctionId = eventArgs.auctionId; pmEvent.bidderCode = eventArgs.bidderCode; pmEvent.doneCbCallCount = eventArgs.doneCbCallCount; @@ -247,7 +247,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.timeout = eventArgs.timeout; break; } - case CONSTANTS.EVENTS.BID_RESPONSE: { + case EVENTS.BID_RESPONSE: { pmEvent.bidderCode = eventArgs.bidderCode; pmEvent.width = eventArgs.width; pmEvent.height = eventArgs.height; @@ -266,7 +266,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.adserverTargeting = eventArgs.adserverTargeting; break; } - case CONSTANTS.EVENTS.BID_WON: { + case EVENTS.BID_WON: { pmEvent.auctionId = eventArgs.auctionId; pmEvent.adId = eventArgs.adId; pmEvent.adserverTargeting = eventArgs.adserverTargeting; @@ -284,7 +284,7 @@ function handleEvent(eventType, eventArgs) { pmEvent.bidder = eventArgs.bidder; break; } - case CONSTANTS.EVENTS.BIDDER_DONE: { + case EVENTS.BIDDER_DONE: { pmEvent.auctionId = eventArgs.auctionId; pmEvent.auctionStart = eventArgs.auctionStart; pmEvent.bidderCode = eventArgs.bidderCode; @@ -297,16 +297,16 @@ function handleEvent(eventType, eventArgs) { pmEvent.src = eventArgs.src; break; } - case CONSTANTS.EVENTS.SET_TARGETING: { + case EVENTS.SET_TARGETING: { break; } - case CONSTANTS.EVENTS.REQUEST_BIDS: { + case EVENTS.REQUEST_BIDS: { break; } - case CONSTANTS.EVENTS.ADD_AD_UNITS: { + case EVENTS.ADD_AD_UNITS: { break; } - case CONSTANTS.EVENTS.AD_RENDER_FAILED: { + case EVENTS.AD_RENDER_FAILED: { pmEvent.bid = eventArgs.bid; pmEvent.message = eventArgs.message; pmEvent.reason = eventArgs.reason; @@ -326,7 +326,7 @@ function sendEvent(event) { _eventQueue.push(event); logInfo(`${analyticsName} Event ${event.eventType}:`, event); - if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (event.eventType === EVENTS.AUCTION_END) { flush(); } } diff --git a/modules/priceFloors.js b/modules/priceFloors.js index 70a0f9b9a14..5df8f938c3d 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -19,7 +19,7 @@ import {getGlobal} from '../src/prebidGlobal.js'; import {config} from '../src/config.js'; import {ajaxBuilder} from '../src/ajax.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, REJECTION_REASON } from '../src/constants.js'; import {getHook} from '../src/hook.js'; import {find} from '../src/polyfill.js'; import {getRefererInfo} from '../src/refererDetection.js'; @@ -31,6 +31,11 @@ import {adjustCpm} from '../src/utils/cpm.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; import {convertCurrency} from '../libraries/currencyUtils/currency.js'; +export const FLOOR_SKIPPED_REASON = { + NOT_FOUND: 'not_found', + RANDOM: 'random' +}; + /** * @summary This Module is intended to provide users with the ability to dynamically set and enforce price floors on a per auction basis. */ @@ -412,13 +417,13 @@ export function createFloorsDataForAuction(adUnits, auctionId) { // if we still do not have a valid floor data then floors is not on for this auction, so skip if (Object.keys(deepAccess(resolvedFloorsData, 'data.values') || {}).length === 0) { resolvedFloorsData.skipped = true; - resolvedFloorsData.skippedReason = CONSTANTS.FLOOR_SKIPPED_REASON.NOT_FOUND + resolvedFloorsData.skippedReason = FLOOR_SKIPPED_REASON.NOT_FOUND } else { // determine the skip rate now const auctionSkipRate = getParameterByName('pbjs_skipRate') || (deepAccess(resolvedFloorsData, 'data.skipRate') ?? resolvedFloorsData.skipRate); const isSkipped = Math.random() * 100 < parseFloat(auctionSkipRate); resolvedFloorsData.skipped = isSkipped; - if (isSkipped) resolvedFloorsData.skippedReason = CONSTANTS.FLOOR_SKIPPED_REASON.RANDOM + if (isSkipped) resolvedFloorsData.skippedReason = FLOOR_SKIPPED_REASON.RANDOM } // copy FloorMin to floorData.data if (resolvedFloorsData.hasOwnProperty('floorMin')) resolvedFloorsData.data.floorMin = resolvedFloorsData.floorMin; @@ -701,7 +706,7 @@ export function handleSetFloorsConfig(config) { if (!addedFloorsHook) { // register hooks / listening events // when auction finishes remove it's associated floor data after 3 seconds so we stil have it for latent responses - events.on(CONSTANTS.EVENTS.AUCTION_END, (args) => { + events.on(EVENTS.AUCTION_END, (args) => { setTimeout(() => delete _floorDataForAuction[args.auctionId], 3000); }); @@ -802,7 +807,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a // now do the compare! if (shouldFloorBid(floorData, floorInfo, bid)) { // bid fails floor -> throw it out - reject(CONSTANTS.REJECTION_REASON.FLOOR_NOT_MET); + reject(REJECTION_REASON.FLOOR_NOT_MET); logWarn(`${MODULE_NAME}: ${bid.bidderCode}'s Bid Response for ${adUnitCode} was rejected due to floor not met (adjusted cpm: ${bid?.floorData?.cpmAfterAdjustments}, floor: ${floorInfo?.matchingFloor})`, bid); return; } diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js index ced47086f7b..753b706e363 100755 --- a/modules/pubmaticAnalyticsAdapter.js +++ b/modules/pubmaticAnalyticsAdapter.js @@ -1,12 +1,22 @@ import {_each, isArray, isStr, logError, logWarn, pick, generateUUID} from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { BID_STATUS, EVENTS, STATUS, REJECTION_REASON } from '../src/constants.js'; import {ajax} from '../src/ajax.js'; import {config} from '../src/config.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; +const FLOOR_VALUES = { + NO_DATA: 'noData', + AD_UNIT: 'adUnit', + SET_CONFIG: 'setConfig', + FETCH: 'fetch', + SUCCESS: 'success', + ERROR: 'error', + TIMEOUT: 'timeout' +}; + /// /////////// CONSTANTS ////////////// const ADAPTER_CODE = 'pubmatic'; const VENDOR_OPENWRAP = 'openwrap'; @@ -109,7 +119,7 @@ function copyRequiredBidDetails(bid) { function setBidStatus(bid, args) { switch (args.getStatusCode()) { - case CONSTANTS.STATUS.GOOD: + case STATUS.GOOD: bid.status = SUCCESS; delete bid.error; // it's possible for this to be set by a previous timeout break; @@ -346,9 +356,9 @@ function getFloorFetchStatus(floorData) { return false; } const { location, fetchStatus } = floorData?.floorRequestData; - const isDataValid = location !== CONSTANTS.FLOOR_VALUES.NO_DATA; - const isFetchSuccessful = location === CONSTANTS.FLOOR_VALUES.FETCH && fetchStatus === CONSTANTS.FLOOR_VALUES.SUCCESS; - const isAdUnitOrSetConfig = location === CONSTANTS.FLOOR_VALUES.AD_UNIT || location === CONSTANTS.FLOOR_VALUES.SET_CONFIG; + const isDataValid = location !== FLOOR_VALUES.NO_DATA; + const isFetchSuccessful = location === FLOOR_VALUES.FETCH && fetchStatus === FLOOR_VALUES.SUCCESS; + const isAdUnitOrSetConfig = location === FLOOR_VALUES.AD_UNIT || location === FLOOR_VALUES.SET_CONFIG; return isDataValid && (isAdUnitOrSetConfig || isFetchSuccessful); } @@ -404,16 +414,16 @@ function executeBidsLoggerCall(e, highestCpmBids) { if (floorData?.floorRequestData) { const { location, fetchStatus, floorProvider } = floorData?.floorRequestData; slotObject.ffs = { - [CONSTANTS.FLOOR_VALUES.SUCCESS]: 1, - [CONSTANTS.FLOOR_VALUES.ERROR]: 2, - [CONSTANTS.FLOOR_VALUES.TIMEOUT]: 4, + [FLOOR_VALUES.SUCCESS]: 1, + [FLOOR_VALUES.ERROR]: 2, + [FLOOR_VALUES.TIMEOUT]: 4, undefined: 0 }[fetchStatus]; slotObject.fsrc = { - [CONSTANTS.FLOOR_VALUES.FETCH]: 2, - [CONSTANTS.FLOOR_VALUES.NO_DATA]: 2, - [CONSTANTS.FLOOR_VALUES.AD_UNIT]: 1, - [CONSTANTS.FLOOR_VALUES.SET_CONFIG]: 1 + [FLOOR_VALUES.FETCH]: 2, + [FLOOR_VALUES.NO_DATA]: 2, + [FLOOR_VALUES.AD_UNIT]: 1, + [FLOOR_VALUES.SET_CONFIG]: 1 }[location]; slotObject.fp = floorProvider; } @@ -578,9 +588,9 @@ function bidResponseHandler(args) { function bidRejectedHandler(args) { // If bid is rejected due to floors value did not met // make cpm as 0, status as bidRejected and forward the bid for logging - if (args.rejectionReason === CONSTANTS.REJECTION_REASON.FLOOR_NOT_MET) { + if (args.rejectionReason === REJECTION_REASON.FLOOR_NOT_MET) { args.cpm = 0; - args.status = CONSTANTS.BID_STATUS.BID_REJECTED; + args.status = BID_STATUS.BID_REJECTED; bidResponseHandler(args); } } @@ -674,28 +684,28 @@ let pubmaticAdapter = Object.assign({}, baseAdapter, { track({eventType, args}) { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: auctionInitHandler(args); break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: bidRequestedHandler(args); break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: bidResponseHandler(args); break; - case CONSTANTS.EVENTS.BID_REJECTED: + case EVENTS.BID_REJECTED: bidRejectedHandler(args) break; - case CONSTANTS.EVENTS.BIDDER_DONE: + case EVENTS.BIDDER_DONE: bidderDoneHandler(args); break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: bidWonHandler(args); break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: auctionEndHandler(args); break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: bidTimeoutHandler(args); break; } diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 846c59c1ae5..a428ba9fa6e 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -4,7 +4,7 @@ import { BANNER, VIDEO, NATIVE, ADPOD } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { bidderSettings } from '../src/bidderSettings.js'; -import CONSTANTS from '../src/constants.json'; +import { NATIVE_IMAGE_TYPES, NATIVE_KEYS_THAT_ARE_NOT_ASSETS, NATIVE_KEYS, NATIVE_ASSET_TYPES } from '../src/constants.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -331,7 +331,6 @@ const PREBID_NATIVE_DATA_KEYS_TO_ORTB = { 'displayurl': 'displayurl' }; -const { NATIVE_IMAGE_TYPES, NATIVE_KEYS_THAT_ARE_NOT_ASSETS, NATIVE_KEYS, NATIVE_ASSET_TYPES } = CONSTANTS; const PREBID_NATIVE_DATA_KEY_VALUES = Object.values(PREBID_NATIVE_DATA_KEYS_TO_ORTB); // TODO remove this function when the support for 1.1 is removed diff --git a/modules/pubwiseAnalyticsAdapter.js b/modules/pubwiseAnalyticsAdapter.js index 6aed462f2d5..00d8e3ccb6a 100644 --- a/modules/pubwiseAnalyticsAdapter.js +++ b/modules/pubwiseAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { getParameterByName, logInfo, generateUUID, debugTurnedOn } from '../src import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getStorageManager} from '../src/storageManager.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; const MODULE_CODE = 'pubwise'; @@ -176,13 +176,13 @@ function flushEvents() { function isIngestedEvent(eventType) { const ingested = [ - CONSTANTS.EVENTS.AUCTION_INIT, - CONSTANTS.EVENTS.BID_REQUESTED, - CONSTANTS.EVENTS.BID_RESPONSE, - CONSTANTS.EVENTS.BID_WON, - CONSTANTS.EVENTS.BID_TIMEOUT, - CONSTANTS.EVENTS.AD_RENDER_FAILED, - CONSTANTS.EVENTS.TCF2_ENFORCEMENT + EVENTS.AUCTION_INIT, + EVENTS.BID_REQUESTED, + EVENTS.BID_RESPONSE, + EVENTS.BID_WON, + EVENTS.BID_TIMEOUT, + EVENTS.AD_RENDER_FAILED, + EVENTS.TCF2_ENFORCEMENT ]; return ingested.indexOf(eventType) !== -1; } @@ -278,9 +278,9 @@ pubwiseAnalytics.handleEvent = function(eventType, data) { metaData = enrichWithCustomSegments(metaData); // add data on init to the metadata container - if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) { + if (eventType === EVENTS.AUCTION_INIT) { data = filterAuctionInit(data); - } else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) { + } else if (eventType === EVENTS.BID_RESPONSE) { data = filterBidResponse(data); } @@ -294,7 +294,7 @@ pubwiseAnalytics.handleEvent = function(eventType, data) { } // once the auction ends, or the event is a bid won send events - if (eventType === CONSTANTS.EVENTS.AUCTION_END || eventType === CONSTANTS.EVENTS.BID_WON) { + if (eventType === EVENTS.AUCTION_END || eventType === EVENTS.BID_WON) { flushEvents(); } }; diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index e97e5505768..d4a7ec70a70 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { deepAccess, parseSizesInput, getWindowLocation, buildUrl } from '../src import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; @@ -38,9 +38,9 @@ var pubxaiAnalyticsAdapter = Object.assign(adapter( }), { track({ eventType, args }) { if (typeof args !== 'undefined') { - if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT) { + if (eventType === EVENTS.BID_TIMEOUT) { args.forEach(item => { mapBidResponse(item, 'timeout'); }); - } else if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) { + } else if (eventType === EVENTS.AUCTION_INIT) { events.auctionInit = args; events.floorDetail = {}; events.bids = []; @@ -49,15 +49,15 @@ var pubxaiAnalyticsAdapter = Object.assign(adapter( Object.assign(events.floorDetail, floorData); } auctionTimestamp = args.timestamp; - } else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) { + } else if (eventType === EVENTS.BID_RESPONSE) { mapBidResponse(args, 'response'); - } else if (eventType === CONSTANTS.EVENTS.BID_WON) { + } else if (eventType === EVENTS.BID_WON) { send({ winningBid: mapBidResponse(args, 'bidwon') }, 'bidwon'); } } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { send(events, 'auctionEnd'); } } diff --git a/modules/qortexRtdProvider.js b/modules/qortexRtdProvider.js index 7aa30334756..88b4339b38e 100644 --- a/modules/qortexRtdProvider.js +++ b/modules/qortexRtdProvider.js @@ -3,7 +3,7 @@ import { ajax } from '../src/ajax.js'; import { logWarn, mergeDeep, logMessage, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; let requestUrl; let bidderArray; @@ -128,7 +128,7 @@ export function loadScriptTag(config) { logMessage('received billable event: qx-impression') impressionIds.add(uid) billableEvent.transactionId = e.detail.uid; - events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, billableEvent); + events.emit(EVENTS.BILLABLE_EVENT, billableEvent); break; } default: diff --git a/modules/roxotAnalyticsAdapter.js b/modules/roxotAnalyticsAdapter.js index 2c3be3e1757..8e5371044a2 100644 --- a/modules/roxotAnalyticsAdapter.js +++ b/modules/roxotAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {deepClone, getParameterByName, logError, logInfo} from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {includes} from '../src/polyfill.js'; import {ajaxBuilder} from '../src/ajax.js'; @@ -18,15 +18,13 @@ const DEFAULT_SERVER_CONFIG_URL = 'pa.rxthdr.com/v3'; const analyticsType = 'endpoint'; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_ADJUSTMENT, - BIDDER_DONE, - BID_WON - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_ADJUSTMENT, + BIDDER_DONE, + BID_WON +} = EVENTS; const AUCTION_STATUS = { 'RUNNING': 'running', diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index c5308c91e18..0c654fc28b0 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -163,7 +163,7 @@ import {config} from '../../src/config.js'; import {getHook, module} from '../../src/hook.js'; import {logError, logInfo, logWarn} from '../../src/utils.js'; import * as events from '../../src/events.js'; -import CONSTANTS from '../../src/constants.json'; +import { EVENTS, JSON_MAPPING } from '../../src/constants.js'; import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../../src/adapterManager.js'; import {find} from '../../src/polyfill.js'; import {timedAuctionHook} from '../../src/utils/perfMetrics.js'; @@ -213,11 +213,11 @@ const setEventsListeners = (function () { return function setEventsListeners() { if (!registered) { Object.entries({ - [CONSTANTS.EVENTS.AUCTION_INIT]: ['onAuctionInitEvent'], - [CONSTANTS.EVENTS.AUCTION_END]: ['onAuctionEndEvent', getAdUnitTargeting], - [CONSTANTS.EVENTS.BID_RESPONSE]: ['onBidResponseEvent'], - [CONSTANTS.EVENTS.BID_REQUESTED]: ['onBidRequestEvent'], - [CONSTANTS.EVENTS.BID_ACCEPTED]: ['onBidAcceptedEvent'] + [EVENTS.AUCTION_INIT]: ['onAuctionInitEvent'], + [EVENTS.AUCTION_END]: ['onAuctionEndEvent', getAdUnitTargeting], + [EVENTS.BID_RESPONSE]: ['onBidResponseEvent'], + [EVENTS.BID_REQUESTED]: ['onBidRequestEvent'], + [EVENTS.BID_ACCEPTED]: ['onBidAcceptedEvent'] }).forEach(([ev, [handler, preprocess]]) => { events.on(ev, (args) => { preprocess && preprocess(args); @@ -380,7 +380,7 @@ export function getAdUnitTargeting(auction) { return } logInfo('RTD set ad unit targeting of', kv, 'for', adUnit); - adUnit[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = Object.assign(adUnit[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] || {}, kv); + adUnit[JSON_MAPPING.ADSERVER_TARGETING] = Object.assign(adUnit[JSON_MAPPING.ADSERVER_TARGETING] || {}, kv); }); return auction.adUnits; } diff --git a/modules/scaleableAnalyticsAdapter.js b/modules/scaleableAnalyticsAdapter.js index 46f9d45d84d..054ccb7db55 100644 --- a/modules/scaleableAnalyticsAdapter.js +++ b/modules/scaleableAnalyticsAdapter.js @@ -1,7 +1,7 @@ /* COPYRIGHT SCALEABLE LLC 2019 */ import { ajax } from '../src/ajax.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import { logMessage } from '../src/utils.js'; @@ -16,10 +16,10 @@ const entries = Object.entries || function(obj) { return resArray; }; -const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; -const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; -const BID_WON = CONSTANTS.EVENTS.BID_WON; -const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; +const BID_TIMEOUT = EVENTS.BID_TIMEOUT; +const AUCTION_INIT = EVENTS.AUCTION_INIT; +const BID_WON = EVENTS.BID_WON; +const AUCTION_END = EVENTS.AUCTION_END; const URL = 'https://auction.scaleable.ai/'; const ANALYTICS_TYPE = 'endpoint'; diff --git a/modules/sigmoidAnalyticsAdapter.js b/modules/sigmoidAnalyticsAdapter.js index 18e1e20e3e3..a9d92b67e24 100644 --- a/modules/sigmoidAnalyticsAdapter.js +++ b/modules/sigmoidAnalyticsAdapter.js @@ -2,7 +2,7 @@ Updated : 2018-03-28 */ import {includes} from '../src/polyfill.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {getStorageManager} from '../src/storageManager.js'; import {generateUUID, logError, logInfo} from '../src/utils.js'; @@ -14,12 +14,12 @@ const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName const url = 'https://kinesis.us-east-1.amazonaws.com/'; const analyticsType = 'endpoint'; -const auctionInitConst = CONSTANTS.EVENTS.AUCTION_INIT; -const auctionEndConst = CONSTANTS.EVENTS.AUCTION_END; -const bidWonConst = CONSTANTS.EVENTS.BID_WON; -const bidRequestConst = CONSTANTS.EVENTS.BID_REQUESTED; -const bidAdjustmentConst = CONSTANTS.EVENTS.BID_ADJUSTMENT; -const bidResponseConst = CONSTANTS.EVENTS.BID_RESPONSE; +const auctionInitConst = EVENTS.AUCTION_INIT; +const auctionEndConst = EVENTS.AUCTION_END; +const bidWonConst = EVENTS.BID_WON; +const bidRequestConst = EVENTS.BID_REQUESTED; +const bidAdjustmentConst = EVENTS.BID_ADJUSTMENT; +const bidResponseConst = EVENTS.BID_RESPONSE; let initOptions = { publisherIds: [], utmTagData: [], adUnits: [] }; let bidWon = {options: {}, events: []}; diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index ac0422842d5..64d8765dc04 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -3,7 +3,7 @@ import {find} from '../src/polyfill.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import CONSTANTS from '../src/constants.json'; +import { NATIVE_IMAGE_TYPES } from '../src/constants.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; import {fill} from '../libraries/appnexusUtils/anUtils.js'; import {chunk} from '../libraries/chunk/chunk.js'; @@ -16,7 +16,6 @@ import {chunk} from '../libraries/chunk/chunk.js'; * @typedef {import('../src/adapters/bidderFactory.js').UserSync} UserSync */ -const { NATIVE_IMAGE_TYPES } = CONSTANTS; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.8' diff --git a/modules/sonobiAnalyticsAdapter.js b/modules/sonobiAnalyticsAdapter.js index 04a855b5be6..8242df7e0c5 100644 --- a/modules/sonobiAnalyticsAdapter.js +++ b/modules/sonobiAnalyticsAdapter.js @@ -1,6 +1,6 @@ import { deepClone, logInfo, logError } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {ajaxBuilder} from '../src/ajax.js'; @@ -10,17 +10,15 @@ export const DEFAULT_EVENT_URL = 'apex.go.sonobi.com/keymaker'; const analyticsType = 'endpoint'; const QUEUE_TIMEOUT_DEFAULT = 200; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_ADJUSTMENT, - BIDDER_DONE, - BID_WON, - BID_RESPONSE, - BID_TIMEOUT - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_ADJUSTMENT, + BIDDER_DONE, + BID_WON, + BID_RESPONSE, + BID_TIMEOUT +} = EVENTS; let initOptions = {}; let auctionCache = {}; diff --git a/modules/sovrnAnalyticsAdapter.js b/modules/sovrnAnalyticsAdapter.js index a72c4b1a5a5..a89b365e074 100644 --- a/modules/sovrnAnalyticsAdapter.js +++ b/modules/sovrnAnalyticsAdapter.js @@ -1,7 +1,7 @@ import {logError, timestamp} from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adaptermanager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {ajaxBuilder} from '../src/ajax.js'; import {config} from '../src/config.js'; import {find, includes} from '../src/polyfill.js'; @@ -10,14 +10,12 @@ import {getRefererInfo} from '../src/refererDetection.js'; const ajax = ajaxBuilder(0) const { - EVENTS: { - AUCTION_END, - BID_REQUESTED, - BID_ADJUSTMENT, - BID_RESPONSE, - BID_WON - } -} = CONSTANTS + AUCTION_END, + BID_REQUESTED, + BID_ADJUSTMENT, + BID_RESPONSE, + BID_WON +} = EVENTS; let pbaUrl = 'https://pba.aws.lijit.com/analytics' let currentAuctions = {}; diff --git a/modules/staqAnalyticsAdapter.js b/modules/staqAnalyticsAdapter.js index c1aaa727af5..ac5e86db19d 100644 --- a/modules/staqAnalyticsAdapter.js +++ b/modules/staqAnalyticsAdapter.js @@ -1,6 +1,6 @@ import { logInfo, logError, parseUrl, _each } from '../src/utils.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { ajax } from '../src/ajax.js'; @@ -55,25 +55,25 @@ let analyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoint' }), { } let handler = null; switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: if (analyticsAdapter.context.queue) { analyticsAdapter.context.queue.init(); } handler = trackAuctionInit; break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: handler = trackBidRequest; break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: handler = trackBidResponse; break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: handler = trackBidWon; break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: handler = trackBidTimeout; break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: handler = trackAuctionEnd; break; } @@ -81,11 +81,11 @@ let analyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoint' }), { let events = handler(args); if (analyticsAdapter.context.queue) { analyticsAdapter.context.queue.push(events); - if (eventType === CONSTANTS.EVENTS.BID_WON) { + if (eventType === EVENTS.BID_WON) { analyticsAdapter.context.queue.updateWithWins(events); } } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { sendAll(); } } diff --git a/modules/terceptAnalyticsAdapter.js b/modules/terceptAnalyticsAdapter.js index c17948d73d0..089f8d917d6 100644 --- a/modules/terceptAnalyticsAdapter.js +++ b/modules/terceptAnalyticsAdapter.js @@ -2,7 +2,7 @@ import { parseSizesInput, getWindowLocation, buildUrl } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import {getGlobal} from '../src/prebidGlobal.js'; const emptyUrl = ''; @@ -24,23 +24,23 @@ var terceptAnalyticsAdapter = Object.assign(adapter( }), { track({ eventType, args }) { if (typeof args !== 'undefined') { - if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT) { + if (eventType === EVENTS.BID_TIMEOUT) { args.forEach(item => { mapBidResponse(item, 'timeout'); }); - } else if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) { + } else if (eventType === EVENTS.AUCTION_INIT) { events.auctionInit = args; auctionTimestamp = args.timestamp; - } else if (eventType === CONSTANTS.EVENTS.BID_REQUESTED) { + } else if (eventType === EVENTS.BID_REQUESTED) { mapBidRequests(args).forEach(item => { events.bids.push(item) }); - } else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) { + } else if (eventType === EVENTS.BID_RESPONSE) { mapBidResponse(args, 'response'); - } else if (eventType === CONSTANTS.EVENTS.BID_WON) { + } else if (eventType === EVENTS.BID_WON) { send({ bidWon: mapBidResponse(args, 'win') }, 'won'); } } - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + if (eventType === EVENTS.AUCTION_END) { send(events, 'auctionEnd'); } } diff --git a/modules/ucfunnelAnalyticsAdapter.js b/modules/ucfunnelAnalyticsAdapter.js index 77fffddbaae..3b4053d3626 100644 --- a/modules/ucfunnelAnalyticsAdapter.js +++ b/modules/ucfunnelAnalyticsAdapter.js @@ -1,6 +1,6 @@ import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {logError, logInfo, deepClone} from '../src/utils.js'; @@ -12,12 +12,10 @@ export const ANALYTICS_VERSION = '1.0.0'; const ANALYTICS_SERVER = 'https://hbwa.aralego.com'; const { - EVENTS: { - AUCTION_END, - BID_WON, - BID_TIMEOUT - } -} = CONSTANTS; + AUCTION_END, + BID_WON, + BID_TIMEOUT +} = EVENTS; export const BIDDER_STATUS = { BID: 'bid', diff --git a/modules/userId/index.js b/modules/userId/index.js index 0e1df12e1db..90d377a816e 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -131,7 +131,7 @@ import {config} from '../../src/config.js'; import * as events from '../../src/events.js'; import {getGlobal} from '../../src/prebidGlobal.js'; import adapterManager, {gdprDataHandler} from '../../src/adapterManager.js'; -import CONSTANTS from '../../src/constants.json'; +import { EVENTS } from '../../src/constants.js'; import {module, ready as hooksReady} from '../../src/hook.js'; import {buildEidPermissions, createEidsArray, EID_CONFIG} from './eids.js'; import { @@ -538,8 +538,8 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) { if (auctionDelay > 0) { startCallbacks.resolve(); } else { - events.on(CONSTANTS.EVENTS.AUCTION_END, function auctionEndHandler() { - events.off(CONSTANTS.EVENTS.AUCTION_END, auctionEndHandler); + events.on(EVENTS.AUCTION_END, function auctionEndHandler() { + events.off(EVENTS.AUCTION_END, auctionEndHandler); delay(syncDelay).then(startCallbacks.resolve); }); } diff --git a/modules/videoModule/index.js b/modules/videoModule/index.js index 28f5c90d326..c84d98a6d5f 100644 --- a/modules/videoModule/index.js +++ b/modules/videoModule/index.js @@ -3,7 +3,7 @@ import { find } from '../../src/polyfill.js'; import * as events from '../../src/events.js'; import {mergeDeep, logWarn, logError} from '../../src/utils.js'; import { getGlobal } from '../../src/prebidGlobal.js'; -import CONSTANTS from '../../src/constants.json'; +import { EVENTS } from '../../src/constants.js'; import { videoEvents, AUCTION_AD_LOAD_ATTEMPT, @@ -71,7 +71,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent requestBids.before(beforeBidsRequested, 40); - pbEvents.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) { + pbEvents.on(EVENTS.BID_ADJUSTMENT, function (bid) { videoImpressionVerifier.trackBid(bid); }); @@ -107,7 +107,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent const bidsBackHandler = bidderRequest.bidsBackHandler; if (!bidsBackHandler || typeof bidsBackHandler !== 'function') { - pbEvents.on(CONSTANTS.EVENTS.AUCTION_END, auctionEnd); + pbEvents.on(EVENTS.AUCTION_END, auctionEnd); } return nextFn.call(this, bidderRequest); @@ -192,7 +192,7 @@ export function PbVideo(videoCore_, getConfig_, pbGlobal_, pbEvents_, videoEvent renderWinningBid(adUnit); } }); - pbEvents.off(CONSTANTS.EVENTS.AUCTION_END, auctionEnd); + pbEvents.off(EVENTS.AUCTION_END, auctionEnd); } function getAdServerConfig(adUnitVideoConfig) { diff --git a/modules/yandexAnalyticsAdapter.js b/modules/yandexAnalyticsAdapter.js index ba000db6162..5150d5d7dca 100644 --- a/modules/yandexAnalyticsAdapter.js +++ b/modules/yandexAnalyticsAdapter.js @@ -1,7 +1,7 @@ import buildAdapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import { logError, logInfo } from '../src/utils.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import * as events from '../src/events.js'; const timeoutIds = {}; @@ -32,7 +32,7 @@ const { BIDDER_DONE, AUCTION_END, BID_TIMEOUT, -} = CONSTANTS.EVENTS; +} = EVENTS; export const EVENTS_TO_TRACK = [ BID_REQUESTED, diff --git a/modules/yieldoneAnalyticsAdapter.js b/modules/yieldoneAnalyticsAdapter.js index 0663ecb3f76..23fa0e0eec9 100644 --- a/modules/yieldoneAnalyticsAdapter.js +++ b/modules/yieldoneAnalyticsAdapter.js @@ -1,7 +1,7 @@ import { isArray, deepClone } from '../src/utils.js'; import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import { targeting } from '../src/targeting.js'; import { auctionManager } from '../src/auctionManager.js'; @@ -14,9 +14,9 @@ const requestedBidders = {}; const requestedBids = {}; const referrers = {}; const ignoredEvents = {}; -ignoredEvents[CONSTANTS.EVENTS.BID_ADJUSTMENT] = true; -ignoredEvents[CONSTANTS.EVENTS.BIDDER_DONE] = true; -ignoredEvents[CONSTANTS.EVENTS.AUCTION_END] = true; +ignoredEvents[EVENTS.BID_ADJUSTMENT] = true; +ignoredEvents[EVENTS.BIDDER_DONE] = true; +ignoredEvents[EVENTS.AUCTION_END] = true; let currentAuctionId = ''; let url = defaultUrl; @@ -69,7 +69,7 @@ function addAdUnitName(params, map) { const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { getUrl() { return url; }, track({eventType, args = {}}) { - if (eventType === CONSTANTS.EVENTS.BID_REQUESTED) { + if (eventType === EVENTS.BID_REQUESTED) { const reqBidderId = `${args.bidderCode}_${args.auctionId}`; requestedBidders[reqBidderId] = deepClone(args); requestedBidders[reqBidderId].bids = []; @@ -77,7 +77,7 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { requestedBids[`${bid.bidId}_${bid.auctionId}`] = bid; }); } - if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT && isArray(args)) { + if (eventType === EVENTS.BID_TIMEOUT && isArray(args)) { const eventsStorage = yieldoneAnalytics.eventsStorage; const reqBidders = {}; args.forEach((bid) => { @@ -118,7 +118,7 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { } if ( - eventType === CONSTANTS.EVENTS.AUCTION_END || eventType === CONSTANTS.EVENTS.BID_WON + eventType === EVENTS.AUCTION_END || eventType === EVENTS.BID_WON ) { params.adServerTargeting = targeting.getAllTargeting( auctionManager.getAdUnitCodes(), diff --git a/modules/yuktamediaAnalyticsAdapter.js b/modules/yuktamediaAnalyticsAdapter.js index 820e6365a9f..25e4dc73b74 100644 --- a/modules/yuktamediaAnalyticsAdapter.js +++ b/modules/yuktamediaAnalyticsAdapter.js @@ -2,7 +2,7 @@ import {buildUrl, generateUUID, getWindowLocation, logError, logInfo, parseSizes import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS, STATUS } from '../src/constants.js'; import {getStorageManager} from '../src/storageManager.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {includes as strIncludes} from '../src/polyfill.js'; @@ -100,13 +100,13 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin track({ eventType, args }) { if (typeof args !== 'undefined') { switch (eventType) { - case CONSTANTS.EVENTS.AUCTION_INIT: + case EVENTS.AUCTION_INIT: logInfo(localStoragePrefix + 'AUCTION_INIT:', JSON.stringify(args)); if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { events.auctions[args.auctionId] = { bids: {} }; } break; - case CONSTANTS.EVENTS.BID_REQUESTED: + case EVENTS.BID_REQUESTED: logInfo(localStoragePrefix + 'BID_REQUESTED:', JSON.stringify(args)); if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { if (typeof events.auctions[args.auctionId] === 'undefined') { @@ -135,14 +135,14 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin }); } break; - case CONSTANTS.EVENTS.BID_RESPONSE: + case EVENTS.BID_RESPONSE: logInfo(localStoragePrefix + 'BID_RESPONSE:', JSON.stringify(args)); if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { if (typeof events.auctions[args.auctionId] === 'undefined') { events.auctions[args.auctionId] = { bids: {} }; } else if (Object.keys(events.auctions[args.auctionId]['bids']).length) { let bidResponse = events.auctions[args.auctionId]['bids'][args.requestId]; - bidResponse.isBid = args.getStatusCode() === CONSTANTS.STATUS.GOOD; + bidResponse.isBid = args.getStatusCode() === STATUS.GOOD; bidResponse.cpm = args.cpm; bidResponse.currency = args.currency; bidResponse.netRevenue = args.netRevenue; @@ -165,7 +165,7 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin } } break; - case CONSTANTS.EVENTS.NO_BID: + case EVENTS.NO_BID: logInfo(localStoragePrefix + 'NO_BID:', JSON.stringify(args)); if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { if (typeof events.auctions[args.auctionId] === 'undefined') { @@ -176,7 +176,7 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin } } break; - case CONSTANTS.EVENTS.BID_WON: + case EVENTS.BID_WON: logInfo(localStoragePrefix + 'BID_WON:', JSON.stringify(args)); if (typeof initOptions.enableSession !== 'undefined' && initOptions.enableSession) { updateSessionId(); @@ -192,7 +192,7 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin } } break; - case CONSTANTS.EVENTS.BID_TIMEOUT: + case EVENTS.BID_TIMEOUT: logInfo(localStoragePrefix + 'BID_TIMEOUT:', JSON.stringify(args)); if (args.length) { args.forEach(timeout => { @@ -208,7 +208,7 @@ var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoin }); } break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: logInfo(localStoragePrefix + 'AUCTION_END:', JSON.stringify(args)); if (typeof initOptions.enableSession !== 'undefined' && initOptions.enableSession) { updateSessionId(); diff --git a/modules/zeta_global_sspAnalyticsAdapter.js b/modules/zeta_global_sspAnalyticsAdapter.js index 1eb4cab93b0..f0933d2f62f 100644 --- a/modules/zeta_global_sspAnalyticsAdapter.js +++ b/modules/zeta_global_sspAnalyticsAdapter.js @@ -1,7 +1,7 @@ import {logInfo, logError} from '../src/utils.js'; import { ajax } from '../src/ajax.js'; import adapterManager from '../src/adapterManager.js'; -import CONSTANTS from '../src/constants.json'; +import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; @@ -48,7 +48,7 @@ function getZetaParams(event) { /// /////////// ADAPTER EVENT HANDLER FUNCTIONS ////////////// function adRenderSucceededHandler(args) { - let eventType = CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED + let eventType = EVENTS.AD_RENDER_SUCCEEDED logInfo(LOG_PREFIX + 'handle ' + eventType + ' event'); const event = { @@ -88,7 +88,7 @@ function adRenderSucceededHandler(args) { } function auctionEndHandler(args) { - let eventType = CONSTANTS.EVENTS.AUCTION_END; + let eventType = EVENTS.AUCTION_END; logInfo(LOG_PREFIX + 'handle ' + eventType + ' event'); const event = { @@ -177,10 +177,10 @@ let zetaAdapter = Object.assign({}, baseAdapter, { track({ eventType, args }) { switch (eventType) { - case CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED: + case EVENTS.AD_RENDER_SUCCEEDED: adRenderSucceededHandler(args); break; - case CONSTANTS.EVENTS.AUCTION_END: + case EVENTS.AUCTION_END: auctionEndHandler(args); break; } diff --git a/src/adRendering.js b/src/adRendering.js index a6d509bea77..7d306adc9cc 100644 --- a/src/adRendering.js +++ b/src/adRendering.js @@ -1,6 +1,6 @@ import {createIframe, deepAccess, inIframe, insertElement, logError, logWarn, replaceMacros} from './utils.js'; import * as events from './events.js'; -import CONSTANTS from './constants.json'; +import { AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS, MESSAGES } from './constants.js'; import {config} from './config.js'; import {executeRenderer, isRendererRequired} from './Renderer.js'; import {VIDEO} from './mediaTypes.js'; @@ -9,14 +9,14 @@ import {getCreativeRenderer} from './creativeRenderers.js'; import {hook} from './hook.js'; import {fireNativeTrackers} from './native.js'; -const {AD_RENDER_FAILED, AD_RENDER_SUCCEEDED, STALE_RENDER, BID_WON} = CONSTANTS.EVENTS; -const {EXCEPTION} = CONSTANTS.AD_RENDER_FAILED_REASON; +const { AD_RENDER_FAILED, AD_RENDER_SUCCEEDED, STALE_RENDER, BID_WON } = EVENTS; +const { EXCEPTION } = AD_RENDER_FAILED_REASON; /** * Emit the AD_RENDER_FAILED event. * * @param {Object} data - * @param data.reason one of the values in CONSTANTS.AD_RENDER_FAILED_REASON + * @param data.reason one of the values in AD_RENDER_FAILED_REASON * @param data.message failure description * @param [data.bid] bid response object that failed to render * @param [data.id] adId that failed to render @@ -52,7 +52,7 @@ export function emitAdRenderSucceeded({ doc, bid, id }) { export function handleCreativeEvent(data, bidResponse) { switch (data.event) { - case CONSTANTS.EVENTS.AD_RENDER_FAILED: + case EVENTS.AD_RENDER_FAILED: emitAdRenderFail({ bid: bidResponse, id: bidResponse.adId, @@ -60,7 +60,7 @@ export function handleCreativeEvent(data, bidResponse) { message: data.info.message }); break; - case CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED: + case EVENTS.AD_RENDER_SUCCEEDED: emitAdRenderSucceeded({ doc: null, bid: bidResponse, @@ -83,11 +83,11 @@ export function handleNativeMessage(data, bidResponse, {resizeFn, fireTrackers = } const HANDLERS = { - [CONSTANTS.MESSAGES.EVENT]: handleCreativeEvent + [MESSAGES.EVENT]: handleCreativeEvent } if (FEATURES.NATIVE) { - HANDLERS[CONSTANTS.MESSAGES.NATIVE] = handleNativeMessage; + HANDLERS[MESSAGES.NATIVE] = handleNativeMessage; } function creativeMessageHandler(deps) { @@ -115,7 +115,7 @@ export const getRenderingData = hook('sync', function (bidResponse, options) { export const doRender = hook('sync', function({renderFn, resizeFn, bidResponse, options}) { if (FEATURES.VIDEO && bidResponse.mediaType === VIDEO) { emitAdRenderFail({ - reason: CONSTANTS.AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT, + reason: AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT, message: 'Cannot render video ad', bid: bidResponse, id: bidResponse.adId @@ -145,13 +145,13 @@ doRender.before(function (next, args) { export function handleRender({renderFn, resizeFn, adId, options, bidResponse, doc}) { if (bidResponse == null) { emitAdRenderFail({ - reason: CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, + reason: AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, message: `Cannot find ad '${adId}'`, id: adId }); return; } - if (bidResponse.status === CONSTANTS.BID_STATUS.RENDERED) { + if (bidResponse.status === BID_STATUS.RENDERED) { logWarn(`Ad id ${adId} has been rendered before`); events.emit(STALE_RENDER, bidResponse); if (deepAccess(config.getConfig('auctionOptions'), 'suppressStaleRender')) { @@ -162,7 +162,7 @@ export function handleRender({renderFn, resizeFn, adId, options, bidResponse, do doRender({renderFn, resizeFn, bidResponse, options, doc}); } catch (e) { emitAdRenderFail({ - reason: CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION, + reason: AD_RENDER_FAILED_REASON.EXCEPTION, message: e.message, id: adId, bid: bidResponse @@ -198,7 +198,7 @@ export function renderAdDirect(doc, adId, options) { .then( () => emitAdRenderSucceeded({doc, bid, adId: bid.adId}), (e) => { - fail(e?.reason || CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION, e?.message) + fail(e?.reason || AD_RENDER_FAILED_REASON.EXCEPTION, e?.message) e?.stack && logError(e); } ); @@ -209,12 +209,12 @@ export function renderAdDirect(doc, adId, options) { } try { if (!adId || !doc) { - fail(CONSTANTS.AD_RENDER_FAILED_REASON.MISSING_DOC_OR_ADID, `missing ${adId ? 'doc' : 'adId'}`); + fail(AD_RENDER_FAILED_REASON.MISSING_DOC_OR_ADID, `missing ${adId ? 'doc' : 'adId'}`); } else { bid = auctionManager.findBidByAdId(adId); if ((doc === document && !inIframe())) { - fail(CONSTANTS.AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT, `renderAd was prevented from writing to the main document.`); + fail(AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT, `renderAd was prevented from writing to the main document.`); } else { handleRender({renderFn, resizeFn, adId, options: {clickUrl: options?.clickThrough}, bidResponse: bid, doc}); } diff --git a/src/adapterManager.js b/src/adapterManager.js index 72695be0946..cbabfa4380e 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -31,7 +31,7 @@ import {adunitCounter} from './adUnits.js'; import {getRefererInfo} from './refererDetection.js'; import {GDPR_GVLIDS, gdprDataHandler, gppDataHandler, uspDataHandler, } from './consentHandler.js'; import * as events from './events.js'; -import CONSTANTS from './constants.json'; +import { EVENTS, S2S } from './constants.js'; import {useMetrics} from './utils/perfMetrics.js'; import {auctionManager} from './auctionManager.js'; import {MODULE_TYPE_ANALYTICS, MODULE_TYPE_BIDDER, MODULE_TYPE_PREBID} from './activities/modules.js'; @@ -242,7 +242,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a * emit and pass adunits for external modification * @see {@link https://github.com/prebid/Prebid.js/issues/4149|Issue} */ - events.emit(CONSTANTS.EVENTS.BEFORE_REQUEST_BIDS, adUnits); + events.emit(EVENTS.BEFORE_REQUEST_BIDS, adUnits); if (FEATURES.NATIVE) { decorateAdUnitsWithNativeParams(adUnits); } @@ -300,10 +300,10 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a auctionId, bidderRequestId, uniquePbsTid, - bids: hookedGetBids({bidderCode, auctionId, bidderRequestId, 'adUnits': deepClone(adUnitsS2SCopy), src: CONSTANTS.S2S.SRC, metrics}), + bids: hookedGetBids({ bidderCode, auctionId, bidderRequestId, 'adUnits': deepClone(adUnitsS2SCopy), src: S2S.SRC, metrics }), auctionStart: auctionStart, timeout: s2sConfig.timeout, - src: CONSTANTS.S2S.SRC, + src: S2S.SRC, refererInfo, metrics, }, s2sParams); @@ -375,7 +375,7 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request } let [clientBidderRequests, serverBidderRequests] = bidRequests.reduce((partitions, bidRequest) => { - partitions[Number(typeof bidRequest.src !== 'undefined' && bidRequest.src === CONSTANTS.S2S.SRC)].push(bidRequest); + partitions[Number(typeof bidRequest.src !== 'undefined' && bidRequest.src === S2S.SRC)].push(bidRequest); return partitions; }, [[], []]); @@ -428,7 +428,7 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request // fire BID_REQUESTED event for each s2s bidRequest uniqueServerRequests.forEach(bidRequest => { // add the new sourceTid - events.emit(CONSTANTS.EVENTS.BID_REQUESTED, {...bidRequest, tid: bidRequest.auctionId}); + events.emit(EVENTS.BID_REQUESTED, { ...bidRequest, tid: bidRequest.auctionId }); }); // make bid requests @@ -454,7 +454,7 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request const adapter = _bidderRegistry[bidderRequest.bidderCode]; config.runWithBidder(bidderRequest.bidderCode, () => { logMessage(`CALLING BIDDER`); - events.emit(CONSTANTS.EVENTS.BID_REQUESTED, bidderRequest); + events.emit(EVENTS.BID_REQUESTED, bidderRequest); }); let ajax = ajaxBuilder(requestBidsTimeout, requestCallbacks ? { request: requestCallbacks.request.bind(null, bidderRequest.bidderCode), @@ -630,7 +630,7 @@ function invokeBidderMethod(bidder, method, spec, fn, ...params) { } function tryCallBidderMethod(bidder, method, param) { - if (param?.src !== CONSTANTS.S2S.SRC) { + if (param?.src !== S2S.SRC) { const target = getBidderMethod(bidder, method); if (target != null) { invokeBidderMethod(bidder, method, ...target, param); diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 337ae47f338..1d10c3161e5 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -5,7 +5,7 @@ import {createBid} from '../bidfactory.js'; import {userSync} from '../userSync.js'; import {nativeBidIsValid} from '../native.js'; import {isValidVideoBid} from '../video.js'; -import CONSTANTS from '../constants.json'; +import { EVENTS, STATUS, REJECTION_REASON } from '../constants.js'; import * as events from '../events.js'; import {includes} from '../polyfill.js'; import { @@ -256,7 +256,7 @@ export function newBidder(spec) { if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid))) { addBidResponse(adUnitCode, bid); } else { - addBidResponse.reject(adUnitCode, bid, CONSTANTS.REJECTION_REASON.INVALID) + addBidResponse.reject(adUnitCode, bid, REJECTION_REASON.INVALID) } } @@ -266,7 +266,7 @@ export function newBidder(spec) { function afterAllResponses() { done(); config.runWithBidder(spec.code, () => { - events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest); + events.emit(EVENTS.BIDDER_DONE, bidderRequest); registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent, bidderRequest.gppConsent); }); } @@ -288,7 +288,7 @@ export function newBidder(spec) { }); processBidderRequests(spec, validBidRequests.map(tidGuard.bidRequest), tidGuard.bidderRequest(bidderRequest), ajax, configEnabledCallback, { - onRequest: requestObject => events.emit(CONSTANTS.EVENTS.BEFORE_BIDDER_HTTP, bidderRequest, requestObject), + onRequest: requestObject => events.emit(EVENTS.BEFORE_BIDDER_HTTP, bidderRequest, requestObject), onResponse: (resp) => { onTimelyResponse(spec.code); responses.push(resp) @@ -307,7 +307,7 @@ export function newBidder(spec) { onTimelyResponse(spec.code); } adapterManager.callBidderError(spec.code, error, bidderRequest) - events.emit(CONSTANTS.EVENTS.BIDDER_ERROR, { error, bidderRequest }); + events.emit(EVENTS.BIDDER_ERROR, { error, bidderRequest }); logError(`Server call for ${spec.code} failed: ${errorMessage} ${error.status}. Continuing without bids.`); }, onBid: (bid) => { @@ -316,18 +316,18 @@ export function newBidder(spec) { bid.adapterCode = bidRequest.bidder; if (isInvalidAlternateBidder(bid.bidderCode, bidRequest.bidder)) { logWarn(`${bid.bidderCode} is not a registered partner or known bidder of ${bidRequest.bidder}, hence continuing without bid. If you wish to support this bidder, please mark allowAlternateBidderCodes as true in bidderSettings.`); - addBidResponse.reject(bidRequest.adUnitCode, bid, CONSTANTS.REJECTION_REASON.BIDDER_DISALLOWED) + addBidResponse.reject(bidRequest.adUnitCode, bid, REJECTION_REASON.BIDDER_DISALLOWED) return; } // creating a copy of original values as cpm and currency are modified later bid.originalCpm = bid.cpm; bid.originalCurrency = bid.currency; bid.meta = bid.meta || Object.assign({}, bid[bidRequest.bidder]); - const prebidBid = Object.assign(createBid(CONSTANTS.STATUS.GOOD, bidRequest), bid, pick(bidRequest, TIDS)); + const prebidBid = Object.assign(createBid(STATUS.GOOD, bidRequest), bid, pick(bidRequest, TIDS)); addBidWithCode(bidRequest.adUnitCode, prebidBid); } else { logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bid.requestId}. Ignoring.`); - addBidResponse.reject(null, bid, CONSTANTS.REJECTION_REASON.INVALID_REQUEST_ID); + addBidResponse.reject(null, bid, REJECTION_REASON.INVALID_REQUEST_ID); } }, onCompletion: afterAllResponses, diff --git a/src/auction.js b/src/auction.js index 2d7d350bb7a..26845936797 100644 --- a/src/auction.js +++ b/src/auction.js @@ -94,7 +94,7 @@ import {auctionManager} from './auctionManager.js'; import {bidderSettings} from './bidderSettings.js'; import * as events from './events.js'; import adapterManager from './adapterManager.js'; -import CONSTANTS from './constants.json'; +import { EVENTS, GRANULARITY_OPTIONS, JSON_MAPPING, S2S, TARGETING_KEYS } from './constants.js'; import {defer, GreedyPromise} from './utils/promise.js'; import {useMetrics} from './utils/perfMetrics.js'; import {adjustCpm} from './utils/cpm.js'; @@ -107,7 +107,7 @@ export const AUCTION_IN_PROGRESS = 'inProgress'; export const AUCTION_COMPLETED = 'completed'; // register event for bid adjustment -events.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) { +events.on(EVENTS.BID_ADJUSTMENT, function (bid) { adjustBids(bid); }); @@ -196,7 +196,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a if (!timedOut) { clearTimeout(_timeoutTimer); } else { - events.emit(CONSTANTS.EVENTS.AUCTION_TIMEOUT, getProperties()); + events.emit(EVENTS.AUCTION_TIMEOUT, getProperties()); } if (_auctionEnd === undefined) { let timedOutRequests = []; @@ -204,7 +204,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a logMessage(`Auction ${_auctionId} timedOut`); timedOutRequests = _bidderRequests.filter(rq => !_timelyRequests.has(rq.bidderRequestId)).flatMap(br => br.bids) if (timedOutRequests.length) { - events.emit(CONSTANTS.EVENTS.BID_TIMEOUT, timedOutRequests); + events.emit(EVENTS.BID_TIMEOUT, timedOutRequests); } } @@ -215,7 +215,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a metrics.timeBetween('callBids', 'auctionEnd', 'requestBids.callBids'); done.resolve(); - events.emit(CONSTANTS.EVENTS.AUCTION_END, getProperties()); + events.emit(EVENTS.AUCTION_END, getProperties()); bidsBackCallback(_adUnits, function () { try { if (_callback != null) { @@ -293,7 +293,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a _auctionStatus = AUCTION_IN_PROGRESS; - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, getProperties()); + events.emit(EVENTS.AUCTION_INIT, getProperties()); let callbacks = auctionCallbacks(auctionDone, this); adapterManager.callBids(_adUnits, bidRequests, callbacks.addBidResponse, callbacks.adapterDone, { @@ -335,7 +335,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a call.bidRequests.some(bidRequest => { let requests = 1; - let source = (typeof bidRequest.src !== 'undefined' && bidRequest.src === CONSTANTS.S2S.SRC) ? 's2s' + let source = (typeof bidRequest.src !== 'undefined' && bidRequest.src === S2S.SRC) ? 's2s' : bidRequest.bidderCode; // if we have no previous info on this source just let them through if (sourceInfo[source]) { @@ -381,7 +381,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a adapterManager.callSetTargetingBidder(bid.adapterCode || bid.bidder, bid); } - events.on(CONSTANTS.EVENTS.SEAT_NON_BID, (event) => { + events.on(EVENTS.SEAT_NON_BID, (event) => { if (event.auctionId === _auctionId) { addNonBids(event.seatnonbid) } @@ -465,7 +465,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM function acceptBidResponse(adUnitCode, bid) { handleBidResponse(adUnitCode, bid, (done) => { let bidResponse = getPreparedBidForAuction(bid); - events.emit(CONSTANTS.EVENTS.BID_ACCEPTED, bidResponse); + events.emit(EVENTS.BID_ACCEPTED, bidResponse); if (FEATURES.VIDEO && bidResponse.mediaType === VIDEO) { tryAddVideoBid(auctionInstance, bidResponse, done); } else { @@ -482,7 +482,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM return handleBidResponse(adUnitCode, bid, (done) => { bid.rejectionReason = reason; logWarn(`Bid from ${bid.bidder || 'unknown bidder'} was rejected: ${reason}`, bid) - events.emit(CONSTANTS.EVENTS.BID_REJECTED, bid); + events.emit(EVENTS.BID_REJECTED, bid); auctionInstance.addBidRejected(bid); done(); }) @@ -507,7 +507,7 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM bidderRequest.bids.forEach(bid => { if (!bidResponseMap[bid.bidId]) { auctionInstance.addNoBid(bid); - events.emit(CONSTANTS.EVENTS.NO_BID, bid); + events.emit(EVENTS.NO_BID, bid); } }); @@ -546,7 +546,7 @@ export function addBidToAuction(auctionInstance, bidResponse) { useMetrics(bidResponse.metrics).timeSince('addBidResponse', 'addBidResponse.total'); auctionInstance.addBidReceived(bidResponse); - events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); } // Video bids may fail if the cache is down, or there's trouble on the network. @@ -672,7 +672,7 @@ function getPreparedBidForAuction(bid, {index = auctionManager.index} = {}) { // // CAREFUL: Publishers rely on certain bid properties to be available (like cpm), // but others to not be set yet (like priceStrings). See #1372 and #1389. - events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid); + events.emit(EVENTS.BID_ADJUSTMENT, bid); // a publisher-defined renderer can be used to render bids const bidRenderer = index.getBidRequest(bid)?.renderer || index.getAdUnit(bid).renderer; @@ -767,17 +767,17 @@ export const getPriceGranularity = (bid, {index = auctionManager.index} = {}) => export const getPriceByGranularity = (granularity) => { return (bid) => { const bidGranularity = granularity || getPriceGranularity(bid); - if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) { + if (bidGranularity === GRANULARITY_OPTIONS.AUTO) { return bid.pbAg; - } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) { + } else if (bidGranularity === GRANULARITY_OPTIONS.DENSE) { return bid.pbDg; - } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.LOW) { + } else if (bidGranularity === GRANULARITY_OPTIONS.LOW) { return bid.pbLg; - } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.MEDIUM) { + } else if (bidGranularity === GRANULARITY_OPTIONS.MEDIUM) { return bid.pbMg; - } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.HIGH) { + } else if (bidGranularity === GRANULARITY_OPTIONS.HIGH) { return bid.pbHg; - } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.CUSTOM) { + } else if (bidGranularity === GRANULARITY_OPTIONS.CUSTOM) { return bid.pbCg; } } @@ -838,7 +838,6 @@ function createKeyVal(key, value) { } function defaultAdserverTargeting() { - const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS; return [ createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'), createKeyVal(TARGETING_KEYS.AD_ID, 'adId'), @@ -860,15 +859,14 @@ function defaultAdserverTargeting() { * @returns {*} */ export function getStandardBidderSettings(mediaType, bidderCode) { - const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS; const standardSettings = Object.assign({}, bidderSettings.settingsFor(null)); - if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) { - standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting(); + if (!standardSettings[JSON_MAPPING.ADSERVER_TARGETING]) { + standardSettings[JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting(); } if (FEATURES.VIDEO && mediaType === 'video') { - const adserverTargeting = standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING].slice(); - standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = adserverTargeting; + const adserverTargeting = standardSettings[JSON_MAPPING.ADSERVER_TARGETING].slice(); + standardSettings[JSON_MAPPING.ADSERVER_TARGETING] = adserverTargeting; // Adding hb_uuid + hb_cache_id [TARGETING_KEYS.UUID, TARGETING_KEYS.CACHE_ID].forEach(targetingKeyVal => { @@ -906,7 +904,7 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, {index = aucti setKeys(keyValues, standardSettings, custBidObj, bidRequest); // 2) set keys from specific bidder setting override if they exist - if (bidderCode && bidderSettings.getOwn(bidderCode, CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING)) { + if (bidderCode && bidderSettings.getOwn(bidderCode, JSON_MAPPING.ADSERVER_TARGETING)) { setKeys(keyValues, bidderSettings.ownSettingsFor(bidderCode), custBidObj, bidRequest); custBidObj.sendStandardTargeting = bidderSettings.get(bidderCode, 'sendStandardTargeting'); } @@ -920,7 +918,7 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, {index = aucti } function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { - var targeting = bidderSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]; + var targeting = bidderSettings[JSON_MAPPING.ADSERVER_TARGETING]; custBidObj.size = custBidObj.getSize(); (targeting || []).forEach(function (kvPair) { @@ -941,7 +939,7 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { if ( ((typeof bidderSettings.suppressEmptyKeys !== 'undefined' && bidderSettings.suppressEmptyKeys === true) || - key === CONSTANTS.TARGETING_KEYS.DEAL || key === CONSTANTS.TARGETING_KEYS.ACAT || key === CONSTANTS.TARGETING_KEYS.DSP || key === CONSTANTS.TARGETING_KEYS.CRID) && // hb_deal & hb_acat are suppressed automatically if not set + key === TARGETING_KEYS.DEAL || key === TARGETING_KEYS.ACAT || key === TARGETING_KEYS.DSP || key === TARGETING_KEYS.CRID) && // hb_deal & hb_acat are suppressed automatically if not set ( isEmptyStr(value) || value === null || diff --git a/src/auctionManager.js b/src/auctionManager.js index 2d6e0ffbfd9..a1ab1a859da 100644 --- a/src/auctionManager.js +++ b/src/auctionManager.js @@ -23,7 +23,7 @@ import { uniques, logWarn } from './utils.js'; import { newAuction, getStandardBidderSettings, AUCTION_COMPLETED } from './auction.js'; import {AuctionIndex} from './auctionIndex.js'; -import CONSTANTS from './constants.json'; +import { BID_STATUS, JSON_MAPPING } from './constants.js'; import {useMetrics} from './utils/perfMetrics.js'; import {ttlCollection} from './utils/ttlCollection.js'; import {getTTL, onTTLBufferChange} from './bidTTL.js'; @@ -77,7 +77,7 @@ export function newAuctionManager() { metrics.timeBetween('requestBids', 'bidWon', 'render.e2e'); const auction = getAuction(bid.auctionId); if (auction) { - bid.status = CONSTANTS.BID_STATUS.RENDERED; + bid.status = BID_STATUS.RENDERED; auction.addWinningBid(bid); } else { logWarn(`Auction not found when adding winning bid`); @@ -134,14 +134,14 @@ export function newAuctionManager() { }; auctionManager.getStandardBidderAdServerTargeting = function() { - return getStandardBidderSettings()[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]; + return getStandardBidderSettings()[JSON_MAPPING.ADSERVER_TARGETING]; }; auctionManager.setStatusForBids = function(adId, status) { let bid = auctionManager.findBidByAdId(adId); if (bid) bid.status = status; - if (bid && status === CONSTANTS.BID_STATUS.BID_TARGETING_SET) { + if (bid && status === BID_STATUS.BID_TARGETING_SET) { const auction = getAuction(bid.auctionId); if (auction) auction.setBidTargeting(bid); } diff --git a/src/bidderSettings.js b/src/bidderSettings.js index b39bf480511..4d97ed2b95e 100644 --- a/src/bidderSettings.js +++ b/src/bidderSettings.js @@ -1,6 +1,6 @@ import {deepAccess, mergeDeep} from './utils.js'; import {getGlobal} from './prebidGlobal.js'; -import CONSTANTS from './constants.json'; +import { JSON_MAPPING } from './constants.js'; export class ScopedSettings { constructor(getSettings, defaultScope) { @@ -65,4 +65,4 @@ export class ScopedSettings { } } -export const bidderSettings = new ScopedSettings(() => getGlobal().bidderSettings || {}, CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD); +export const bidderSettings = new ScopedSettings(() => getGlobal().bidderSettings || {}, JSON_MAPPING.BD_SETTING_STANDARD); diff --git a/src/config.js b/src/config.js index e3bb5f146ed..f4dd0de9612 100644 --- a/src/config.js +++ b/src/config.js @@ -27,9 +27,9 @@ import { logWarn, mergeDeep } from './utils.js'; -import CONSTANTS from './constants.json'; +import {DEBUG_MODE} from './constants.js'; -const DEFAULT_DEBUG = getParameterByName(CONSTANTS.DEBUG_MODE).toUpperCase() === 'TRUE'; +const DEFAULT_DEBUG = getParameterByName(DEBUG_MODE).toUpperCase() === 'TRUE'; const DEFAULT_BIDDER_TIMEOUT = 3000; const DEFAULT_ENABLE_SEND_ALL_BIDS = true; const DEFAULT_DISABLE_AJAX_TIMEOUT = false; diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 00000000000..b40b7ddb9b0 --- /dev/null +++ b/src/constants.js @@ -0,0 +1,190 @@ +export const JSON_MAPPING = { + PL_CODE: 'code', + PL_SIZE: 'sizes', + PL_BIDS: 'bids', + BD_BIDDER: 'bidder', + BD_ID: 'paramsd', + BD_PL_ID: 'placementId', + ADSERVER_TARGETING: 'adserverTargeting', + BD_SETTING_STANDARD: 'standard' +}; + +export const DEBUG_MODE = 'pbjs_debug'; + +export const STATUS = { + GOOD: 1 +}; + +export const EVENTS = { + AUCTION_INIT: 'auctionInit', + AUCTION_TIMEOUT: 'auctionTimeout', + AUCTION_END: 'auctionEnd', + BID_ADJUSTMENT: 'bidAdjustment', + BID_TIMEOUT: 'bidTimeout', + BID_REQUESTED: 'bidRequested', + BID_RESPONSE: 'bidResponse', + BID_REJECTED: 'bidRejected', + NO_BID: 'noBid', + SEAT_NON_BID: 'seatNonBid', + BID_WON: 'bidWon', + BIDDER_DONE: 'bidderDone', + BIDDER_ERROR: 'bidderError', + SET_TARGETING: 'setTargeting', + BEFORE_REQUEST_BIDS: 'beforeRequestBids', + BEFORE_BIDDER_HTTP: 'beforeBidderHttp', + REQUEST_BIDS: 'requestBids', + ADD_AD_UNITS: 'addAdUnits', + AD_RENDER_FAILED: 'adRenderFailed', + AD_RENDER_SUCCEEDED: 'adRenderSucceeded', + TCF2_ENFORCEMENT: 'tcf2Enforcement', + AUCTION_DEBUG: 'auctionDebug', + BID_VIEWABLE: 'bidViewable', + STALE_RENDER: 'staleRender', + BILLABLE_EVENT: 'billableEvent', + BID_ACCEPTED: 'bidAccepted' +}; + +export const AD_RENDER_FAILED_REASON = { + PREVENT_WRITING_ON_MAIN_DOCUMENT: 'preventWritingOnMainDocument', + NO_AD: 'noAd', + EXCEPTION: 'exception', + CANNOT_FIND_AD: 'cannotFindAd', + MISSING_DOC_OR_ADID: 'missingDocOrAdid' +}; + +export const EVENT_ID_PATHS = { + bidWon: 'adUnitCode' +}; + +export const GRANULARITY_OPTIONS = { + LOW: 'low', + MEDIUM: 'medium', + HIGH: 'high', + AUTO: 'auto', + DENSE: 'dense', + CUSTOM: 'custom' +}; + +export const TARGETING_KEYS = { + BIDDER: 'hb_bidder', + AD_ID: 'hb_adid', + PRICE_BUCKET: 'hb_pb', + SIZE: 'hb_size', + DEAL: 'hb_deal', + SOURCE: 'hb_source', + FORMAT: 'hb_format', + UUID: 'hb_uuid', + CACHE_ID: 'hb_cache_id', + CACHE_HOST: 'hb_cache_host', + ADOMAIN: 'hb_adomain', + ACAT: 'hb_acat', + CRID: 'hb_crid', + DSP: 'hb_dsp' +}; + +export const DEFAULT_TARGETING_KEYS = { + BIDDER: 'hb_bidder', + AD_ID: 'hb_adid', + PRICE_BUCKET: 'hb_pb', + SIZE: 'hb_size', + DEAL: 'hb_deal', + FORMAT: 'hb_format', + UUID: 'hb_uuid', + CACHE_HOST: 'hb_cache_host' +}; + +export const NATIVE_KEYS = { + title: 'hb_native_title', + body: 'hb_native_body', + body2: 'hb_native_body2', + privacyLink: 'hb_native_privacy', + privacyIcon: 'hb_native_privicon', + sponsoredBy: 'hb_native_brand', + image: 'hb_native_image', + icon: 'hb_native_icon', + clickUrl: 'hb_native_linkurl', + displayUrl: 'hb_native_displayurl', + cta: 'hb_native_cta', + rating: 'hb_native_rating', + address: 'hb_native_address', + downloads: 'hb_native_downloads', + likes: 'hb_native_likes', + phone: 'hb_native_phone', + price: 'hb_native_price', + salePrice: 'hb_native_saleprice', + rendererUrl: 'hb_renderer_url', + adTemplate: 'hb_adTemplate' +}; + +export const S2S = { + SRC: 's2s', + DEFAULT_ENDPOINT: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', + SYNCED_BIDDERS_KEY: 'pbjsSyncs' +}; + +export const BID_STATUS = { + BID_TARGETING_SET: 'targetingSet', + RENDERED: 'rendered', + BID_REJECTED: 'bidRejected' +}; + +export const REJECTION_REASON = { + INVALID: 'Bid has missing or invalid properties', + INVALID_REQUEST_ID: 'Invalid request ID', + BIDDER_DISALLOWED: 'Bidder code is not allowed by allowedAlternateBidderCodes / allowUnknownBidderCodes', + FLOOR_NOT_MET: 'Bid does not meet price floor', + CANNOT_CONVERT_CURRENCY: 'Unable to convert currency', + DSA_REQUIRED: 'Bid does not provide required DSA transparency info', + DSA_MISMATCH: 'Bid indicates inappropriate DSA rendering method' +}; + +export const PREBID_NATIVE_DATA_KEYS_TO_ORTB = { + body: 'desc', + body2: 'desc2', + sponsoredBy: 'sponsored', + cta: 'ctatext', + rating: 'rating', + address: 'address', + downloads: 'downloads', + likes: 'likes', + phone: 'phone', + price: 'price', + salePrice: 'saleprice', + displayUrl: 'displayurl' +}; + +export const NATIVE_ASSET_TYPES = { + sponsored: 1, + desc: 2, + rating: 3, + likes: 4, + downloads: 5, + price: 6, + saleprice: 7, + phone: 8, + address: 9, + desc2: 10, + displayurl: 11, + ctatext: 12 +}; + +export const NATIVE_IMAGE_TYPES = { + ICON: 1, + MAIN: 3 +}; + +export const NATIVE_KEYS_THAT_ARE_NOT_ASSETS = [ + 'privacyIcon', + 'clickUrl', + 'sendTargetingKeys', + 'adTemplate', + 'rendererUrl', + 'type' +]; + +export const MESSAGES = { + REQUEST: 'Prebid Request', + RESPONSE: 'Prebid Response', + NATIVE: 'Prebid Native', + EVENT: 'Prebid Event' +}; diff --git a/src/constants.json b/src/constants.json deleted file mode 100644 index ceac779a508..00000000000 --- a/src/constants.json +++ /dev/null @@ -1,196 +0,0 @@ -{ - "JSON_MAPPING": { - "PL_CODE": "code", - "PL_SIZE": "sizes", - "PL_BIDS": "bids", - "BD_BIDDER": "bidder", - "BD_ID": "paramsd", - "BD_PL_ID": "placementId", - "ADSERVER_TARGETING": "adserverTargeting", - "BD_SETTING_STANDARD": "standard" - }, - "FLOOR_SKIPPED_REASON": { - "NOT_FOUND": "not_found", - "RANDOM": "random" - }, - "DEBUG_MODE": "pbjs_debug", - "STATUS": { - "GOOD": 1 - }, - "CB": { - "TYPE": { - "ALL_BIDS_BACK": "allRequestedBidsBack", - "AD_UNIT_BIDS_BACK": "adUnitBidsBack", - "BID_WON": "bidWon", - "REQUEST_BIDS": "requestBids" - } - }, - "EVENTS": { - "AUCTION_INIT": "auctionInit", - "AUCTION_TIMEOUT": "auctionTimeout", - "AUCTION_END": "auctionEnd", - "BID_ADJUSTMENT": "bidAdjustment", - "BID_TIMEOUT": "bidTimeout", - "BID_REQUESTED": "bidRequested", - "BID_RESPONSE": "bidResponse", - "BID_REJECTED": "bidRejected", - "NO_BID": "noBid", - "SEAT_NON_BID": "seatNonBid", - "BID_WON": "bidWon", - "BIDDER_DONE": "bidderDone", - "BIDDER_ERROR": "bidderError", - "SET_TARGETING": "setTargeting", - "BEFORE_REQUEST_BIDS": "beforeRequestBids", - "BEFORE_BIDDER_HTTP": "beforeBidderHttp", - "REQUEST_BIDS": "requestBids", - "ADD_AD_UNITS": "addAdUnits", - "AD_RENDER_FAILED": "adRenderFailed", - "AD_RENDER_SUCCEEDED": "adRenderSucceeded", - "TCF2_ENFORCEMENT": "tcf2Enforcement", - "AUCTION_DEBUG": "auctionDebug", - "BID_VIEWABLE": "bidViewable", - "STALE_RENDER": "staleRender", - "BILLABLE_EVENT": "billableEvent", - "BID_ACCEPTED": "bidAccepted" - }, - "AD_RENDER_FAILED_REASON": { - "PREVENT_WRITING_ON_MAIN_DOCUMENT": "preventWritingOnMainDocument", - "NO_AD": "noAd", - "EXCEPTION": "exception", - "CANNOT_FIND_AD": "cannotFindAd", - "MISSING_DOC_OR_ADID": "missingDocOrAdid" - }, - "EVENT_ID_PATHS": { - "bidWon": "adUnitCode" - }, - "GRANULARITY_OPTIONS": { - "LOW": "low", - "MEDIUM": "medium", - "HIGH": "high", - "AUTO": "auto", - "DENSE": "dense", - "CUSTOM": "custom" - }, - "TARGETING_KEYS": { - "BIDDER": "hb_bidder", - "AD_ID": "hb_adid", - "PRICE_BUCKET": "hb_pb", - "SIZE": "hb_size", - "DEAL": "hb_deal", - "SOURCE": "hb_source", - "FORMAT": "hb_format", - "UUID": "hb_uuid", - "CACHE_ID": "hb_cache_id", - "CACHE_HOST": "hb_cache_host", - "ADOMAIN": "hb_adomain", - "ACAT": "hb_acat", - "CRID": "hb_crid", - "DSP": "hb_dsp" - }, - "DEFAULT_TARGETING_KEYS": { - "BIDDER": "hb_bidder", - "AD_ID": "hb_adid", - "PRICE_BUCKET": "hb_pb", - "SIZE": "hb_size", - "DEAL": "hb_deal", - "FORMAT": "hb_format", - "UUID": "hb_uuid", - "CACHE_HOST": "hb_cache_host" - }, - "NATIVE_KEYS": { - "title": "hb_native_title", - "body": "hb_native_body", - "body2": "hb_native_body2", - "privacyLink": "hb_native_privacy", - "privacyIcon": "hb_native_privicon", - "sponsoredBy": "hb_native_brand", - "image": "hb_native_image", - "icon": "hb_native_icon", - "clickUrl": "hb_native_linkurl", - "displayUrl": "hb_native_displayurl", - "cta": "hb_native_cta", - "rating": "hb_native_rating", - "address": "hb_native_address", - "downloads": "hb_native_downloads", - "likes": "hb_native_likes", - "phone": "hb_native_phone", - "price": "hb_native_price", - "salePrice": "hb_native_saleprice", - "rendererUrl": "hb_renderer_url", - "adTemplate": "hb_adTemplate" - }, - "S2S": { - "SRC": "s2s", - "DEFAULT_ENDPOINT": "https://prebid.adnxs.com/pbs/v1/openrtb2/auction", - "SYNCED_BIDDERS_KEY": "pbjsSyncs" - }, - "BID_STATUS": { - "BID_TARGETING_SET": "targetingSet", - "RENDERED": "rendered", - "BID_REJECTED": "bidRejected" - }, - "REJECTION_REASON": { - "INVALID": "Bid has missing or invalid properties", - "INVALID_REQUEST_ID": "Invalid request ID", - "BIDDER_DISALLOWED": "Bidder code is not allowed by allowedAlternateBidderCodes / allowUnknownBidderCodes", - "FLOOR_NOT_MET": "Bid does not meet price floor", - "CANNOT_CONVERT_CURRENCY": "Unable to convert currency", - "DSA_REQUIRED": "Bid does not provide required DSA transparency info", - "DSA_MISMATCH": "Bid indicates inappropriate DSA rendering method" - }, - "PREBID_NATIVE_DATA_KEYS_TO_ORTB": { - "body": "desc", - "body2": "desc2", - "sponsoredBy": "sponsored", - "cta": "ctatext", - "rating": "rating", - "address": "address", - "downloads": "downloads", - "likes": "likes", - "phone": "phone", - "price": "price", - "salePrice": "saleprice", - "displayUrl": "displayurl" - }, - "NATIVE_ASSET_TYPES": { - "sponsored": 1, - "desc": 2, - "rating": 3, - "likes": 4, - "downloads": 5, - "price": 6, - "saleprice": 7, - "phone": 8, - "address": 9, - "desc2": 10, - "displayurl": 11, - "ctatext": 12 - }, - "NATIVE_IMAGE_TYPES": { - "ICON": 1, - "MAIN": 3 - }, - "NATIVE_KEYS_THAT_ARE_NOT_ASSETS": [ - "privacyIcon", - "clickUrl", - "sendTargetingKeys", - "adTemplate", - "rendererUrl", - "type" - ], - "FLOOR_VALUES": { - "NO_DATA": "noData", - "AD_UNIT": "adUnit", - "SET_CONFIG": "setConfig", - "FETCH": "fetch", - "SUCCESS": "success", - "ERROR": "error", - "TIMEOUT": "timeout" - }, - "MESSAGES": { - "REQUEST": "Prebid Request", - "RESPONSE": "Prebid Response", - "NATIVE": "Prebid Native", - "EVENT": "Prebid Event" - } -} diff --git a/src/events.js b/src/events.js index d98991180bf..38e7f633d16 100644 --- a/src/events.js +++ b/src/events.js @@ -2,7 +2,7 @@ * events.js */ import * as utils from './utils.js' -import CONSTANTS from './constants.json'; +import { EVENTS, EVENT_ID_PATHS } from './constants.js'; import {ttlCollection} from './utils/ttlCollection.js'; import {config} from './config.js'; const TTL_CONFIG = 'eventHistoryTTL'; @@ -28,9 +28,9 @@ let slice = Array.prototype.slice; let push = Array.prototype.push; // define entire events -let allEvents = Object.values(CONSTANTS.EVENTS); +let allEvents = Object.values(EVENTS); -const idPaths = CONSTANTS.EVENT_ID_PATHS; +const idPaths = EVENT_ID_PATHS; const _public = (function () { let _handlers = {}; diff --git a/src/native.js b/src/native.js index 1b6e13c77fc..f001200000d 100644 --- a/src/native.js +++ b/src/native.js @@ -13,7 +13,7 @@ import { } from './utils.js'; import {includes} from './polyfill.js'; import {auctionManager} from './auctionManager.js'; -import CONSTANTS from './constants.json'; +import {NATIVE_ASSET_TYPES, NATIVE_IMAGE_TYPES, PREBID_NATIVE_DATA_KEYS_TO_ORTB, NATIVE_KEYS_THAT_ARE_NOT_ASSETS, NATIVE_KEYS} from './constants.js'; import {NATIVE} from './mediaTypes.js'; /** @@ -23,8 +23,8 @@ import {NATIVE} from './mediaTypes.js'; export const nativeAdapters = []; -export const NATIVE_TARGETING_KEYS = Object.keys(CONSTANTS.NATIVE_KEYS).map( - key => CONSTANTS.NATIVE_KEYS[key] +export const NATIVE_TARGETING_KEYS = Object.keys(NATIVE_KEYS).map( + key => NATIVE_KEYS[key] ); export const IMAGE = { @@ -84,8 +84,6 @@ const SUPPORTED_TYPES = { image: IMAGE }; -const { NATIVE_ASSET_TYPES, NATIVE_IMAGE_TYPES, PREBID_NATIVE_DATA_KEYS_TO_ORTB, NATIVE_KEYS_THAT_ARE_NOT_ASSETS, NATIVE_KEYS } = CONSTANTS; - // inverse native maps useful for converting to legacy const PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE = inverse(PREBID_NATIVE_DATA_KEYS_TO_ORTB); const NATIVE_ASSET_TYPES_INVERSE = inverse(NATIVE_ASSET_TYPES); @@ -425,7 +423,7 @@ export function getNativeRenderingData(bid, adUnit, keys) { const data = { ...getDefinedParams(bid.native, ['rendererUrl', 'adTemplate']), assets: getNativeAssets(bid.native, keys), - nativeKeys: CONSTANTS.NATIVE_KEYS + nativeKeys: NATIVE_KEYS }; if (bid.native.ortb) { data.ortb = bid.native.ortb; @@ -443,7 +441,7 @@ function assetsMessage(data, adObject, keys, {index = auctionManager.index} = {} }; } -const NATIVE_KEYS_INVERTED = Object.fromEntries(Object.entries(CONSTANTS.NATIVE_KEYS).map(([k, v]) => [v, k])); +const NATIVE_KEYS_INVERTED = Object.fromEntries(Object.entries(NATIVE_KEYS).map(([k, v]) => [v, k])); /** * Constructs a message object containing asset values for each of the @@ -476,7 +474,7 @@ function getNativeKeys(adUnit) { } return { - ...CONSTANTS.NATIVE_KEYS, + ...NATIVE_KEYS, ...extraNativeKeys } } diff --git a/src/prebid.js b/src/prebid.js index 750a4bdee1a..e96c0b36c9f 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -34,7 +34,7 @@ import {adunitCounter} from './adUnits.js'; import {createBid} from './bidfactory.js'; import {storageCallbacks} from './storageManager.js'; import {default as adapterManager, getS2SBidderSet} from './adapterManager.js'; -import CONSTANTS from './constants.json'; +import { BID_STATUS, EVENTS, NATIVE_KEYS } from './constants.js'; import * as events from './events.js'; import {newMetrics, useMetrics} from './utils/perfMetrics.js'; import {defer, GreedyPromise} from './utils/promise.js'; @@ -48,7 +48,7 @@ const pbjsInstance = getGlobal(); const { triggerUserSyncs } = userSync; /* private variables */ -const { ADD_AD_UNITS, REQUEST_BIDS, SET_TARGETING } = CONSTANTS.EVENTS; +const { ADD_AD_UNITS, REQUEST_BIDS, SET_TARGETING } = EVENTS; const eventValidators = { bidWon: checkDefinedPlacement @@ -143,7 +143,7 @@ function validateNativeMediaType(adUnit) { const native = validatedAdUnit.mediaTypes.native; // if native assets are specified in OpenRTB format, remove legacy assets and print a warn. if (native.ortb) { - const legacyNativeKeys = Object.keys(CONSTANTS.NATIVE_KEYS).filter(key => CONSTANTS.NATIVE_KEYS[key].includes('hb_native_')); + const legacyNativeKeys = Object.keys(NATIVE_KEYS).filter(key => NATIVE_KEYS[key].includes('hb_native_')); const nativeKeys = Object.keys(native); const intersection = nativeKeys.filter(nativeKey => legacyNativeKeys.includes(nativeKey)); if (intersection.length > 0) { @@ -173,7 +173,7 @@ function validateAdUnitPos(adUnit, mediaType) { let warning = `Value of property 'pos' on ad unit ${adUnit.code} should be of type: Number`; logWarn(warning); - events.emit(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'WARNING', arguments: warning}); + events.emit(EVENTS.AUCTION_DEBUG, { type: 'WARNING', arguments: warning }); delete adUnit.mediaTypes[mediaType].pos; } @@ -416,7 +416,7 @@ pbjsInstance.setTargetingForGPTAsync = function (adUnit, customSlotMatching) { Object.keys(targetingSet).forEach((adUnitCode) => { Object.keys(targetingSet[adUnitCode]).forEach((targetingKey) => { if (targetingKey === 'hb_adid') { - auctionManager.setStatusForBids(targetingSet[adUnitCode][targetingKey], CONSTANTS.BID_STATUS.BID_TARGETING_SET); + auctionManager.setStatusForBids(targetingSet[adUnitCode][targetingKey], BID_STATUS.BID_TARGETING_SET); } }); }); @@ -857,7 +857,7 @@ pbjsInstance.getAllWinningBids = function () { */ pbjsInstance.getAllPrebidWinningBids = function () { return auctionManager.getBidsReceived() - .filter(bid => bid.status === CONSTANTS.BID_STATUS.BID_TARGETING_SET); + .filter(bid => bid.status === BID_STATUS.BID_TARGETING_SET); }; /** diff --git a/src/secureCreatives.js b/src/secureCreatives.js index 1880f56f474..96ace0792e4 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -5,16 +5,16 @@ import * as events from './events.js'; import {getAllAssetsMessage, getAssetMessage} from './native.js'; -import CONSTANTS from './constants.json'; +import { BID_STATUS, EVENTS, MESSAGES } from './constants.js'; import {isApnGetTagDefined, isGptPubadsDefined, logError, logWarn} from './utils.js'; import {auctionManager} from './auctionManager.js'; import {find, includes} from './polyfill.js'; import {handleCreativeEvent, handleNativeMessage, handleRender} from './adRendering.js'; import {getCreativeRendererSource} from './creativeRenderers.js'; -const {REQUEST, RESPONSE, NATIVE, EVENT} = CONSTANTS.MESSAGES; +const { REQUEST, RESPONSE, NATIVE, EVENT } = MESSAGES; -const BID_WON = CONSTANTS.EVENTS.BID_WON; +const BID_WON = EVENTS.BID_WON; const HANDLER_MAP = { [REQUEST]: handleRenderRequest, @@ -99,7 +99,7 @@ function handleNativeRequest(reply, data, adObject) { return; } - if (adObject.status !== CONSTANTS.BID_STATUS.RENDERED) { + if (adObject.status !== BID_STATUS.RENDERED) { auctionManager.addWinningBid(adObject); events.emit(BID_WON, adObject); } @@ -121,7 +121,7 @@ function handleEventRequest(reply, data, adObject) { logError(`Cannot find ad '${data.adId}' for x-origin event request`); return; } - if (adObject.status !== CONSTANTS.BID_STATUS.RENDERED) { + if (adObject.status !== BID_STATUS.RENDERED) { logWarn(`Received x-origin event request without corresponding render request for ad '${adObject.adId}'`); return; } diff --git a/src/targeting.js b/src/targeting.js index ddbc3cebaf3..acb3ddb09ff 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -21,7 +21,7 @@ import {ADPOD} from './mediaTypes.js'; import {hook} from './hook.js'; import {bidderSettings} from './bidderSettings.js'; import {find, includes} from './polyfill.js'; -import CONSTANTS from './constants.json'; +import { BID_STATUS, JSON_MAPPING, DEFAULT_TARGETING_KEYS, TARGETING_KEYS, NATIVE_KEYS, STATUS } from './constants.js'; import {getHighestCpm, getOldestHighestCpmBid} from './utils/reducers.js'; import {getTTL} from './bidTTL.js'; @@ -33,19 +33,19 @@ const CFG_ALLOW_TARGETING_KEYS = `targetingControls.allowTargetingKeys`; const CFG_ADD_TARGETING_KEYS = `targetingControls.addTargetingKeys`; const TARGETING_KEY_CONFIGURATION_ERROR_MSG = `Only one of "${CFG_ALLOW_TARGETING_KEYS}" or "${CFG_ADD_TARGETING_KEYS}" can be set`; -export const TARGETING_KEYS = Object.keys(CONSTANTS.TARGETING_KEYS).map( - key => CONSTANTS.TARGETING_KEYS[key] +export const TARGETING_KEYS_ARR = Object.keys(TARGETING_KEYS).map( + key => TARGETING_KEYS[key] ); // return unexpired bids const isBidNotExpired = (bid) => (bid.responseTimestamp + getTTL(bid) * 1000) > timestamp(); // return bids whose status is not set. Winning bids can only have a status of `rendered`. -const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status); +const isUnusedBid = (bid) => bid && ((bid.status && !includes([BID_STATUS.RENDERED], bid.status)) || !bid.status); export let filters = { isActualBid(bid) { - return bid.getStatusCode() === CONSTANTS.STATUS.GOOD + return bid.getStatusCode() === STATUS.GOOD }, isBidNotExpired, isUnusedBid @@ -195,7 +195,7 @@ export function newTargeting(auctionManager) { */ function getDealBids(adUnitCodes, bidsReceived) { if (config.getConfig('targetingControls.alwaysIncludeDeals') === true) { - const standardKeys = FEATURES.NATIVE ? TARGETING_KEYS.concat(NATIVE_TARGETING_KEYS) : TARGETING_KEYS.slice(); + const standardKeys = FEATURES.NATIVE ? TARGETING_KEYS_ARR.concat(NATIVE_TARGETING_KEYS) : TARGETING_KEYS_ARR.slice(); // we only want the top bid from bidders who have multiple entries per ad unit code const bids = getHighestCpmBidsFromBidPool(bidsReceived, getHighestCpm); @@ -221,7 +221,7 @@ export function newTargeting(auctionManager) { * @return {targetingArray} filtered targeting */ function getAllowedTargetingKeyValues(targeting, allowedKeys) { - const defaultKeyring = Object.assign({}, CONSTANTS.TARGETING_KEYS, CONSTANTS.NATIVE_KEYS); + const defaultKeyring = Object.assign({}, TARGETING_KEYS, NATIVE_KEYS); const defaultKeys = Object.keys(defaultKeyring); const keyDispositions = {}; logInfo(`allowTargetingKeys - allowed keys [ ${allowedKeys.map(k => defaultKeyring[k]).join(', ')} ]`); @@ -282,7 +282,7 @@ export function newTargeting(auctionManager) { }); }); - const defaultKeys = Object.keys(Object.assign({}, CONSTANTS.DEFAULT_TARGETING_KEYS, CONSTANTS.NATIVE_KEYS)); + const defaultKeys = Object.keys(Object.assign({}, DEFAULT_TARGETING_KEYS, NATIVE_KEYS)); let allowedKeys = config.getConfig(CFG_ALLOW_TARGETING_KEYS); const addedKeys = config.getConfig(CFG_ADD_TARGETING_KEYS); @@ -547,7 +547,7 @@ export function newTargeting(auctionManager) { .reduce((acc, key) => { const targetingValue = [winner.adserverTargeting[key]]; const targeting = { [key.substring(0, MAX_DFP_KEYLENGTH)]: targetingValue }; - if (key === CONSTANTS.TARGETING_KEYS.DEAL) { + if (key === TARGETING_KEYS.DEAL) { const bidderCodeTargetingKey = `${key}_${winner.bidderCode}`.substring(0, MAX_DFP_KEYLENGTH); const bidderCodeTargeting = { [bidderCodeTargetingKey]: targetingValue }; return [...acc, targeting, bidderCodeTargeting]; @@ -563,7 +563,7 @@ export function newTargeting(auctionManager) { function getStandardKeys() { return auctionManager.getStandardBidderAdServerTargeting() // in case using a custom standard key set .map(targeting => targeting.key) - .concat(TARGETING_KEYS).filter(uniques); // standard keys defined in the library. + .concat(TARGETING_KEYS_ARR).filter(uniques); // standard keys defined in the library. } /** @@ -648,13 +648,13 @@ export function newTargeting(auctionManager) { * @return {targetingArray} all non-winning bids targeting */ function getBidLandscapeTargeting(adUnitCodes, bidsReceived) { - const standardKeys = FEATURES.NATIVE ? TARGETING_KEYS.concat(NATIVE_TARGETING_KEYS) : TARGETING_KEYS.slice(); + const standardKeys = FEATURES.NATIVE ? TARGETING_KEYS_ARR.concat(NATIVE_TARGETING_KEYS) : TARGETING_KEYS_ARR.slice(); const adUnitBidLimit = config.getConfig('sendBidsControl.bidLimit'); const bids = getHighestCpmBidsFromBidPool(bidsReceived, getHighestCpm, adUnitBidLimit); const allowSendAllBidsTargetingKeys = config.getConfig('targetingControls.allowSendAllBidsTargetingKeys'); const allowedSendAllBidTargeting = allowSendAllBidsTargetingKeys - ? allowSendAllBidsTargetingKeys.map((key) => CONSTANTS.TARGETING_KEYS[key]) + ? allowSendAllBidsTargetingKeys.map((key) => TARGETING_KEYS[key]) : standardKeys; // populate targeting keys for the remaining bids @@ -680,7 +680,7 @@ export function newTargeting(auctionManager) { function getAdUnitTargeting(adUnitCodes) { function getTargetingObj(adUnit) { - return deepAccess(adUnit, CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING); + return deepAccess(adUnit, JSON_MAPPING.ADSERVER_TARGETING); } function getTargetingValues(adUnit) { diff --git a/src/utils.js b/src/utils.js index c7ce5f22f9a..71cc78090a6 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,7 +1,7 @@ import {config} from './config.js'; import clone from 'just-clone'; import {includes} from './polyfill.js'; -import CONSTANTS from './constants.json'; +import { EVENTS, S2S } from './constants.js'; import {GreedyPromise} from './utils/promise.js'; import {getGlobal} from './prebidGlobal.js'; @@ -202,7 +202,7 @@ export function logWarn() { // eslint-disable-next-line no-console console.warn.apply(console, decorateLog(arguments, 'WARNING:')); } - emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'WARNING', arguments: arguments}); + emitEvent(EVENTS.AUCTION_DEBUG, { type: 'WARNING', arguments: arguments }); } export function logError() { @@ -210,7 +210,7 @@ export function logError() { // eslint-disable-next-line no-console console.error.apply(console, decorateLog(arguments, 'ERROR:')); } - emitEvent(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'ERROR', arguments: arguments}); + emitEvent(EVENTS.AUCTION_DEBUG, { type: 'ERROR', arguments: arguments }); } export function prefixLog(prefix) { @@ -444,7 +444,7 @@ export function triggerPixel(url, done, timeout) { } export function callBurl({ source, burl }) { - if (source === CONSTANTS.S2S.SRC && burl) { + if (source === S2S.SRC && burl) { internal.triggerPixel(burl); } } diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index 7317ea039d1..fb6cfe036e5 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -1,17 +1,17 @@ // jscs:disable -import CONSTANTS from 'src/constants.json'; +import { TARGETING_KEYS, STATUS } from 'src/constants.js'; import {createBid} from '../../src/bidfactory.js'; const utils = require('src/utils.js'); function convertTargetingsFromOldToNew(targetings) { var mapOfOldToNew = { - 'hb_bidder': CONSTANTS.TARGETING_KEYS.BIDDER, - 'hb_adid': CONSTANTS.TARGETING_KEYS.AD_ID, - 'hb_pb': CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, - 'hb_size': CONSTANTS.TARGETING_KEYS.SIZE, - 'hb_deal': CONSTANTS.TARGETING_KEYS.DEAL, - 'hb_source': CONSTANTS.TARGETING_KEYS.SOURCE, - 'hb_format': CONSTANTS.TARGETING_KEYS.FORMAT + 'hb_bidder': TARGETING_KEYS.BIDDER, + 'hb_adid': TARGETING_KEYS.AD_ID, + 'hb_pb': TARGETING_KEYS.PRICE_BUCKET, + 'hb_size': TARGETING_KEYS.SIZE, + 'hb_deal': TARGETING_KEYS.DEAL, + 'hb_source': TARGETING_KEYS.SOURCE, + 'hb_format': TARGETING_KEYS.FORMAT }; var newTargetings = {}; utils._each(targetings, function(value, currentKey) { @@ -1018,19 +1018,19 @@ export function getAdServerTargeting() { export function getTargetingKeys() { return [ [ - CONSTANTS.TARGETING_KEYS.BIDDER, + TARGETING_KEYS.BIDDER, 'appnexus' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID, + TARGETING_KEYS.AD_ID, '233bcbee889d46d' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + TARGETING_KEYS.PRICE_BUCKET, '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE, + TARGETING_KEYS.SIZE, '300x250' ], [ @@ -1045,19 +1045,19 @@ export function getTargetingKeys() { export function getTargetingKeysBidLandscape() { return [ [ - CONSTANTS.TARGETING_KEYS.BIDDER, + TARGETING_KEYS.BIDDER, 'appnexus' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus', + TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + TARGETING_KEYS.PRICE_BUCKET, '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE, + TARGETING_KEYS.SIZE, '300x250' ], [ @@ -1065,111 +1065,111 @@ export function getTargetingKeysBidLandscape() { ['0x0', '300x250', '300x600'] ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_triplelift', + TARGETING_KEYS.BIDDER + '_triplelift', 'triplelift' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_triplelift', + TARGETING_KEYS.AD_ID + '_triplelift', '222bb26f9e8bd' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_triplelift', + TARGETING_KEYS.PRICE_BUCKET + '_triplelift', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_triplelift', + TARGETING_KEYS.SIZE + '_triplelift', '0x0' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_appnexus', + TARGETING_KEYS.BIDDER + '_appnexus', 'appnexus' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus', + TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_appnexus', + TARGETING_KEYS.SIZE + '_appnexus', '300x250' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_pagescienc', + TARGETING_KEYS.BIDDER + '_pagescienc', 'pagescience' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_pagescience', + TARGETING_KEYS.AD_ID + '_pagescience', '25bedd4813632d7' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pagescience', + TARGETING_KEYS.PRICE_BUCKET + '_pagescience', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_pagescience', + TARGETING_KEYS.SIZE + '_pagescience', '300x250' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_brightcom', + TARGETING_KEYS.BIDDER + '_brightcom', 'brightcom' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_brightcom', + TARGETING_KEYS.AD_ID + '_brightcom', '26e0795ab963896' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brightcom', + TARGETING_KEYS.PRICE_BUCKET + '_brightcom', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_brightcom', + TARGETING_KEYS.SIZE + '_brightcom', '300x250' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_brealtime', + TARGETING_KEYS.BIDDER + '_brealtime', 'brealtime' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_brealtime', + TARGETING_KEYS.AD_ID + '_brealtime', '275bd666f5a5a5d' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brealtime', + TARGETING_KEYS.PRICE_BUCKET + '_brealtime', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_brealtime', + TARGETING_KEYS.SIZE + '_brealtime', '300x250' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_pubmatic', + TARGETING_KEYS.BIDDER + '_pubmatic', 'pubmatic' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_pubmatic', + TARGETING_KEYS.AD_ID + '_pubmatic', '28f4039c636b6a7' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pubmatic', + TARGETING_KEYS.PRICE_BUCKET + '_pubmatic', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_pubmatic', + TARGETING_KEYS.SIZE + '_pubmatic', '300x250' ], [ - CONSTANTS.TARGETING_KEYS.BIDDER + '_rubicon', + TARGETING_KEYS.BIDDER + '_rubicon', 'rubicon' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID + '_rubicon', + TARGETING_KEYS.AD_ID + '_rubicon', '29019e2ab586a5a' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon', + TARGETING_KEYS.PRICE_BUCKET + '_rubicon', '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE + '_rubicon', + TARGETING_KEYS.SIZE + '_rubicon', '300x600' ] ]; @@ -1262,7 +1262,7 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad if (typeof status !== 'undefined') { bid.status = status; } - return Object.assign(createBid(CONSTANTS.STATUS.GOOD), bid); + return Object.assign(createBid(STATUS.GOOD), bid); } export function getServerTestingsAds() { diff --git a/test/helpers/analytics.js b/test/helpers/analytics.js index b376118dc6f..d36bcf44f64 100644 --- a/test/helpers/analytics.js +++ b/test/helpers/analytics.js @@ -1,12 +1,12 @@ import * as pbEvents from 'src/events.js'; -import constants from '../../src/constants.json'; +import { EVENTS } from '../../src/constants.js'; export function fireEvents(events = [ - constants.EVENTS.AUCTION_INIT, - constants.EVENTS.AUCTION_END, - constants.EVENTS.BID_REQUESTED, - constants.EVENTS.BID_RESPONSE, - constants.EVENTS.BID_WON + EVENTS.AUCTION_INIT, + EVENTS.AUCTION_END, + EVENTS.BID_REQUESTED, + EVENTS.BID_RESPONSE, + EVENTS.BID_WON ]) { return events.map((ev, i) => { ev = Array.isArray(ev) ? ev : [ev, {i: i}]; diff --git a/test/spec/AnalyticsAdapter_spec.js b/test/spec/AnalyticsAdapter_spec.js index 62c00e04403..e853fb72fa8 100644 --- a/test/spec/AnalyticsAdapter_spec.js +++ b/test/spec/AnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import {server} from 'test/mocks/xhr.js'; import {disableAjaxForAnalytics, enableAjaxForAnalytics} from '../mocks/analyticsStub.js'; import {clearEvents} from 'src/events.js'; @@ -10,8 +10,8 @@ import { setDebounceDelay } from '../../libraries/analyticsAdapter/AnalyticsAdapter.js'; -const BID_WON = CONSTANTS.EVENTS.BID_WON; -const NO_BID = CONSTANTS.EVENTS.NO_BID; +const BID_WON = EVENTS.BID_WON; +const NO_BID = EVENTS.NO_BID; const AnalyticsAdapter = require('libraries/analyticsAdapter/AnalyticsAdapter.js').default; const config = { diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 06d3d538596..65c6256acdc 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -7,7 +7,7 @@ import { getPriceByGranularity, addBidResponse, resetAuctionState, responsesReady } from 'src/auction.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS, TARGETING_KEYS, S2S } from 'src/constants.js'; import * as auctionModule from 'src/auction.js'; import { registerBidder } from 'src/adapters/bidderFactory.js'; import { createBid } from 'src/bidfactory.js'; @@ -110,8 +110,8 @@ function mockBidRequest(bid, opts) { 'auctionId': opts && opts.auctionId, 'bidderRequestId': requestId, src: bid?._ctx?.src, - adUnitsS2SCopy: bid?._ctx?.src === CONSTANTS.S2S.SRC ? bid?._ctx?.adUnits : undefined, - uniquePbsTid: bid?._ctx?.src === CONSTANTS.S2S.SRC ? bid?._ctx?.uniquePbsTid : undefined, + adUnitsS2SCopy: bid?._ctx?.src === S2S.SRC ? bid?._ctx?.adUnits : undefined, + uniquePbsTid: bid?._ctx?.src === S2S.SRC ? bid?._ctx?.uniquePbsTid : undefined, 'bids': [ { 'bidder': bidderCode || bid.bidderCode, @@ -215,20 +215,20 @@ describe('auctionmanager.js', function () { /* return the expected response for a given bid, filter by keys if given */ function getDefaultExpected(bid, keys) { var expected = {}; - expected[ CONSTANTS.TARGETING_KEYS.BIDDER ] = bid.bidderCode; - expected[ CONSTANTS.TARGETING_KEYS.AD_ID ] = bid.adId; - expected[ CONSTANTS.TARGETING_KEYS.PRICE_BUCKET ] = bid.pbMg; - expected[ CONSTANTS.TARGETING_KEYS.SIZE ] = bid.getSize(); - expected[ CONSTANTS.TARGETING_KEYS.SOURCE ] = bid.source; - expected[ CONSTANTS.TARGETING_KEYS.FORMAT ] = bid.mediaType; - expected[ CONSTANTS.TARGETING_KEYS.ADOMAIN ] = bid.meta.advertiserDomains[0]; - expected[ CONSTANTS.TARGETING_KEYS.ACAT ] = bid.meta.primaryCatId; - expected[ CONSTANTS.TARGETING_KEYS.DSP ] = bid.meta.networkId; - expected[ CONSTANTS.TARGETING_KEYS.CRID ] = bid.creativeId; + expected[TARGETING_KEYS.BIDDER] = bid.bidderCode; + expected[TARGETING_KEYS.AD_ID] = bid.adId; + expected[TARGETING_KEYS.PRICE_BUCKET] = bid.pbMg; + expected[TARGETING_KEYS.SIZE] = bid.getSize(); + expected[TARGETING_KEYS.SOURCE] = bid.source; + expected[TARGETING_KEYS.FORMAT] = bid.mediaType; + expected[TARGETING_KEYS.ADOMAIN] = bid.meta.advertiserDomains[0]; + expected[TARGETING_KEYS.ACAT] = bid.meta.primaryCatId; + expected[TARGETING_KEYS.DSP] = bid.meta.networkId; + expected[TARGETING_KEYS.CRID] = bid.creativeId; if (bid.mediaType === 'video') { - expected[ CONSTANTS.TARGETING_KEYS.UUID ] = bid.videoCacheKey; - expected[ CONSTANTS.TARGETING_KEYS.CACHE_ID ] = bid.videoCacheKey; - expected[ CONSTANTS.TARGETING_KEYS.CACHE_HOST ] = 'prebid.adnxs.com'; + expected[TARGETING_KEYS.UUID] = bid.videoCacheKey; + expected[TARGETING_KEYS.CACHE_ID] = bid.videoCacheKey; + expected[TARGETING_KEYS.CACHE_HOST] = 'prebid.adnxs.com'; } if (!keys) { return expected; @@ -288,59 +288,59 @@ describe('auctionmanager.js', function () { standard: { adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return bidResponse.pbHg; } }, { - key: CONSTANTS.TARGETING_KEYS.SIZE, + key: TARGETING_KEYS.SIZE, val: function (bidResponse) { return bidResponse.size; } }, { - key: CONSTANTS.TARGETING_KEYS.SOURCE, + key: TARGETING_KEYS.SOURCE, val: function (bidResponse) { return bidResponse.source; } }, { - key: CONSTANTS.TARGETING_KEYS.FORMAT, + key: TARGETING_KEYS.FORMAT, val: function (bidResponse) { return bidResponse.mediaType; } }, { - key: CONSTANTS.TARGETING_KEYS.ADOMAIN, + key: TARGETING_KEYS.ADOMAIN, val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } }, { - key: CONSTANTS.TARGETING_KEYS.CRID, + key: TARGETING_KEYS.CRID, val: function (bidResponse) { return bidResponse.creativeId; } }, { - key: CONSTANTS.TARGETING_KEYS.DSP, + key: TARGETING_KEYS.DSP, val: function (bidResponse) { return bidResponse.meta.networkId; } }, { - key: CONSTANTS.TARGETING_KEYS.ACAT, + key: TARGETING_KEYS.ACAT, val: function (bidResponse) { return bidResponse.meta.primaryCatId; } @@ -351,7 +351,7 @@ describe('auctionmanager.js', function () { }; var expected = getDefaultExpected(bid); - expected[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] = bid.pbHg; + expected[TARGETING_KEYS.PRICE_BUCKET] = bid.pbHg; var response = getKeyValueTargetingPairs(bid.bidderCode, bid); assert.deepEqual(response, expected); @@ -373,70 +373,70 @@ describe('auctionmanager.js', function () { standard: { adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { return bidResponse.pbMg; } }, { - key: CONSTANTS.TARGETING_KEYS.SIZE, + key: TARGETING_KEYS.SIZE, val: function (bidResponse) { return bidResponse.size; } }, { - key: CONSTANTS.TARGETING_KEYS.SOURCE, + key: TARGETING_KEYS.SOURCE, val: function (bidResponse) { return bidResponse.source; } }, { - key: CONSTANTS.TARGETING_KEYS.FORMAT, + key: TARGETING_KEYS.FORMAT, val: function (bidResponse) { return bidResponse.mediaType; } }, { - key: CONSTANTS.TARGETING_KEYS.UUID, + key: TARGETING_KEYS.UUID, val: function (bidResponse) { return bidResponse.videoCacheKey; } }, { - key: CONSTANTS.TARGETING_KEYS.CACHE_ID, + key: TARGETING_KEYS.CACHE_ID, val: function (bidResponse) { return bidResponse.videoCacheKey; } }, { - key: CONSTANTS.TARGETING_KEYS.ADOMAIN, + key: TARGETING_KEYS.ADOMAIN, val: function (bidResponse) { return bidResponse.meta.advertiserDomains[0]; } }, { - key: CONSTANTS.TARGETING_KEYS.CRID, + key: TARGETING_KEYS.CRID, val: function (bidResponse) { return bidResponse.creativeId; } }, { - key: CONSTANTS.TARGETING_KEYS.DSP, + key: TARGETING_KEYS.DSP, val: function (bidResponse) { return bidResponse.meta.networkId; } }, { - key: CONSTANTS.TARGETING_KEYS.ACAT, + key: TARGETING_KEYS.ACAT, val: function (bidResponse) { return bidResponse.meta.primaryCatId; } @@ -459,23 +459,23 @@ describe('auctionmanager.js', function () { appnexus: { adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return bidResponse.pbHg; } }, { - key: CONSTANTS.TARGETING_KEYS.SIZE, + key: TARGETING_KEYS.SIZE, val: function (bidResponse) { return bidResponse.size; } @@ -486,7 +486,7 @@ describe('auctionmanager.js', function () { }; var expected = getDefaultExpected(bid); - expected[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] = bid.pbHg; + expected[TARGETING_KEYS.PRICE_BUCKET] = bid.pbHg; var response = getKeyValueTargetingPairs(bid.bidderCode, bid); assert.deepEqual(response, expected); @@ -498,23 +498,23 @@ describe('auctionmanager.js', function () { nonExistentBidder: { adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return bidResponse.pbHg; } }, { - key: CONSTANTS.TARGETING_KEYS.SIZE, + key: TARGETING_KEYS.SIZE, val: function (bidResponse) { return bidResponse.size; } @@ -561,17 +561,17 @@ describe('auctionmanager.js', function () { }, adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return 10.00; @@ -581,8 +581,8 @@ describe('auctionmanager.js', function () { } }; - var expected = getDefaultExpected(bid, [CONSTANTS.TARGETING_KEYS.BIDDER, CONSTANTS.TARGETING_KEYS.AD_ID]); - expected[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] = 10.0; + var expected = getDefaultExpected(bid, [TARGETING_KEYS.BIDDER, TARGETING_KEYS.AD_ID]); + expected[TARGETING_KEYS.PRICE_BUCKET] = 10.0; var response = getKeyValueTargetingPairs(bid.bidderCode, bid); assert.deepEqual(response, expected); @@ -618,17 +618,17 @@ describe('auctionmanager.js', function () { }, adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return 15.00; @@ -639,24 +639,24 @@ describe('auctionmanager.js', function () { standard: { adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { // change default here return 10.00; }, }, { - key: CONSTANTS.TARGETING_KEYS.SIZE, + key: TARGETING_KEYS.SIZE, val: function (bidResponse) { return bidResponse.size; } @@ -665,8 +665,8 @@ describe('auctionmanager.js', function () { } }; - var expected = getDefaultExpected(bid, [CONSTANTS.TARGETING_KEYS.BIDDER, CONSTANTS.TARGETING_KEYS.AD_ID, CONSTANTS.TARGETING_KEYS.SIZE]); - expected[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] = 15.0; + var expected = getDefaultExpected(bid, [TARGETING_KEYS.BIDDER, TARGETING_KEYS.AD_ID, TARGETING_KEYS.SIZE]); + expected[TARGETING_KEYS.PRICE_BUCKET] = 15.0; var response = getKeyValueTargetingPairs(bid.bidderCode, bid); assert.deepEqual(response, expected); @@ -679,17 +679,17 @@ describe('auctionmanager.js', function () { sendStandardTargeting: false, adserverTargeting: [ { - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: CONSTANTS.TARGETING_KEYS.AD_ID, + key: TARGETING_KEYS.AD_ID, val: function (bidResponse) { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function (bidResponse) { return bidResponse.pbHg; } @@ -698,7 +698,7 @@ describe('auctionmanager.js', function () { } }; var expected = getDefaultExpected(bid); - expected[CONSTANTS.TARGETING_KEYS.PRICE_BUCKET] = 5.57; + expected[TARGETING_KEYS.PRICE_BUCKET] = 5.57; var response = getKeyValueTargetingPairs(bid.bidderCode, bid); assert.deepEqual(response, expected); @@ -830,7 +830,7 @@ describe('auctionmanager.js', function () { } const auction = auctionManager.createAuction({adUnits, ortb2Fragments}); expect(auction.getNonBids()[0]).to.equal(undefined); - events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, { + events.emit(EVENTS.SEAT_NON_BID, { auctionId: auction.getAuctionId(), seatnonbid: ['test'] }); @@ -990,7 +990,7 @@ describe('auctionmanager.js', function () { auction.callBids(); let registeredBid = auction.getBidsReceived().pop(); - assert.equal(registeredBid.adserverTargeting[CONSTANTS.TARGETING_KEYS.DEAL], 'test deal', 'dealId placed in adserverTargeting'); + assert.equal(registeredBid.adserverTargeting[TARGETING_KEYS.DEAL], 'test deal', 'dealId placed in adserverTargeting'); }); it('should pass through default adserverTargeting sent from adapter', function () { @@ -999,7 +999,7 @@ describe('auctionmanager.js', function () { auction.callBids(); let registeredBid = auction.getBidsReceived().pop(); - assert.equal(registeredBid.adserverTargeting[CONSTANTS.TARGETING_KEYS.BIDDER], BIDDER_CODE); + assert.equal(registeredBid.adserverTargeting[TARGETING_KEYS.BIDDER], BIDDER_CODE); assert.equal(registeredBid.adserverTargeting.extra, 'stuff'); }); it('should add the bidResponse to the collection before calling BID_RESPONSE', function () { @@ -1008,9 +1008,9 @@ describe('auctionmanager.js', function () { const storedBid = auction.getBidsReceived().pop(); hasBid = storedBid === bid; } - events.on(CONSTANTS.EVENTS.BID_RESPONSE, eventHandler); + events.on(EVENTS.BID_RESPONSE, eventHandler); auction.callBids(); - events.off(CONSTANTS.EVENTS.BID_RESPONSE, eventHandler); + events.off(EVENTS.BID_RESPONSE, eventHandler); assert.ok(hasBid, 'Bid not available'); }); @@ -1231,10 +1231,10 @@ describe('auctionmanager.js', function () { let handler; beforeEach(() => { handler = sinon.spy(); - events.on(CONSTANTS.EVENTS.AUCTION_TIMEOUT, handler); + events.on(EVENTS.AUCTION_TIMEOUT, handler); }) afterEach(() => { - events.off(CONSTANTS.EVENTS.AUCTION_TIMEOUT, handler); + events.off(EVENTS.AUCTION_TIMEOUT, handler); }); Object.entries({ @@ -1257,14 +1257,14 @@ describe('auctionmanager.js', function () { it('should emit BID_TIMEOUT and AUCTION_END for timed out bids', function () { const pm = runAuction().then(() => { - const bidTimeoutCall = eventsEmitSpy.withArgs(CONSTANTS.EVENTS.BID_TIMEOUT).getCalls()[0]; + const bidTimeoutCall = eventsEmitSpy.withArgs(EVENTS.BID_TIMEOUT).getCalls()[0]; const timedOutBids = bidTimeoutCall.args[1]; assert.equal(timedOutBids.length, 1); assert.equal(timedOutBids[0].bidder, BIDDER_CODE1); // Check that additional properties are available assert.equal(timedOutBids[0].params[0].placementId, 'id'); - const auctionEndCall = eventsEmitSpy.withArgs(CONSTANTS.EVENTS.AUCTION_END).getCalls()[0]; + const auctionEndCall = eventsEmitSpy.withArgs(EVENTS.AUCTION_END).getCalls()[0]; const auctionProps = auctionEndCall.args[1]; assert.equal(auctionProps.adUnits, adUnits); assert.equal(auctionProps.timeout, 20); @@ -1276,7 +1276,7 @@ describe('auctionmanager.js', function () { it('should NOT emit BID_TIMEOUT when all bidders responded in time', function () { const pm = runAuction().then(() => { - assert.ok(eventsEmitSpy.withArgs(CONSTANTS.EVENTS.BID_TIMEOUT).notCalled, 'did not emit event BID_TIMEOUT'); + assert.ok(eventsEmitSpy.withArgs(EVENTS.BID_TIMEOUT).notCalled, 'did not emit event BID_TIMEOUT'); }); respondToRequest(0); respondToRequest(1); @@ -1285,7 +1285,7 @@ describe('auctionmanager.js', function () { it('should NOT emit BID_TIMEOUT for bidders which responded in time but with an empty bid', function () { const pm = runAuction().then(() => { - const bidTimeoutCall = eventsEmitSpy.withArgs(CONSTANTS.EVENTS.BID_TIMEOUT).getCalls()[0]; + const bidTimeoutCall = eventsEmitSpy.withArgs(EVENTS.BID_TIMEOUT).getCalls()[0]; const timedOutBids = bidTimeoutCall.args[1]; assert.equal(timedOutBids.length, 1); assert.equal(timedOutBids[0].bidder, BIDDER_CODE1); @@ -1314,8 +1314,8 @@ describe('auctionmanager.js', function () { adUnits[0].bids.push({bidder: 'mock-s2s-1'}, {bidder: 'mock-s2s-2'}) const s2sAdUnits = deepClone(adUnits); bids.unshift( - mockBid({bidderCode: 'mock-s2s-1', src: CONSTANTS.S2S.SRC, adUnits: s2sAdUnits, uniquePbsTid: '1'}), - mockBid({bidderCode: 'mock-s2s-2', src: CONSTANTS.S2S.SRC, adUnits: s2sAdUnits, uniquePbsTid: '2'}) + mockBid({ bidderCode: 'mock-s2s-1', src: S2S.SRC, adUnits: s2sAdUnits, uniquePbsTid: '1' }), + mockBid({ bidderCode: 'mock-s2s-2', src: S2S.SRC, adUnits: s2sAdUnits, uniquePbsTid: '2' }) ); Object.assign(s2sAdUnits[0], { mediaTypes: { @@ -1336,7 +1336,7 @@ describe('auctionmanager.js', function () { }) const pm = runAuction().then(() => { - const toBids = eventsEmitSpy.withArgs(CONSTANTS.EVENTS.BID_TIMEOUT).getCalls()[0].args[1] + const toBids = eventsEmitSpy.withArgs(EVENTS.BID_TIMEOUT).getCalls()[0].args[1] expect(toBids.map(bid => bid.bidder)).to.eql([ 'mock-s2s-2', BIDDER_CODE, @@ -1906,12 +1906,12 @@ describe('auctionmanager.js', function () { before(() => { addBidResponse.before(rejectHook, 999); - events.on(CONSTANTS.EVENTS.BID_REJECTED, onBidRejected); + events.on(EVENTS.BID_REJECTED, onBidRejected); }); after(() => { addBidResponse.getHooks({hook: rejectHook}).remove(); - events.off(CONSTANTS.EVENTS.BID_REJECTED, onBidRejected); + events.off(EVENTS.BID_REJECTED, onBidRejected); }); beforeEach(() => { diff --git a/test/spec/modules/33acrossAnalyticsAdapter_spec.js b/test/spec/modules/33acrossAnalyticsAdapter_spec.js index 9e0d928cd97..5089f12a461 100644 --- a/test/spec/modules/33acrossAnalyticsAdapter_spec.js +++ b/test/spec/modules/33acrossAnalyticsAdapter_spec.js @@ -4,10 +4,9 @@ import { log } from 'modules/33acrossAnalyticsAdapter.js'; import * as mockGpt from 'test/spec/integration/faker/googletag.js'; import * as events from 'src/events.js'; import * as faker from 'faker'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import { gdprDataHandler, gppDataHandler, uspDataHandler } from '../../../src/adapterManager'; import { DEFAULT_ENDPOINT, POST_GAM_TIMEOUT, locals } from '../../../modules/33acrossAnalyticsAdapter'; -const { EVENTS, BID_STATUS } = CONSTANTS; describe('33acrossAnalyticsAdapter:', function () { let sandbox; diff --git a/test/spec/modules/adWMGAnalyticsAdapter_spec.js b/test/spec/modules/adWMGAnalyticsAdapter_spec.js index 1e0da1bb3c8..92e1fcbe4db 100644 --- a/test/spec/modules/adWMGAnalyticsAdapter_spec.js +++ b/test/spec/modules/adWMGAnalyticsAdapter_spec.js @@ -2,9 +2,9 @@ import adWMGAnalyticsAdapter from 'modules/adWMGAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; import {expectEvents} from '../../helpers/analytics.js'; +import {EVENTS} from 'src/constants.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); describe('adWMG Analytics', function () { let timestamp = new Date() - 256; @@ -142,31 +142,31 @@ describe('adWMG Analytics', function () { }); expectEvents([ - [constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}], - [constants.EVENTS.BID_REQUESTED, {}], - [constants.EVENTS.BID_RESPONSE, bidResponse], - [constants.EVENTS.NO_BID, {}], - [constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs], - [constants.EVENTS.AUCTION_END, {}], - [constants.EVENTS.BID_WON, wonRequest], + [EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}], + [EVENTS.BID_REQUESTED, {}], + [EVENTS.BID_RESPONSE, bidResponse], + [EVENTS.NO_BID, {}], + [EVENTS.BID_TIMEOUT, bidTimeoutArgs], + [EVENTS.AUCTION_END, {}], + [EVENTS.BID_WON, wonRequest], ]).to.beTrackedBy(adWMGAnalyticsAdapter.track); }); it('should be two xhr requests', function () { - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.AUCTION_END, {}); + events.emit(EVENTS.BID_WON, wonRequest); expect(server.requests.length).to.equal(2); }); it('second request should be bidWon', function () { - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.AUCTION_END, {}); + events.emit(EVENTS.BID_WON, wonRequest); expect(JSON.parse(server.requests[1].requestBody).events[0].status).to.equal(expectedBidWonData.events[0].status); }); it('check bidWon data', function () { - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.AUCTION_END, {}); + events.emit(EVENTS.BID_WON, wonRequest); let realBidWonData = JSON.parse(server.requests[1].requestBody); expect(realBidWonData.publisher_id).to.equal(expectedBidWonData.publisher_id); expect(realBidWonData.site).to.equal(expectedBidWonData.site); diff --git a/test/spec/modules/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index 64740f32b06..c14393e267b 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -3,10 +3,10 @@ import { expect } from 'chai'; import * as utils from 'src/utils.js'; import { server } from 'test/mocks/xhr.js'; import * as prebidGlobal from 'src/prebidGlobal.js'; +import { EVENTS } from 'src/constants.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); describe('adagio analytics adapter - adagio.js', () => { let sandbox; @@ -86,9 +86,9 @@ describe('adagio analytics adapter - adagio.js', () => { }; const testEvents = { - [constants.EVENTS.BID_REQUESTED]: bidRequest, - [constants.EVENTS.BID_RESPONSE]: bidResponse, - [constants.EVENTS.AUCTION_END]: {} + [EVENTS.BID_REQUESTED]: bidRequest, + [EVENTS.BID_RESPONSE]: bidResponse, + [EVENTS.AUCTION_END]: {} }; // Step 1-3: Send events @@ -162,13 +162,13 @@ describe('adagio analytics adapter - adagio.js', () => { }; // Step 1: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); // Step 2: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // Step 3: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); utils.getWindowTop.restore(); @@ -661,12 +661,12 @@ describe('adagio analytics adapter', () => { } }); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END.another); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON.another); - events.emit(constants.EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END.another); + events.emit(EVENTS.BID_WON, MOCK.BID_WON.another); + events.emit(EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); expect(server.requests.length).to.equal(3, 'requests count'); { @@ -733,13 +733,13 @@ describe('adagio analytics adapter', () => { } }); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.bidcached); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END.another_nobid); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON.bidcached); - events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED.bidcached); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.bidcached); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END.another_nobid); + events.emit(EVENTS.BID_WON, MOCK.BID_WON.bidcached); + events.emit(EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED.bidcached); expect(server.requests.length).to.equal(5, 'requests count'); { @@ -831,12 +831,12 @@ describe('adagio analytics adapter', () => { it('send an "empty" cpm when adserver currency != USD and convertCurrency() is undefined', () => { sandbox.stub(prebidGlobal, 'getGlobal').returns({}); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END.another); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON.another); - events.emit(constants.EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT.another); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.adagio); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE.another); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END.another); + events.emit(EVENTS.BID_WON, MOCK.BID_WON.another); + events.emit(EVENTS.AD_RENDER_SUCCEEDED, MOCK.AD_RENDER_SUCCEEDED.another); expect(server.requests.length).to.equal(3, 'requests count'); diff --git a/test/spec/modules/adkernelAdnAnalytics_spec.js b/test/spec/modules/adkernelAdnAnalytics_spec.js index 7af96c9321c..fc6cba5176b 100644 --- a/test/spec/modules/adkernelAdnAnalytics_spec.js +++ b/test/spec/modules/adkernelAdnAnalytics_spec.js @@ -1,7 +1,7 @@ import analyticsAdapter, {ExpiringQueue, getUmtSource, storage} from 'modules/adkernelAdnAnalyticsAdapter'; import {expect} from 'chai'; import adapterManager from 'src/adapterManager'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; const events = require('../../../src/events'); @@ -230,21 +230,21 @@ describe('', function () { }); it('should handle auction init event', function () { - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {config: {}, bidderRequests: [REQUEST], timeout: 3000}); + events.emit(EVENTS.AUCTION_INIT, {config: {}, bidderRequests: [REQUEST], timeout: 3000}); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(1); expect(ev[0]).to.be.eql({event: 'auctionInit'}); }); it('should handle bid request event', function () { - events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST); + events.emit(EVENTS.BID_REQUESTED, REQUEST); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(2); expect(ev[1]).to.be.eql({event: 'bidRequested', adapter: 'adapter', tagid: 'container-1'}); }); it('should handle bid response event', function () { - events.emit(CONSTANTS.EVENTS.BID_RESPONSE, RESPONSE); + events.emit(EVENTS.BID_RESPONSE, RESPONSE); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(3); expect(ev[2]).to.be.eql({ @@ -258,7 +258,7 @@ describe('', function () { it('should handle auction end event', function () { timer.tick(447); - events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE); + events.emit(EVENTS.AUCTION_END, RESPONSE); let ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(0); expect(ajaxStub.calledOnce).to.be.equal(true); @@ -267,7 +267,7 @@ describe('', function () { }); it('should handle winning bid', function () { - events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE); + events.emit(EVENTS.BID_WON, RESPONSE); timer.tick(4500); expect(ajaxStub.calledTwice).to.be.equal(true); let ev = JSON.parse(ajaxStub.secondCall.args[0]).hb_ev; diff --git a/test/spec/modules/adlooxAnalyticsAdapter_spec.js b/test/spec/modules/adlooxAnalyticsAdapter_spec.js index 8acd02c7f26..450dd83f86d 100644 --- a/test/spec/modules/adlooxAnalyticsAdapter_spec.js +++ b/test/spec/modules/adlooxAnalyticsAdapter_spec.js @@ -3,7 +3,7 @@ import analyticsAdapter, { command as analyticsCommand, COMMAND } from 'modules/ import { AUCTION_COMPLETED } from 'src/auction.js'; import { expect } from 'chai'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import * as utils from 'src/utils.js'; import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; @@ -143,10 +143,10 @@ describe('Adloox Analytics Adapter', function () { return arg.tagName === 'LINK' && arg.getAttribute('rel') === 'preload' && arg.getAttribute('as') === 'script' && href_uri.href === uri.href; }; - events.emit(CONSTANTS.EVENTS.AUCTION_END, auctionDetails); + events.emit(EVENTS.AUCTION_END, auctionDetails); expect(insertElementStub.calledWith(sinon.match(isLinkPreloadAsScript))).to.true; - events.emit(CONSTANTS.EVENTS.AUCTION_END, auctionDetails); + events.emit(EVENTS.AUCTION_END, auctionDetails); expect(insertElementStub.callCount).to.equal(1); done(); @@ -167,7 +167,7 @@ describe('Adloox Analytics Adapter', function () { const querySelectorStub = sandbox.stub(document, 'querySelector'); querySelectorStub.withArgs(`#${bid.adUnitCode}`).returns(slot); - events.emit(CONSTANTS.EVENTS.BID_WON, bid); + events.emit(EVENTS.BID_WON, bid); const [urlInserted, moduleCode] = loadExternalScriptStub.getCall(0).args; @@ -196,7 +196,7 @@ describe('Adloox Analytics Adapter', function () { const querySelectorStub = sandbox.stub(document, 'querySelector'); querySelectorStub.withArgs(`#${bid.adUnitCode}`).returns(slot); - events.emit(CONSTANTS.EVENTS.BID_WON, bidIgnore); + events.emit(EVENTS.BID_WON, bidIgnore); expect(parent.querySelector('script')).is.null; @@ -238,7 +238,7 @@ describe('Adloox Analytics Adapter', function () { it('should inject tracking event', function (done) { const data = { - eventType: CONSTANTS.EVENTS.BID_WON, + eventType: EVENTS.BID_WON, args: bid }; diff --git a/test/spec/modules/adomikAnalyticsAdapter_spec.js b/test/spec/modules/adomikAnalyticsAdapter_spec.js index d872d6f8e08..703e6ed8992 100644 --- a/test/spec/modules/adomikAnalyticsAdapter_spec.js +++ b/test/spec/modules/adomikAnalyticsAdapter_spec.js @@ -1,9 +1,9 @@ import adomikAnalytics from 'modules/adomikAnalyticsAdapter.js'; import { expect } from 'chai'; +import {EVENTS} from 'src/constants.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); describe('Adomik Prebid Analytic', function () { let sendEventStub; @@ -70,7 +70,7 @@ describe('Adomik Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, auctionId: 'test-test-test'}); + events.emit(EVENTS.AUCTION_INIT, {config: initOptions, auctionId: 'test-test-test'}); expect(adomikAnalytics.currentContext).to.deep.equal({ uid: '123456', @@ -81,7 +81,7 @@ describe('Adomik Prebid Analytic', function () { }); // Step 3: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, { bids: [bid] }); + events.emit(EVENTS.BID_REQUESTED, { bids: [bid] }); expect(adomikAnalytics.bucketEvents.length).to.equal(1); expect(adomikAnalytics.bucketEvents[0]).to.deep.equal({ @@ -93,7 +93,7 @@ describe('Adomik Prebid Analytic', function () { }); // Step 4: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bid); + events.emit(EVENTS.BID_RESPONSE, bid); expect(adomikAnalytics.bucketEvents.length).to.equal(2); expect(adomikAnalytics.bucketEvents[1]).to.deep.equal({ @@ -114,17 +114,17 @@ describe('Adomik Prebid Analytic', function () { }); // Step 5: Send bid won event - events.emit(constants.EVENTS.BID_WON, bid); + events.emit(EVENTS.BID_WON, bid); expect(adomikAnalytics.bucketEvents.length).to.equal(2); // Step 6: Send bid timeout event - events.emit(constants.EVENTS.BID_TIMEOUT, {}); + events.emit(EVENTS.BID_TIMEOUT, {}); expect(adomikAnalytics.currentContext.timeouted).to.equal(true); // Step 7: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); setTimeout(function() { sinon.assert.callCount(sendEventStub, 1); diff --git a/test/spec/modules/adxcgAnalyticsAdapter_spec.js b/test/spec/modules/adxcgAnalyticsAdapter_spec.js index a796e7e966d..40e1347bce3 100644 --- a/test/spec/modules/adxcgAnalyticsAdapter_spec.js +++ b/test/spec/modules/adxcgAnalyticsAdapter_spec.js @@ -2,9 +2,9 @@ import adxcgAnalyticsAdapter from 'modules/adxcgAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('adxcg analytics adapter', function () { beforeEach(function () { @@ -171,21 +171,21 @@ describe('adxcg analytics adapter', function () { it('builds and sends auction data', function () { // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { timestamp: auctionTimestamp }); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); + events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); expect(server.requests.length).to.equal(1); @@ -196,7 +196,7 @@ describe('adxcg analytics adapter', function () { expect(realAfterBid.bidTimeout).to.deep.equal(['bidderOne', 'bidderTwo']); // Step 6: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.BID_WON, wonRequest); expect(server.requests.length).to.equal(2); let winEventData = JSON.parse(server.requests[1].requestBody); diff --git a/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js b/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js index fd698e9e1fd..fe453a1c208 100644 --- a/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js +++ b/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js @@ -3,9 +3,9 @@ import { testSend } from 'modules/adxpremiumAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('AdxPremium analytics adapter', function () { beforeEach(function () { @@ -378,19 +378,19 @@ describe('AdxPremium analytics adapter', function () { it('builds and sends auction data', function () { // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); + events.emit(EVENTS.AUCTION_INIT, auctionInit); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); + events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); testSend(); @@ -404,7 +404,7 @@ describe('AdxPremium analytics adapter', function () { expect(realAfterBid).to.deep.equal(expectedAfterTimeout); // Step 6: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.BID_WON, wonRequest); expect(server.requests.length).to.equal(3); let winEventData = JSON.parse(server.requests[1].requestBody); diff --git a/test/spec/modules/agmaAnalyticsAdapter_spec.js b/test/spec/modules/agmaAnalyticsAdapter_spec.js index df18e7bcf45..227acacde12 100644 --- a/test/spec/modules/agmaAnalyticsAdapter_spec.js +++ b/test/spec/modules/agmaAnalyticsAdapter_spec.js @@ -7,7 +7,7 @@ import agmaAnalyticsAdapter, { import { gdprDataHandler } from '../../../src/adapterManager.js'; import { expect } from 'chai'; import * as events from '../../../src/events.js'; -import constants from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { generateUUID } from '../../../src/utils.js'; import { server } from '../../mocks/xhr.js'; import { config } from 'src/config.js'; @@ -281,22 +281,22 @@ describe('AGMA Analytics Adapter', () => { auctionId: generateUUID(), }; - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { auctionId: generateUUID('1'), auction, }); clock.tick(200); - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { auctionId: generateUUID('2'), auction, }); - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { auctionId: generateUUID('3'), auction, }); - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { auctionId: generateUUID('4'), auction, }); @@ -307,7 +307,7 @@ describe('AGMA Analytics Adapter', () => { const requestBody = JSON.parse(request.requestBody); expect(request.url).to.equal(INGEST_URL); expect(requestBody).to.have.all.keys(extendedKey); - expect(requestBody.triggerEvent).to.equal(constants.EVENTS.AUCTION_INIT); + expect(requestBody.triggerEvent).to.equal(EVENTS.AUCTION_INIT); expect(server.requests).to.have.length(1); }); @@ -327,14 +327,14 @@ describe('AGMA Analytics Adapter', () => { auctionId: generateUUID(), }; - events.emit(constants.EVENTS.AUCTION_INIT, auction); + events.emit(EVENTS.AUCTION_INIT, auction); clock.tick(1100); const [request] = server.requests; const requestBody = JSON.parse(request.requestBody); expect(request.url).to.equal(INGEST_URL); expect(requestBody).to.have.all.keys(extendedKey); - expect(requestBody.triggerEvent).to.equal(constants.EVENTS.AUCTION_INIT); + expect(requestBody.triggerEvent).to.equal(EVENTS.AUCTION_INIT); expect(requestBody.deviceWidth).to.equal(screen.width); expect(requestBody.deviceHeight).to.equal(screen.height); expect(server.requests).to.have.length(1); @@ -351,13 +351,13 @@ describe('AGMA Analytics Adapter', () => { auctionId: generateUUID(), }; - events.emit(constants.EVENTS.AUCTION_INIT, auction); + events.emit(EVENTS.AUCTION_INIT, auction); clock.tick(1000); const [request] = server.requests; const requestBody = JSON.parse(request.requestBody); expect(request.url).to.equal(INGEST_URL); - expect(requestBody.triggerEvent).to.equal(constants.EVENTS.AUCTION_INIT); + expect(requestBody.triggerEvent).to.equal(EVENTS.AUCTION_INIT); expect(server.requests).to.have.length(1); expect(agmaAnalyticsAdapter.auctionIds).to.have.length(0); }); @@ -369,22 +369,22 @@ describe('AGMA Analytics Adapter', () => { provider: 'agma', options: { code: 'test', - triggerEvent: constants.EVENTS.AUCTION_END + triggerEvent: EVENTS.AUCTION_END }, }); const auction = { auctionId: generateUUID(), }; - events.emit(constants.EVENTS.AUCTION_INIT, auction); - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_INIT, auction); + events.emit(EVENTS.AUCTION_END, auction); clock.tick(1000); const [request] = server.requests; const requestBody = JSON.parse(request.requestBody); expect(request.url).to.equal(INGEST_URL); expect(requestBody.auctionIds).to.have.length(1); - expect(requestBody.triggerEvent).to.equal(constants.EVENTS.AUCTION_END); + expect(requestBody.triggerEvent).to.equal(EVENTS.AUCTION_END); expect(server.requests).to.have.length(1); expect(agmaAnalyticsAdapter.auctionIds).to.have.length(0); }); diff --git a/test/spec/modules/appierAnalyticsAdapter_spec.js b/test/spec/modules/appierAnalyticsAdapter_spec.js index cd026f64d49..e380672b73c 100644 --- a/test/spec/modules/appierAnalyticsAdapter_spec.js +++ b/test/spec/modules/appierAnalyticsAdapter_spec.js @@ -4,7 +4,7 @@ import { } from 'modules/appierAnalyticsAdapter.js'; import {expect} from 'chai'; const events = require('src/events'); -const constants = require('src/constants.json'); +const constants = require('src/constants.js'); const affiliateId = 'WhctHaViHtI'; const configId = 'd9cc9a9be9b240eda17cf1c9a8a4b29c'; diff --git a/test/spec/modules/asteriobidAnalyticsAdapter_spec.js b/test/spec/modules/asteriobidAnalyticsAdapter_spec.js index 9be6c1dedac..7c336d2a885 100644 --- a/test/spec/modules/asteriobidAnalyticsAdapter_spec.js +++ b/test/spec/modules/asteriobidAnalyticsAdapter_spec.js @@ -3,9 +3,9 @@ import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; import * as utils from 'src/utils.js'; import {expectEvents} from '../../helpers/analytics.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('AsterioBid Analytics Adapter', function () { let bidWonEvent = { @@ -66,7 +66,7 @@ describe('AsterioBid Analytics Adapter', function () { } }); - events.emit(constants.EVENTS.BID_WON, bidWonEvent); + events.emit(EVENTS.BID_WON, bidWonEvent); asteriobidAnalytics.flush(); expect(server.requests.length).to.equal(1); diff --git a/test/spec/modules/atsAnalyticsAdapter_spec.js b/test/spec/modules/atsAnalyticsAdapter_spec.js index 2316f96ec8e..3440cb1efbb 100644 --- a/test/spec/modules/atsAnalyticsAdapter_spec.js +++ b/test/spec/modules/atsAnalyticsAdapter_spec.js @@ -5,10 +5,10 @@ import {server} from '../../mocks/xhr.js'; import {parseBrowser} from '../../../modules/atsAnalyticsAdapter.js'; import {getCoreStorageManager, getStorageManager} from '../../../src/storageManager.js'; import {analyticsUrl} from '../../../modules/atsAnalyticsAdapter.js'; -let utils = require('src/utils'); +import {EVENTS} from 'src/constants.js'; +let utils = require('src/utils'); let events = require('src/events'); -let constants = require('src/constants.json'); const storage = getCoreStorageManager(); let sandbox; @@ -160,22 +160,22 @@ describe('ats analytics adapter', function () { }); // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { timestamp: auctionTimestamp }); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); + events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); // Step 6: Send bid won event - events.emit(constants.EVENTS.BID_WON, wonRequest); + events.emit(EVENTS.BID_WON, wonRequest); sandbox.stub($$PREBID_GLOBAL$$, 'getAllWinningBids').callsFake((key) => { return [wonRequest] diff --git a/test/spec/modules/automatadAnalyticsAdapter_spec.js b/test/spec/modules/automatadAnalyticsAdapter_spec.js index a7dd28a8dc0..8b566280cc6 100644 --- a/test/spec/modules/automatadAnalyticsAdapter_spec.js +++ b/test/spec/modules/automatadAnalyticsAdapter_spec.js @@ -3,7 +3,7 @@ import * as utils from 'src/utils.js'; import spec, {self as exports} from 'modules/automatadAnalyticsAdapter.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import { expect } from 'chai'; const obj = { @@ -28,7 +28,7 @@ const { BID_TIMEOUT, BID_WON, NO_BID -} = CONSTANTS.EVENTS +} = EVENTS const CONFIG_WITH_DEBUG = { provider: 'atmtdAnalyticsAdapter', diff --git a/test/spec/modules/bidViewabilityIO_spec.js b/test/spec/modules/bidViewabilityIO_spec.js index 5b4944082bc..e18d3bdca58 100644 --- a/test/spec/modules/bidViewabilityIO_spec.js +++ b/test/spec/modules/bidViewabilityIO_spec.js @@ -3,7 +3,7 @@ import * as events from 'src/events.js'; import * as utils from 'src/utils.js'; import * as sinon from 'sinon'; import { expect } from 'chai'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; describe('#bidViewabilityIO', function() { const makeElement = (id) => { @@ -97,7 +97,7 @@ describe('#bidViewabilityIO', function() { expect(mockObserver.unobserve.calledOnce).to.be.true; expect(emitSpy.calledOnce).to.be.true; // expect(emitSpy.firstCall.args).to.be.false; - expect(emitSpy.firstCall.args[0]).to.eq(CONSTANTS.EVENTS.BID_VIEWABLE); + expect(emitSpy.firstCall.args[0]).to.eq(EVENTS.BID_VIEWABLE); }); }) diff --git a/test/spec/modules/bidViewability_spec.js b/test/spec/modules/bidViewability_spec.js index 2d2e51abbe1..1df9aecf73a 100644 --- a/test/spec/modules/bidViewability_spec.js +++ b/test/spec/modules/bidViewability_spec.js @@ -5,7 +5,7 @@ import * as utils from 'src/utils.js'; import * as sinon from 'sinon'; import {expect, spy} from 'chai'; import * as prebidGlobal from 'src/prebidGlobal.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import adapterManager, { gdprDataHandler, uspDataHandler } from 'src/adapterManager.js'; import parse from 'url-parse'; @@ -292,9 +292,9 @@ describe('#bidViewability', function() { let call = callBidViewableBidderSpy.getCall(0); expect(call.args[0]).to.equal(PBJS_WINNING_BID.bidder); expect(call.args[1]).to.deep.equal(PBJS_WINNING_BID); - // CONSTANTS.EVENTS.BID_VIEWABLE is triggered + // EVENTS.BID_VIEWABLE is triggered call = eventsEmitSpy.getCall(0); - expect(call.args[0]).to.equal(CONSTANTS.EVENTS.BID_VIEWABLE); + expect(call.args[0]).to.equal(EVENTS.BID_VIEWABLE); expect(call.args[1]).to.deep.equal(PBJS_WINNING_BID); }); @@ -303,7 +303,7 @@ describe('#bidViewability', function() { expect(triggerPixelSpy.callCount).to.equal(0); // adapterManager.callBidViewableBidder is NOT called expect(callBidViewableBidderSpy.callCount).to.equal(0); - // CONSTANTS.EVENTS.BID_VIEWABLE is NOT triggered + // EVENTS.BID_VIEWABLE is NOT triggered expect(eventsEmitSpy.callCount).to.equal(0); }); diff --git a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js index be1ffb06c76..d934a6c611b 100644 --- a/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +++ b/test/spec/modules/bidwatchAnalyticsAdapter_spec.js @@ -2,9 +2,10 @@ import bidwatchAnalytics from 'modules/bidwatchAnalyticsAdapter.js'; import {dereferenceWithoutRenderer} from 'modules/bidwatchAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; + let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); describe('BidWatch Analytics', function () { let timestamp = new Date() - 256; @@ -301,10 +302,10 @@ describe('BidWatch Analytics', function () { } }); - events.emit(constants.EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); - events.emit(constants.EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); + events.emit(EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); expect(server.requests.length).to.equal(1); let message = JSON.parse(server.requests[0].requestBody); expect(message).to.have.property('auctionEnd').exist; @@ -331,7 +332,7 @@ describe('BidWatch Analytics', function () { domain: 'test' } }); - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests.length).to.equal(1); let message = JSON.parse(server.requests[0].requestBody); expect(message).not.to.have.property('ad'); diff --git a/test/spec/modules/byDataAnalyticsAdapter_spec.js b/test/spec/modules/byDataAnalyticsAdapter_spec.js index c680c687a71..b98b5cb7039 100644 --- a/test/spec/modules/byDataAnalyticsAdapter_spec.js +++ b/test/spec/modules/byDataAnalyticsAdapter_spec.js @@ -1,8 +1,9 @@ import ascAdapter from 'modules/byDataAnalyticsAdapter'; import { expect } from 'chai'; +import {EVENTS} from 'src/constants.js'; + let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); let auctionId = 'b70ef967-5c5b-4602-831e-f2cf16e59af2'; const initOptions = { clientId: 'asc00000', @@ -176,9 +177,9 @@ describe('byData Analytics Adapter ', () => { }); }); it('sends and formatted auction data ', function () { - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs); - events.emit(constants.EVENTS.NO_BID, noBidArgs); - events.emit(constants.EVENTS.BID_WON, bidWonArgs) + events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgs); + events.emit(EVENTS.NO_BID, noBidArgs); + events.emit(EVENTS.BID_WON, bidWonArgs) var userToken = ascAdapter.getVisitorData(userData); var newAuData = ascAdapter.dataProcess(auctionEndArgs); var newBwData = ascAdapter.getBidWonData(bidWonArgs); diff --git a/test/spec/modules/cleanioRtdProvider_spec.js b/test/spec/modules/cleanioRtdProvider_spec.js index 1d21fbd8457..3145108c373 100644 --- a/test/spec/modules/cleanioRtdProvider_spec.js +++ b/test/spec/modules/cleanioRtdProvider_spec.js @@ -2,7 +2,7 @@ import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; import * as utils from '../../../src/utils.js'; import * as hook from '../../../src/hook.js' import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { __TEST__ } from '../../../modules/cleanioRtdProvider.js'; @@ -193,16 +193,16 @@ describe('clean.io RTD module', function () { const eventCounter = { registerCleanioBillingEvent: function() {} }; sinon.spy(eventCounter, 'registerCleanioBillingEvent'); - events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, (evt) => { + events.on(EVENTS.BILLABLE_EVENT, (evt) => { if (evt.vendor === 'clean.io') { eventCounter.registerCleanioBillingEvent() } }); - events.emit(CONSTANTS.EVENTS.BID_WON, {}); - events.emit(CONSTANTS.EVENTS.BID_WON, {}); - events.emit(CONSTANTS.EVENTS.BID_WON, {}); - events.emit(CONSTANTS.EVENTS.BID_WON, {}); + events.emit(EVENTS.BID_WON, {}); + events.emit(EVENTS.BID_WON, {}); + events.emit(EVENTS.BID_WON, {}); + events.emit(EVENTS.BID_WON, {}); sinon.assert.callCount(eventCounter.registerCleanioBillingEvent, 4); }); diff --git a/test/spec/modules/concertAnalyticsAdapter_spec.js b/test/spec/modules/concertAnalyticsAdapter_spec.js index 1df73ae04fe..7cb6db1b1a0 100644 --- a/test/spec/modules/concertAnalyticsAdapter_spec.js +++ b/test/spec/modules/concertAnalyticsAdapter_spec.js @@ -1,10 +1,11 @@ import concertAnalytics from 'modules/concertAnalyticsAdapter.js'; import { expect } from 'chai'; import {expectEvents} from '../../helpers/analytics.js'; +import { EVENTS } from 'src/constants.js'; + const sinon = require('sinon'); let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); describe('ConcertAnalyticsAdapter', function() { let sandbox; @@ -147,10 +148,10 @@ describe('ConcertAnalyticsAdapter', function() { } function fireBidEvents(events) { - events.emit(constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}); - events.emit(constants.EVENTS.BID_REQUESTED, {bidder: 'concert'}); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.AUCTION_INIT, { timestamp, auctionId, timeout, adUnits }); + events.emit(EVENTS.BID_REQUESTED, { bidder: 'concert' }); + events.emit(EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.AUCTION_END, {}); + events.emit(EVENTS.BID_WON, bidWon); } }); diff --git a/test/spec/modules/confiantRtdProvider_spec.js b/test/spec/modules/confiantRtdProvider_spec.js index 8f9fcd0ba98..f9b86046f3a 100644 --- a/test/spec/modules/confiantRtdProvider_spec.js +++ b/test/spec/modules/confiantRtdProvider_spec.js @@ -1,7 +1,7 @@ import * as utils from '../../../src/utils.js'; import * as hook from '../../../src/hook.js' import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import confiantModule from '../../../modules/confiantRtdProvider.js'; @@ -48,7 +48,7 @@ describe('Confiant RTD module', function () { let billableEventsCounter = 0; const propertyId = 'fff'; - events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, (e) => { + events.on(EVENTS.BILLABLE_EVENT, (e) => { if (e.vendor === 'confiant') { billableEventsCounter++; expect(e.type).to.equal('impression'); diff --git a/test/spec/modules/conversantAnalyticsAdapter_spec.js b/test/spec/modules/conversantAnalyticsAdapter_spec.js index f425535ce73..75cb63b02f6 100644 --- a/test/spec/modules/conversantAnalyticsAdapter_spec.js +++ b/test/spec/modules/conversantAnalyticsAdapter_spec.js @@ -1,13 +1,13 @@ import sinon from 'sinon'; -import {expect} from 'chai'; -import {default as conversantAnalytics, CNVR_CONSTANTS, cnvrHelper} from 'modules/conversantAnalyticsAdapter'; +import { expect } from 'chai'; +import { default as conversantAnalytics, CNVR_CONSTANTS, cnvrHelper } from 'modules/conversantAnalyticsAdapter'; import * as utils from 'src/utils.js'; import * as prebidGlobal from 'src/prebidGlobal'; -import {server} from '../../mocks/xhr.js'; +import { server } from '../../mocks/xhr.js'; -import constants from 'src/constants.json' +import {EVENTS} from 'src/constants.js' -let events = require('src/events'); +const events = require('src/events'); describe('Conversant analytics adapter tests', function() { let sandbox; // sinon sandbox to make restoring all stubbed objects easier @@ -39,7 +39,7 @@ describe('Conversant analytics adapter tests', function() { requests = server.requests; sandbox = sinon.sandbox.create(); sandbox.stub(events, 'getEvents').returns([]); // need to stub this otherwise unwanted events seem to get fired during testing - let getGlobalStub = { + const getGlobalStub = { version: PREBID_VERSION, getUserIds: function() { // userIdTargeting.js init() gets called on AUCTION_END so we need to mock this function. return {}; @@ -98,7 +98,7 @@ describe('Conversant analytics adapter tests', function() { it('should NOT sample when sampling set to 0', function() { sandbox.stub(utils, 'logError'); const NEVER_SAMPLE_CONFIG = utils.deepClone(VALID_ALWAYS_SAMPLE_CONFIG); - NEVER_SAMPLE_CONFIG['options'].cnvr_sampling = 0; + NEVER_SAMPLE_CONFIG.options.cnvr_sampling = 0; conversantAnalytics.disableAnalytics(); conversantAnalytics.enableAnalytics(NEVER_SAMPLE_CONFIG); expect(utils.logError.called).to.equal(false); @@ -110,17 +110,17 @@ describe('Conversant analytics adapter tests', function() { it('should cleanup up cache objects', function() { conversantAnalytics.enableAnalytics(VALID_CONFIGURATION); - cnvrHelper.adIdLookup['keep'] = {timeReceived: DATESTAMP + 1}; - cnvrHelper.adIdLookup['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE}; + cnvrHelper.adIdLookup.keep = { timeReceived: DATESTAMP + 1 }; + cnvrHelper.adIdLookup.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - cnvrHelper.timeoutCache['keep'] = {timeReceived: DATESTAMP + 1}; - cnvrHelper.timeoutCache['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE}; + cnvrHelper.timeoutCache.keep = { timeReceived: DATESTAMP + 1 }; + cnvrHelper.timeoutCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - cnvrHelper.auctionIdTimestampCache['keep'] = {timeReceived: DATESTAMP + 1}; - cnvrHelper.auctionIdTimestampCache['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE}; + cnvrHelper.auctionIdTimestampCache.keep = { timeReceived: DATESTAMP + 1 }; + cnvrHelper.auctionIdTimestampCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - cnvrHelper.bidderErrorCache['keep'] = {timeReceived: DATESTAMP + 1, errors: []}; - cnvrHelper.bidderErrorCache['delete'] = {timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE, errors: []}; + cnvrHelper.bidderErrorCache.keep = { timeReceived: DATESTAMP + 1, errors: [] }; + cnvrHelper.bidderErrorCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE, errors: [] }; expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(2); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(2); @@ -145,12 +145,12 @@ describe('Conversant analytics adapter tests', function() { it('createBid() should return correct object', function() { const EVENT_CODE = 1; const TIME = 2; - let bid = cnvrHelper.createBid(EVENT_CODE, 2); - expect(bid).to.deep.equal({'eventCodes': [EVENT_CODE], 'timeToRespond': TIME}); + const bid = cnvrHelper.createBid(EVENT_CODE, 2); + expect(bid).to.deep.equal({ eventCodes: [EVENT_CODE], timeToRespond: TIME }); }); it('createAdUnit() should return correct object', function() { - let adUnit = cnvrHelper.createAdUnit(); + const adUnit = cnvrHelper.createAdUnit(); expect(adUnit).to.deep.equal({ sizes: [], mediaTypes: [], @@ -160,13 +160,13 @@ describe('Conversant analytics adapter tests', function() { it('createAdSize() should return correct object', function() { let adSize = cnvrHelper.createAdSize(1, 2); - expect(adSize).to.deep.equal({w: 1, h: 2}); + expect(adSize).to.deep.equal({ w: 1, h: 2 }); adSize = cnvrHelper.createAdSize(); - expect(adSize).to.deep.equal({w: -1, h: -1}); + expect(adSize).to.deep.equal({ w: -1, h: -1 }); adSize = cnvrHelper.createAdSize('foo', 'bar'); - expect(adSize).to.deep.equal({w: -1, h: -1}); + expect(adSize).to.deep.equal({ w: -1, h: -1 }); }); it('getLookupKey() should return correct object', function() { @@ -183,7 +183,7 @@ describe('Conversant analytics adapter tests', function() { const myDate = Date.now(); conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - let payload = cnvrHelper.createPayload(REQUEST_TYPE, AUCTION_ID, myDate); + const payload = cnvrHelper.createPayload(REQUEST_TYPE, AUCTION_ID, myDate); expect(payload).to.deep.equal({ bidderErrors: [], cnvrSampleRate: 1, @@ -200,7 +200,7 @@ describe('Conversant analytics adapter tests', function() { }); it('keyExistsAndIsObject() should return correct data', function() { - let data = { + const data = { a: [], b: 1, c: 'foo', @@ -216,21 +216,21 @@ describe('Conversant analytics adapter tests', function() { }); it('deduplicateArray() should return correct data', function () { - let arrayOfObjects = [{w: 1, h: 2}, {w: 2, h: 3}, {w: 1, h: 2}]; - let array = [3, 2, 1, 1, 2, 3]; + const arrayOfObjects = [{ w: 1, h: 2 }, { w: 2, h: 3 }, { w: 1, h: 2 }]; + const array = [3, 2, 1, 1, 2, 3]; let empty; - let notArray = 3; - let emptyArray = []; + const notArray = 3; + const emptyArray = []; expect(JSON.stringify(cnvrHelper.deduplicateArray(array))).to.equal(JSON.stringify([3, 2, 1])); - expect(JSON.stringify(cnvrHelper.deduplicateArray(arrayOfObjects))).to.equal(JSON.stringify([{w: 1, h: 2}, {w: 2, h: 3}])); + expect(JSON.stringify(cnvrHelper.deduplicateArray(arrayOfObjects))).to.equal(JSON.stringify([{ w: 1, h: 2 }, { w: 2, h: 3 }])); expect(JSON.stringify(cnvrHelper.deduplicateArray(emptyArray))).to.equal(JSON.stringify([])); expect(cnvrHelper.deduplicateArray(empty)).to.be.undefined; expect(cnvrHelper.deduplicateArray(notArray)).to.equal(notArray); }); it('getSampleRate() should return correct data', function () { - let obj = { + const obj = { sampling: 1, cnvr_sampling: 0.5, too_big: 1.2, @@ -249,7 +249,7 @@ describe('Conversant analytics adapter tests', function() { }); it('getPageUrl() should return correct data', function() { - let url = cnvrHelper.getPageUrl(); + const url = cnvrHelper.getPageUrl(); expect(url.length).to.be.above(1); }); @@ -313,20 +313,20 @@ describe('Conversant analytics adapter tests', function() { describe('Bid Timeout Event Tests', function() { const BID_TIMEOUT_PAYLOAD = [{ - 'bidId': '80882409358b8a8', - 'bidder': 'conversant', - 'adUnitCode': 'MedRect', - 'auctionId': 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' + bidId: '80882409358b8a8', + bidder: 'conversant', + adUnitCode: 'MedRect', + auctionId: 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' }, { - 'bidId': '9da4c107a6f24c8', - 'bidder': 'conversant', - 'adUnitCode': 'Leaderboard', - 'auctionId': 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' + bidId: '9da4c107a6f24c8', + bidder: 'conversant', + adUnitCode: 'Leaderboard', + auctionId: 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' }]; it('should put both items in timeout cache', function() { expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); - events.emit(constants.EVENTS.BID_TIMEOUT, BID_TIMEOUT_PAYLOAD); + events.emit(EVENTS.BID_TIMEOUT, BID_TIMEOUT_PAYLOAD); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(2); BID_TIMEOUT_PAYLOAD.forEach(timeoutBid => { @@ -358,7 +358,7 @@ describe('Conversant analytics adapter tests', function() { }; expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(constants.EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); + events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // object should be removed expect(requests).to.have.lengthOf(1); const data = JSON.parse(requests[0].requestBody); @@ -366,8 +366,8 @@ describe('Conversant analytics adapter tests', function() { expect(data.auction.auctionId).to.equal('auctionId'); expect(data.auction.preBidVersion).to.equal(PREBID_VERSION); expect(data.auction.sid).to.equal(SITE_ID); - expect(data.adUnits['adUnitCode'].bids['bidderCode'][0].eventCodes.includes(CNVR_CONSTANTS.RENDER_FAILED)).to.be.true; - expect(data.adUnits['adUnitCode'].bids['bidderCode'][0].message).to.have.lengthOf.above(0); + expect(data.adUnits.adUnitCode.bids.bidderCode[0].eventCodes.includes(CNVR_CONSTANTS.RENDER_FAILED)).to.be.true; + expect(data.adUnits.adUnitCode.bids.bidderCode[0].message).to.have.lengthOf.above(0); }); it('should not send data if no adId', function() { @@ -379,14 +379,14 @@ describe('Conversant analytics adapter tests', function() { }; expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(constants.EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD_NO_ADID); + events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD_NO_ADID); expect(requests).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); // same object in cache as before... no change expect(cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId]).to.not.be.undefined; expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(constants.EVENTS.AD_RENDER_FAILED); + expect(data.event).to.be.equal(EVENTS.AD_RENDER_FAILED); expect(data.siteId).to.be.equal(SITE_ID); expect(data.message).to.not.be.undefined; expect(data.prebidVersion).to.not.be.undefined; @@ -402,13 +402,13 @@ describe('Conversant analytics adapter tests', function() { }; expect(requests).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(constants.EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); + events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // object should be removed but no call made to send data expect(requests).to.have.lengthOf(1); expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(constants.EVENTS.AD_RENDER_FAILED); + expect(data.event).to.be.equal(EVENTS.AD_RENDER_FAILED); expect(data.siteId).to.be.equal(SITE_ID); expect(data.message).to.not.be.undefined; expect(data.prebidVersion).to.not.be.undefined; @@ -492,14 +492,14 @@ describe('Conversant analytics adapter tests', function() { it('should not send data or put a record in adIdLookup when bad data provided', function() { expect(requests).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - events.emit(constants.EVENTS.BID_WON, BAD_BID_WON_ARGS); + events.emit(EVENTS.BID_WON, BAD_BID_WON_ARGS); expect(requests).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // check for error event expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(constants.EVENTS.BID_WON); + expect(data.event).to.be.equal(EVENTS.BID_WON); expect(data.siteId).to.be.equal(SITE_ID); expect(data.message).to.not.be.undefined; expect(data.prebidVersion).to.not.be.undefined; @@ -509,11 +509,11 @@ describe('Conversant analytics adapter tests', function() { it('should send data and put a record in adIdLookup', function() { const myAuctionStart = Date.now(); - cnvrHelper.auctionIdTimestampCache[GOOD_BID_WON_ARGS.auctionId] = {timeReceived: myAuctionStart}; + cnvrHelper.auctionIdTimestampCache[GOOD_BID_WON_ARGS.auctionId] = { timeReceived: myAuctionStart }; expect(requests).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - events.emit(constants.EVENTS.BID_WON, GOOD_BID_WON_ARGS); + events.emit(EVENTS.BID_WON, GOOD_BID_WON_ARGS); // Check that adIdLookup was set correctly expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); @@ -914,16 +914,16 @@ describe('Conversant analytics adapter tests', function() { it('should not do anything when auction id doesnt exist', function() { sandbox.stub(utils, 'logError'); - let BAD_ARGS = JSON.parse(JSON.stringify(AUCTION_END_PAYLOAD)); + const BAD_ARGS = JSON.parse(JSON.stringify(AUCTION_END_PAYLOAD)); delete BAD_ARGS.auctionId; expect(requests).to.have.lengthOf(0); - events.emit(constants.EVENTS.AUCTION_END, BAD_ARGS); + events.emit(EVENTS.AUCTION_END, BAD_ARGS); expect(requests).to.have.lengthOf(1); // check for error event expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(constants.EVENTS.AUCTION_END); + expect(data.event).to.be.equal(EVENTS.AUCTION_END); expect(data.siteId).to.be.equal(SITE_ID); expect(data.message).to.not.be.undefined; expect(data.prebidVersion).to.not.be.undefined; @@ -961,7 +961,7 @@ describe('Conversant analytics adapter tests', function() { expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); - events.emit(constants.EVENTS.AUCTION_END, AUCTION_END_PAYLOAD); + events.emit(EVENTS.AUCTION_END, AUCTION_END_PAYLOAD); expect(utils.logError.called).to.equal(false); expect(requests).to.have.lengthOf(1); expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); @@ -993,7 +993,7 @@ describe('Conversant analytics adapter tests', function() { expect(data.adUnits[AD_UNIT_CODE_NATIVE].sizes).to.have.lengthOf(0); expect(Object.keys(data.adUnits[AD_UNIT_CODE].bids)).to.have.lengthOf(2); - const cnvrBidsArray = data.adUnits[AD_UNIT_CODE].bids['conversant']; + const cnvrBidsArray = data.adUnits[AD_UNIT_CODE].bids.conversant; // testing multiple bids from same bidder expect(cnvrBidsArray).to.have.lengthOf(2); expect(cnvrBidsArray[0].eventCodes.includes(CNVR_CONSTANTS.BID)).to.be.true; @@ -1014,7 +1014,7 @@ describe('Conversant analytics adapter tests', function() { expect(cnvrBidsArray[1].adSize.h).to.equal(100); expect(cnvrBidsArray[1].mediaType).to.equal('banner'); - const apnBidsArray = data.adUnits[AD_UNIT_CODE].bids['appnexus']; + const apnBidsArray = data.adUnits[AD_UNIT_CODE].bids.appnexus; expect(apnBidsArray).to.have.lengthOf(2); let apnBid = apnBidsArray[0]; expect(apnBid.originalCpm).to.be.undefined; @@ -1034,7 +1034,7 @@ describe('Conversant analytics adapter tests', function() { expect(apnBid.mediaType).to.be.undefined; expect(Object.keys(data.adUnits[AD_UNIT_CODE_NATIVE].bids)).to.have.lengthOf(1); - const apnNativeBidsArray = data.adUnits[AD_UNIT_CODE_NATIVE].bids['appnexus']; + const apnNativeBidsArray = data.adUnits[AD_UNIT_CODE_NATIVE].bids.appnexus; expect(apnNativeBidsArray).to.have.lengthOf(1); const apnNativeBid = apnNativeBidsArray[0]; expect(apnNativeBid.eventCodes.includes(CNVR_CONSTANTS.BID)).to.be.true; @@ -1075,7 +1075,7 @@ describe('Conversant analytics adapter tests', function() { bidderCode: 'myBidderCode', bidderRequestId: '15246a574e859f', bids: [{}], - gdprConsent: {consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', vendorData: {}, gdprApplies: true}, + gdprConsent: { consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', vendorData: {}, gdprApplies: true }, refererInfo: { canonicalUrl: null, page: 'http://mypage.org?pbjs_debug=true', @@ -1089,12 +1089,12 @@ describe('Conversant analytics adapter tests', function() { }; it('should record error when bidder_error called', function() { - let warnStub = sandbox.stub(utils, 'logWarn'); + const warnStub = sandbox.stub(utils, 'logWarn'); expect(requests).to.have.lengthOf(0); expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); expect(warnStub.calledOnce).to.be.false; - events.emit(constants.EVENTS.BIDDER_ERROR, {'error': XHR_ERROR_MOCK, 'bidderRequest': MOCK_BID_REQUEST}); + events.emit(EVENTS.BIDDER_ERROR, { error: XHR_ERROR_MOCK, bidderRequest: MOCK_BID_REQUEST }); expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); expect(warnStub.calledOnce).to.be.true; @@ -1105,7 +1105,7 @@ describe('Conversant analytics adapter tests', function() { expect(errorObj.errors[0].bidderCode).to.equal(MOCK_BID_REQUEST.bidderCode); expect(errorObj.errors[0].url).to.not.be.undefined; - events.emit(constants.EVENTS.BIDDER_ERROR, {'error': XHR_ERROR_MOCK, 'bidderRequest': MOCK_BID_REQUEST}); + events.emit(EVENTS.BIDDER_ERROR, { error: XHR_ERROR_MOCK, bidderRequest: MOCK_BID_REQUEST }); errorObj = cnvrHelper.bidderErrorCache[MOCK_BID_REQUEST.auctionId]; expect(errorObj.errors).to.have.lengthOf(2); }); diff --git a/test/spec/modules/currency_spec.js b/test/spec/modules/currency_spec.js index fa44b7daa7a..e96867f4e84 100644 --- a/test/spec/modules/currency_spec.js +++ b/test/spec/modules/currency_spec.js @@ -13,7 +13,7 @@ import { responseReady } from 'modules/currency.js'; import {createBid} from '../../../src/bidfactory.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS, STATUS, REJECTION_REASON } from '../../../src/constants.js'; import {server} from '../../mocks/xhr.js'; import * as events from 'src/events.js'; @@ -28,7 +28,7 @@ describe('currency', function () { let fn = sinon.spy(); function makeBid(bidProps) { - return Object.assign(createBid(CONSTANTS.STATUS.GOOD), bidProps); + return Object.assign(createBid(STATUS.GOOD), bidProps); } beforeEach(function () { @@ -335,7 +335,7 @@ describe('currency', function () { addBidResponseHook(addBidResponse, 'au', bid, reject); fakeCurrencyFileServer.respond(); sinon.assert.notCalled(addBidResponse); - sinon.assert.calledWith(reject, CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY); + sinon.assert.calledWith(reject, REJECTION_REASON.CANNOT_CONVERT_CURRENCY); }); it('attempts to load rates again on the next auction', () => { @@ -344,7 +344,7 @@ describe('currency', function () { }); fakeCurrencyFileServer.respond(); fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates())); - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {}); + events.emit(EVENTS.AUCTION_INIT, {}); addBidResponseHook(addBidResponse, 'au', bid, reject); fakeCurrencyFileServer.respond(); sinon.assert.calledWith(addBidResponse, 'au', bid, reject); @@ -462,12 +462,12 @@ describe('currency', function () { const addBidResponse = sinon.spy(); addBidResponseHook(addBidResponse, 'au', bid, reject); addBidResponseHook(addBidResponse, 'au', noConversionBid, reject); - events.emit(CONSTANTS.EVENTS.AUCTION_TIMEOUT, {auctionId: 'aid'}); + events.emit(EVENTS.AUCTION_TIMEOUT, { auctionId: 'aid' }); fakeCurrencyFileServer.respond(); sinon.assert.calledOnce(addBidResponse); sinon.assert.calledWith(addBidResponse, 'au', noConversionBid, reject); sinon.assert.calledOnce(reject); - sinon.assert.calledWith(reject, CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY); + sinon.assert.calledWith(reject, REJECTION_REASON.CANNOT_CONVERT_CURRENCY); }) it('should return 1 when currency support is enabled and same currency code is requested as is set to adServerCurrency', function () { diff --git a/test/spec/modules/dsaControl_spec.js b/test/spec/modules/dsaControl_spec.js index 0d7c52b5efd..45392d58c04 100644 --- a/test/spec/modules/dsaControl_spec.js +++ b/test/spec/modules/dsaControl_spec.js @@ -1,5 +1,5 @@ import {addBidResponseHook, setMetaDsa, reset} from '../../../modules/dsaControl.js'; -import CONSTANTS from 'src/constants.json'; +import { REJECTION_REASON } from 'src/constants.js'; import {auctionManager} from '../../../src/auctionManager.js'; import {AuctionIndex} from '../../../src/auctionIndex.js'; @@ -51,7 +51,7 @@ describe('DSA transparency', () => { }); it('should reject bids that have no meta.dsa', () => { - expectRejection(CONSTANTS.REJECTION_REASON.DSA_REQUIRED); + expectRejection(REJECTION_REASON.DSA_REQUIRED); }); it('should accept bids that do', () => { @@ -66,7 +66,7 @@ describe('DSA transparency', () => { it('should reject bids with adrender = 0 (advertiser will not render)', () => { bid.meta = {dsa: {adrender: 0}}; - expectRejection(CONSTANTS.REJECTION_REASON.DSA_MISMATCH); + expectRejection(REJECTION_REASON.DSA_MISMATCH); }); it('should accept bids with adrender = 1 (advertiser will render)', () => { @@ -81,7 +81,7 @@ describe('DSA transparency', () => { it('should reject bids with adrender = 1 (advertiser will render)', () => { bid.meta = {dsa: {adrender: 1}}; - expectRejection(CONSTANTS.REJECTION_REASON.DSA_MISMATCH); + expectRejection(REJECTION_REASON.DSA_MISMATCH); }); it('should accept bids with adrender = 0 (advertiser will not render)', () => { diff --git a/test/spec/modules/eplanningAnalyticsAdapter_spec.js b/test/spec/modules/eplanningAnalyticsAdapter_spec.js index 419181de983..dddc248b409 100644 --- a/test/spec/modules/eplanningAnalyticsAdapter_spec.js +++ b/test/spec/modules/eplanningAnalyticsAdapter_spec.js @@ -3,9 +3,10 @@ import {includes} from 'src/polyfill.js'; import { expect } from 'chai'; import { parseUrl } from 'src/utils.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; + let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); describe('eplanning analytics adapter', function () { beforeEach(function () { @@ -82,22 +83,22 @@ describe('eplanning analytics adapter', function () { // Emit the events with the "real" arguments // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { auctionId: pauctionId, timestamp: auctionTimestamp }); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); // Step 5: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, { + events.emit(EVENTS.BID_WON, { adId: 'adIdData', ad: 'adContent', auctionId: pauctionId, @@ -106,7 +107,7 @@ describe('eplanning analytics adapter', function () { }); // Step 6: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {auctionId: pauctionId}); + events.emit(EVENTS.AUCTION_END, { auctionId: pauctionId }); // Step 7: Find the request data sent (filtering other hosts) let requests = server.requests.filter(req => { @@ -127,22 +128,28 @@ describe('eplanning analytics adapter', function () { // Step 9 verify that we only receive the parameters we need let expectedEventValues = [ // AUCTION INIT - {ec: constants.EVENTS.AUCTION_INIT, + { + ec: EVENTS.AUCTION_INIT, p: {auctionId: pauctionId, time: auctionTimestamp}}, // BID REQ - {ec: constants.EVENTS.BID_REQUESTED, + { + ec: EVENTS.BID_REQUESTED, p: {auctionId: pauctionId, time: 1509369418389, bidder: pbidderCode, bids: [{time: 1509369418389, sizes: [[300, 250]], bidder: pbidderCode, placementCode: 'container-1', auctionId: pauctionId}]}}, // BID RESP - {ec: constants.EVENTS.BID_RESPONSE, + { + ec: EVENTS.BID_RESPONSE, p: {auctionId: pauctionId, bidder: pbidderCode, cpm: 0.015, size: '300x250', time: 1509369418832}}, // BID T.O. - {ec: constants.EVENTS.BID_TIMEOUT, + { + ec: EVENTS.BID_TIMEOUT, p: [{auctionId: pauctionId, bidder: pbidderCode}]}, // BID WON - {ec: constants.EVENTS.BID_WON, + { + ec: EVENTS.BID_WON, p: {auctionId: pauctionId, size: '300x250'}}, // AUCTION END - {ec: constants.EVENTS.AUCTION_END, + { + ec: EVENTS.AUCTION_END, p: {auctionId: pauctionId}} ]; diff --git a/test/spec/modules/fintezaAnalyticsAdapter_spec.js b/test/spec/modules/fintezaAnalyticsAdapter_spec.js index cddffc63554..1e4c5cbcdd3 100644 --- a/test/spec/modules/fintezaAnalyticsAdapter_spec.js +++ b/test/spec/modules/fintezaAnalyticsAdapter_spec.js @@ -3,10 +3,10 @@ import {includes} from 'src/polyfill.js'; import { expect } from 'chai'; import { parseUrl } from 'src/utils.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); function setCookie(name, value, expires) { document.cookie = name + '=' + value + @@ -74,7 +74,7 @@ describe('finteza analytics adapter', function () { }; // Emit the events with the "real" arguments - events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + events.emit(EVENTS.BID_REQUESTED, bidRequest); expect(server.requests.length).to.equal(1); @@ -117,7 +117,7 @@ describe('finteza analytics adapter', function () { }; // Emit the events with the "real" arguments - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); @@ -171,7 +171,7 @@ describe('finteza analytics adapter', function () { } // Emit the events with the "real" arguments - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); @@ -211,7 +211,7 @@ describe('finteza analytics adapter', function () { ]; // Emit the events with the "real" arguments - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); diff --git a/test/spec/modules/genericAnalyticsAdapter_spec.js b/test/spec/modules/genericAnalyticsAdapter_spec.js index 79874f5d756..2d9c7b4ae45 100644 --- a/test/spec/modules/genericAnalyticsAdapter_spec.js +++ b/test/spec/modules/genericAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ import {defaultHandler, GenericAnalytics} from '../../../modules/genericAnalyticsAdapter.js'; import * as events from 'src/events.js'; -import * as CONSTANTS from 'src/constants.json'; +import {EVENTS} from 'src/constants.js'; -const {AUCTION_INIT, BID_RESPONSE} = CONSTANTS.EVENTS; +const {AUCTION_INIT, BID_RESPONSE} = EVENTS; describe('Generic analytics', () => { describe('adapter', () => { diff --git a/test/spec/modules/geoedgeRtdProvider_spec.js b/test/spec/modules/geoedgeRtdProvider_spec.js index 211a3efa3c6..ecc24bce6b5 100644 --- a/test/spec/modules/geoedgeRtdProvider_spec.js +++ b/test/spec/modules/geoedgeRtdProvider_spec.js @@ -1,11 +1,11 @@ import * as utils from '../../../src/utils.js'; -import {loadExternalScript} from '../../../src/adloader.js'; +import { loadExternalScript } from '../../../src/adloader.js'; import * as geoedgeRtdModule from '../../../modules/geoedgeRtdProvider.js'; -import {server} from '../../../test/mocks/xhr.js'; +import { server } from '../../../test/mocks/xhr.js'; import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; -let { +const { geoedgeSubmodule, getClientUrl, getInPageUrl, @@ -17,35 +17,35 @@ let { markAsLoaded } = geoedgeRtdModule; -let key = '123123123'; +const key = '123123123'; function makeConfig(gpt) { return { name: 'geoedge', params: { wap: false, - key: key, + key, bidders: { bidderA: true, bidderB: false }, - gpt: gpt + gpt } }; } function mockBid(bidderCode) { return { - 'ad': '', - 'adId': '1234', - 'cpm': '1.00', - 'width': 300, - 'height': 250, - 'bidderCode': bidderCode, - 'requestId': utils.getUniqueIdentifierStr(), - 'creativeId': 'id', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 360 + ad: '', + adId: '1234', + cpm: '1.00', + width: 300, + height: 250, + bidderCode, + requestId: utils.getUniqueIdentifierStr(), + creativeId: 'id', + currency: 'USD', + netRevenue: true, + ttl: 360 }; } @@ -58,7 +58,7 @@ function mockMessageFromClient(key) { }; } -let mockWrapper = `${htmlPlaceholder}`; +const mockWrapper = `${htmlPlaceholder}`; describe('Geoedge RTD module', function () { describe('submodule', function () { @@ -75,8 +75,8 @@ describe('Geoedge RTD module', function () { geoedgeRtdModule.preloadClient.restore(); }); it('should return false when missing params or key', function () { - let missingParams = geoedgeSubmodule.init({}); - let missingKey = geoedgeSubmodule.init({ params: {} }); + const missingParams = geoedgeSubmodule.init({}); + const missingKey = geoedgeSubmodule.init({ params: {} }); expect(missingParams || missingKey).to.equal(false); }); it('should return true when params are ok', function () { @@ -84,8 +84,8 @@ describe('Geoedge RTD module', function () { }); it('should fetch the wrapper', function () { geoedgeSubmodule.init(makeConfig(false)); - let request = server.requests[0]; - let isWrapperRequest = request && request.url && request.url && request.url === WRAPPER_URL; + const request = server.requests[0]; + const isWrapperRequest = request && request.url && request.url && request.url === WRAPPER_URL; expect(isWrapperRequest).to.equal(true); }); it('should call preloadClient', function () { @@ -93,7 +93,7 @@ describe('Geoedge RTD module', function () { }); it('should emit billable events with applicable winning bids', function (done) { let counter = 0; - events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) { + events.on(EVENTS.BILLABLE_EVENT, function (event) { if (event.vendor === geoedgeSubmodule.name && event.type === 'impression') { counter += 1; } @@ -104,28 +104,28 @@ describe('Geoedge RTD module', function () { }); it('should load the in page code when gpt params is true', function () { geoedgeSubmodule.init(makeConfig(true)); - let isInPageUrl = arg => arg === getInPageUrl(key); + const isInPageUrl = arg => arg === getInPageUrl(key); expect(loadExternalScript.calledWith(sinon.match(isInPageUrl))).to.equal(true); }); it('should set the window.grumi config object when gpt params is true', function () { - let hasGrumiObj = typeof window.grumi === 'object'; + const hasGrumiObj = typeof window.grumi === 'object'; expect(hasGrumiObj && window.grumi.key === key && window.grumi.fromPrebid).to.equal(true); }); }); describe('preloadClient', function () { let iframe; preloadClient(key); - let loadExternalScriptCall = loadExternalScript.getCall(0); + const loadExternalScriptCall = loadExternalScript.getCall(0); it('should create an invisible iframe and insert it to the DOM', function () { iframe = document.getElementById('grumiFrame'); expect(iframe && iframe.style.display === 'none'); }); it('should assign params object to the iframe\'s window', function () { - let grumi = iframe.contentWindow.grumi; + const grumi = iframe.contentWindow.grumi; expect(grumi.key).to.equal(key); }); it('should preload the client into the iframe', function () { - let isClientUrl = arg => arg === getClientUrl(key); + const isClientUrl = arg => arg === getClientUrl(key); expect(loadExternalScriptCall.calledWithMatch(isClientUrl)).to.equal(true); }); }); @@ -137,28 +137,28 @@ describe('Geoedge RTD module', function () { }); describe('getMacros', function () { it('return a dictionary of macros replaced with values from bid object', function () { - let bid = mockBid('testBidder'); - let dict = getMacros(bid, key); - let hasCpm = dict['%_hbCpm!'] === bid.cpm; - let hasCurrency = dict['%_hbCurrency!'] === bid.currency; + const bid = mockBid('testBidder'); + const dict = getMacros(bid, key); + const hasCpm = dict['%_hbCpm!'] === bid.cpm; + const hasCurrency = dict['%_hbCurrency!'] === bid.currency; expect(hasCpm && hasCurrency); }); }); describe('onBidResponseEvent', function () { - let bidFromA = mockBid('bidderA'); + const bidFromA = mockBid('bidderA'); it('should wrap bid html when bidder is configured', function () { geoedgeSubmodule.onBidResponseEvent(bidFromA, makeConfig(false)); expect(bidFromA.ad.indexOf('')).to.equal(0); }); it('should not wrap bid html when bidder is not configured', function () { - let bidFromB = mockBid('bidderB'); + const bidFromB = mockBid('bidderB'); geoedgeSubmodule.onBidResponseEvent(bidFromB, makeConfig(false)); expect(bidFromB.ad.indexOf('')).to.equal(-1); }); it('should only muatate the bid ad porperty', function () { - let copy = Object.assign({}, bidFromA); + const copy = Object.assign({}, bidFromA); delete copy.ad; - let equalsOriginal = Object.keys(copy).every(key => copy[key] === bidFromA[key]); + const equalsOriginal = Object.keys(copy).every(key => copy[key] === bidFromA[key]); expect(equalsOriginal).to.equal(true); }); }); diff --git a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js index 7b68b0dea46..efaeb06ae53 100644 --- a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js +++ b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js @@ -10,7 +10,7 @@ import {expect} from 'chai'; import sinon from 'sinon'; const events = require('src/events'); -const constants = require('src/constants.json'); +const constants = require('src/constants.js'); const pbuid = 'pbuid-AA778D8A796AEA7A0843E2BBEB677766'; const auctionId = 'b0b39610-b941-4659-a87c-de9f62d3e13e'; diff --git a/test/spec/modules/greenbidsRtdProvider_spec.js b/test/spec/modules/greenbidsRtdProvider_spec.js index d0083d4dc7a..ae63a0b00a0 100644 --- a/test/spec/modules/greenbidsRtdProvider_spec.js +++ b/test/spec/modules/greenbidsRtdProvider_spec.js @@ -8,7 +8,7 @@ import { } from 'modules/greenbidsRtdProvider.js'; import { server } from '../../mocks/xhr.js'; import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; describe('greenbidsRtdProvider', () => { const endPoint = 't.greenbids.ai'; @@ -332,7 +332,7 @@ describe('greenbidsRtdProvider', () => { it('should emit billable event if greenbids has set the adunit.ext value', function (done) { let counter = 0; - events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) { + events.on(EVENTS.BILLABLE_EVENT, function (event) { if (event.vendor === 'greenbidsRtdProvider' && event.type === 'auction') { counter += 1; } diff --git a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js index cd9c12a729c..266bc104fd8 100644 --- a/test/spec/modules/growthCodeAnalyticsAdapter_spec.js +++ b/test/spec/modules/growthCodeAnalyticsAdapter_spec.js @@ -2,7 +2,7 @@ import adapterManager from '../../../src/adapterManager.js'; import growthCodeAnalyticsAdapter from '../../../modules/growthCodeAnalyticsAdapter.js'; import { expect } from 'chai'; import * as events from '../../../src/events.js'; -import constants from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { generateUUID } from '../../../src/utils.js'; import { server } from 'test/mocks/xhr.js'; @@ -58,7 +58,7 @@ describe('growthCode analytics adapter', () => { adUnitCodes: ['usr1234'] }], }; - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); assert(server.requests.length > 0) const body = JSON.parse(server.requests[0].requestBody); var eventTypes = []; diff --git a/test/spec/modules/hadronAnalyticsAdapter_spec.js b/test/spec/modules/hadronAnalyticsAdapter_spec.js index bea131fb78f..68e5bc3aecb 100644 --- a/test/spec/modules/hadronAnalyticsAdapter_spec.js +++ b/test/spec/modules/hadronAnalyticsAdapter_spec.js @@ -2,7 +2,7 @@ import adapterManager from '../../../src/adapterManager.js'; import hadronAnalyticsAdapter from '../../../modules/hadronAnalyticsAdapter.js'; import { expect } from 'chai'; import * as events from '../../../src/events.js'; -import constants from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { generateUUID } from '../../../src/utils.js'; import { server } from 'test/mocks/xhr.js'; @@ -48,13 +48,13 @@ describe('Hadron analytics adapter', () => { adUnitCodes: ['usr1234'] }], }; - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); assert(server.requests.length > 0) const body = JSON.parse(server.requests[0].requestBody); var eventTypes = []; body.events.forEach(e => eventTypes.push(e.eventType)); assert(eventTypes.length > 0) - assert(eventTypes.indexOf(constants.EVENTS.AUCTION_END) > -1); + assert(eventTypes.indexOf(EVENTS.AUCTION_END) > -1); hadronAnalyticsAdapter.disableAnalytics(); }); }); diff --git a/test/spec/modules/id5AnalyticsAdapter_spec.js b/test/spec/modules/id5AnalyticsAdapter_spec.js index 9cb7233ce7c..c9d21daa4e0 100644 --- a/test/spec/modules/id5AnalyticsAdapter_spec.js +++ b/test/spec/modules/id5AnalyticsAdapter_spec.js @@ -2,7 +2,7 @@ import adapterManager from '../../../src/adapterManager.js'; import id5AnalyticsAdapter from '../../../modules/id5AnalyticsAdapter.js'; import { expect } from 'chai'; import * as events from '../../../src/events.js'; -import constants from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { generateUUID } from '../../../src/utils.js'; import {server} from '../../mocks/xhr.js'; @@ -98,7 +98,7 @@ describe('ID5 analytics adapter', () => { it('sends auction end events to the backend', () => { id5AnalyticsAdapter.enableAnalytics(config); server.respond(); - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); server.respond(); // Why 3? 1: config, 2: tcfEnforcement, 3: auctionEnd @@ -307,7 +307,7 @@ describe('ID5 analytics adapter', () => { id5AnalyticsAdapter.enableAnalytics(config); server.respond(); - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); server.respond(); expect(server.requests).to.have.length(3); @@ -360,7 +360,7 @@ describe('ID5 analytics adapter', () => { ]); id5AnalyticsAdapter.enableAnalytics(config); server.respond(); - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); server.respond(); expect(server.requests).to.have.length(2); @@ -441,7 +441,7 @@ describe('ID5 analytics adapter', () => { ]); id5AnalyticsAdapter.enableAnalytics(config); server.respond(); - events.emit(constants.EVENTS.AUCTION_END, auction); + events.emit(EVENTS.AUCTION_END, auction); server.respond(); expect(server.requests).to.have.length(3); diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js index af468f2fe4d..fd5d24295f5 100644 --- a/test/spec/modules/id5IdSystem_spec.js +++ b/test/spec/modules/id5IdSystem_spec.js @@ -8,7 +8,7 @@ import { } from '../../../modules/userId/index.js'; import {config} from '../../../src/config.js'; import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import * as utils from '../../../src/utils.js'; import {uspDataHandler, gppDataHandler} from '../../../src/adapterManager.js'; import '../../../src/prebid.js'; @@ -1004,7 +1004,7 @@ describe('ID5 ID System', function () { }, {adUnits}); }).then(() => { expect(xhrServerMock.hasReceivedAnyRequest()).is.false; - events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); return xhrServerMock.expectFetchRequest(); }).then(request => { const requestBody = JSON.parse(request.requestBody); diff --git a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js index a8828515ffd..e866d2404f3 100644 --- a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +++ b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js @@ -2,8 +2,8 @@ import invisiblyAdapter from 'modules/invisiblyAnalyticsAdapter.js'; import { expect } from 'chai'; import {expectEvents} from '../../helpers/analytics.js'; import {server} from '../../mocks/xhr.js'; +import { EVENTS, STATUS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('Invisibly Analytics Adapter test suite', function () { let xhr; @@ -26,7 +26,7 @@ describe('Invisibly Analytics Adapter test suite', function () { hb_source: 'client', }, getStatusCode() { - return CONSTANTS.STATUS.GOOD; + return STATUS.GOOD; }, }; @@ -54,7 +54,7 @@ describe('Invisibly Analytics Adapter test suite', function () { hb_source: 'server', }, getStatusCode() { - return CONSTANTS.STATUS.GOOD; + return STATUS.GOOD; }, }; @@ -204,11 +204,11 @@ describe('Invisibly Analytics Adapter test suite', function () { options: {}, }); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(EVENTS.BID_WON, MOCK.BID_WON); invisiblyAdapter.flush(); sinon.assert.callCount(invisiblyAdapter.track, 0); }); @@ -230,7 +230,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for auction init event it('auction init event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -252,7 +252,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bid adjustment event it('bid adjustment event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); + events.emit(EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -274,7 +274,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bid timeout event it('bid timeout event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); + events.emit(EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -296,7 +296,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bid requested event it('bid requested event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -318,7 +318,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bid response event it('bid response event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -338,7 +338,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for no bid event it('no bid event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); + events.emit(EVENTS.NO_BID, MOCK.NO_BID); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -360,7 +360,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bid won event it('bid won event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + events.emit(EVENTS.BID_WON, MOCK.BID_WON); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -378,7 +378,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for bidder done event it('bidder done event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -403,7 +403,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for set targeting event it('set targeting event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); + events.emit(EVENTS.SET_TARGETING, MOCK.SET_TARGETING); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -428,7 +428,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for request bids event it('request bids event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); + events.emit(EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -450,7 +450,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for add ad units event it('add ad units event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); + events.emit(EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -472,7 +472,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for ad render failed event it('ad render failed event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); + events.emit(EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -494,7 +494,7 @@ describe('Invisibly Analytics Adapter test suite', function () { // spec for auction end event it('auction end event', function () { invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END); invisiblyAdapter.flush(); const invisiblyEvents = JSON.parse( @@ -516,7 +516,7 @@ describe('Invisibly Analytics Adapter test suite', function () { it('it should not call sendEvent for this event emit', function () { sinon.spy(invisiblyAdapter, 'sendEvent'); invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.INVALID_EVENT, MOCK.INVALID_EVENT); + events.emit(EVENTS.INVALID_EVENT, MOCK.INVALID_EVENT); invisiblyAdapter.flush(); expect(requests.length).to.equal(0); @@ -529,19 +529,19 @@ describe('Invisibly Analytics Adapter test suite', function () { invisiblyAdapter.enableAnalytics(MOCK.config); expectEvents([ - constants.EVENTS.AUCTION_INIT, - constants.EVENTS.AUCTION_END, - constants.EVENTS.BID_ADJUSTMENT, - constants.EVENTS.BID_TIMEOUT, - constants.EVENTS.BID_REQUESTED, - constants.EVENTS.BID_RESPONSE, - constants.EVENTS.NO_BID, - constants.EVENTS.BID_WON, - constants.EVENTS.BIDDER_DONE, - constants.EVENTS.SET_TARGETING, - constants.EVENTS.REQUEST_BIDS, - constants.EVENTS.ADD_AD_UNITS, - constants.EVENTS.AD_RENDER_FAILED + EVENTS.AUCTION_INIT, + EVENTS.AUCTION_END, + EVENTS.BID_ADJUSTMENT, + EVENTS.BID_TIMEOUT, + EVENTS.BID_REQUESTED, + EVENTS.BID_RESPONSE, + EVENTS.NO_BID, + EVENTS.BID_WON, + EVENTS.BIDDER_DONE, + EVENTS.SET_TARGETING, + EVENTS.REQUEST_BIDS, + EVENTS.ADD_AD_UNITS, + EVENTS.AD_RENDER_FAILED ]).to.beTrackedBy(invisiblyAdapter.track); }); }); @@ -558,11 +558,11 @@ describe('Invisibly Analytics Adapter test suite', function () { }, }); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + events.emit(EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(EVENTS.BID_WON, MOCK.BID_WON); invisiblyAdapter.flush(); sinon.assert.callCount(invisiblyAdapter.sendEvent, 0); diff --git a/test/spec/modules/kargoAnalyticsAdapter_spec.js b/test/spec/modules/kargoAnalyticsAdapter_spec.js index c27c8499aa1..c2acd86defa 100644 --- a/test/spec/modules/kargoAnalyticsAdapter_spec.js +++ b/test/spec/modules/kargoAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ import kargoAnalyticsAdapter from 'modules/kargoAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('Kargo Analytics Adapter', function () { const adapterConfig = { @@ -30,10 +30,10 @@ describe('Kargo Analytics Adapter', function () { timeToRespond: 192, }; - events.emit(constants.EVENTS.AUCTION_INIT, { + events.emit(EVENTS.AUCTION_INIT, { timeout: 1000 }); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.BID_RESPONSE, bidResponse); expect(server.requests.length).to.equal(1); expect(server.requests[0].url).to.equal('https://krk.kargo.com/api/v1/event/auction-data?aid=66529d4c-8998-47c2-ab3e-5b953490b98f&ato=1000&rt=192&it=0'); diff --git a/test/spec/modules/konduitAnalyticsAdapter_spec.js b/test/spec/modules/konduitAnalyticsAdapter_spec.js index e79ae2feeeb..496dd171afa 100644 --- a/test/spec/modules/konduitAnalyticsAdapter_spec.js +++ b/test/spec/modules/konduitAnalyticsAdapter_spec.js @@ -2,19 +2,19 @@ import konduitAnalyticsAdapter from 'modules/konduitAnalyticsAdapter'; import { expect } from 'chai'; import { config } from '../../../src/config.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let CONSTANTS = require('src/constants.json'); const eventsData = { - [CONSTANTS.EVENTS.AUCTION_INIT]: { + [EVENTS.AUCTION_INIT]: { 'auctionId': 'test_auction_id', 'timestamp': Date.now(), 'auctionStatus': 'inProgress', 'adUnitCodes': ['video-test'], 'timeout': 700 }, - [CONSTANTS.EVENTS.BID_REQUESTED]: { + [EVENTS.BID_REQUESTED]: { 'bidderCode': 'test_bidder_code', 'time': Date.now(), 'bids': [{ @@ -25,13 +25,13 @@ const eventsData = { 'params': { 'testParam': 'test_param' } }] }, - [CONSTANTS.EVENTS.NO_BID]: { + [EVENTS.NO_BID]: { 'bidderCode': 'test_bidder_code2', 'transactionId': 'test_transaction_id', 'adUnitCode': 'video-test', 'bidId': 'test_bid_id' }, - [CONSTANTS.EVENTS.BID_RESPONSE]: { + [EVENTS.BID_RESPONSE]: { 'bidderCode': 'test_bidder_code', 'adUnitCode': 'video-test', 'statusMessage': 'Bid available', @@ -44,7 +44,7 @@ const eventsData = { 'requestId': 'test_request_id', 'creativeId': 144876543 }, - [CONSTANTS.EVENTS.AUCTION_END]: { + [EVENTS.AUCTION_END]: { 'auctionId': 'test_auction_id', 'timestamp': Date.now(), 'auctionEnd': Date.now() + 400, @@ -52,7 +52,7 @@ const eventsData = { 'adUnitCodes': ['video-test'], 'timeout': 700 }, - [CONSTANTS.EVENTS.BID_WON]: { + [EVENTS.BID_WON]: { 'bidderCode': 'test_bidder_code', 'adUnitCode': 'video-test', 'statusMessage': 'Bid available', @@ -99,12 +99,12 @@ describe(`Konduit Analytics Adapter`, () => { expect(konduitAnalyticsAdapter.context.aggregatedEvents).to.be.an('array'); const eventTypes = [ - CONSTANTS.EVENTS.AUCTION_INIT, - CONSTANTS.EVENTS.BID_REQUESTED, - CONSTANTS.EVENTS.NO_BID, - CONSTANTS.EVENTS.BID_RESPONSE, - CONSTANTS.EVENTS.BID_WON, - CONSTANTS.EVENTS.AUCTION_END, + EVENTS.AUCTION_INIT, + EVENTS.BID_REQUESTED, + EVENTS.NO_BID, + EVENTS.BID_RESPONSE, + EVENTS.BID_WON, + EVENTS.AUCTION_END, ]; const args = eventTypes.map(eventType => eventsData[eventType]); diff --git a/test/spec/modules/lemmaDigitalBidAdapter_spec.js b/test/spec/modules/lemmaDigitalBidAdapter_spec.js index d50728dce3c..ab4c3259671 100644 --- a/test/spec/modules/lemmaDigitalBidAdapter_spec.js +++ b/test/spec/modules/lemmaDigitalBidAdapter_spec.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { spec } from 'modules/lemmaDigitalBidAdapter.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; -const constants = require('src/constants.json'); +const constants = require('src/constants.js'); describe('lemmaDigitalBidAdapter', function () { let bidRequests; diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js index d00bfbc7bb5..e833440bf03 100644 --- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js @@ -3,6 +3,7 @@ import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; import { auctionManager } from 'src/auctionManager.js'; import {expectEvents} from '../../helpers/analytics.js'; +import { EVENTS } from 'src/constants.js'; let utils = require('src/utils'); let refererDetection = require('src/refererDetection'); @@ -13,7 +14,6 @@ let clock; let now = new Date(); let events = require('src/events'); -let constants = require('src/constants.json'); let auctionId = '99abbc81-c1f1-41cd-8f25-f7149244c897' const configWithSamplingAll = { @@ -286,7 +286,7 @@ describe('LiveIntent Analytics Adapter ', () => { sandbox.stub(utils, 'generateUUID').returns(instanceId); sandbox.stub(refererDetection, 'getRefererInfo').returns({page: url}); sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids }); - events.emit(constants.EVENTS.AUCTION_END, args); + events.emit(EVENTS.AUCTION_END, args); clock.tick(2000); expect(server.requests.length).to.equal(1); @@ -305,7 +305,7 @@ describe('LiveIntent Analytics Adapter ', () => { sandbox.stub(utils, 'generateUUID').returns(instanceId); sandbox.stub(refererDetection, 'getRefererInfo').returns({page: url}); sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids }); - events.emit(constants.EVENTS.AUCTION_END, args); + events.emit(EVENTS.AUCTION_END, args); clock.tick(2000); expect(server.requests.length).to.equal(0); }); diff --git a/test/spec/modules/livewrappedAnalyticsAdapter_spec.js b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js index d07b48752c6..f82cc4c4f52 100644 --- a/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +++ b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js @@ -1,5 +1,5 @@ import livewrappedAnalyticsAdapter, { BID_WON_TIMEOUT } from 'modules/livewrappedAnalyticsAdapter.js'; -import CONSTANTS from 'src/constants.json'; +import { AD_RENDER_FAILED_REASON, EVENTS, STATUS } from 'src/constants.js'; import { config } from 'src/config.js'; import { server } from 'test/mocks/xhr.js'; import { setConfig } from 'modules/currency.js'; @@ -9,21 +9,16 @@ let utils = require('src/utils'); let adapterManager = require('src/adapterManager').default; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_RESPONSE, - BIDDER_DONE, - BID_WON, - BID_TIMEOUT, - SET_TARGETING, - AD_RENDER_FAILED - }, - STATUS: { - GOOD - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_WON, + BID_TIMEOUT, + SET_TARGETING, + AD_RENDER_FAILED +} = EVENTS; const BID1 = { width: 980, @@ -43,7 +38,7 @@ const BID1 = { }, dealId: 'dealid', getStatusCode() { - return CONSTANTS.STATUS.GOOD; + return STATUS.GOOD; } }; @@ -71,7 +66,7 @@ const BID3 = { auctionId: '25c6d7f5-699a-4bfc-87c9-996f915341fa', mediaType: 'banner', getStatusCode() { - return CONSTANTS.STATUS.GOOD; + return STATUS.GOOD; } }; @@ -135,7 +130,7 @@ const MOCK = { AD_RENDER_FAILED: [ { 'bidId': '2ecff0db240757', - 'reason': CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, + 'reason': AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, 'message': 'message', 'bid': BID1 } @@ -275,7 +270,7 @@ const ANALYTICS_MESSAGE = { adUnitId: 'adunitid', bidder: 'livewrapped', auctionId: 0, - rsn: CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, + rsn: AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, msg: 'message' }, ] diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index 397ee4a8577..1798c96c341 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -6,7 +6,7 @@ import magniteAdapter, { detectBrowserFromUa, callPrebidCacheHook } from '../../../modules/magniteAnalyticsAdapter.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import { config } from 'src/config.js'; import { server } from 'test/mocks/xhr.js'; import * as mockGpt from '../integration/faker/googletag.js'; @@ -17,19 +17,17 @@ let events = require('src/events.js'); let utils = require('src/utils.js'); const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_RESPONSE, - BIDDER_DONE, - BID_WON, - BID_TIMEOUT, - BILLABLE_EVENT, - SEAT_NON_BID, - BID_REJECTED - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_WON, + BID_TIMEOUT, + BILLABLE_EVENT, + SEAT_NON_BID, + BID_REJECTED +} = EVENTS; const STUBBED_UUID = '12345678-1234-1234-1234-123456789abc'; diff --git a/test/spec/modules/malltvAnalyticsAdapter_spec.js b/test/spec/modules/malltvAnalyticsAdapter_spec.js index c96069df0f9..2be9fe4b09f 100644 --- a/test/spec/modules/malltvAnalyticsAdapter_spec.js +++ b/test/spec/modules/malltvAnalyticsAdapter_spec.js @@ -5,7 +5,7 @@ import { import { expect } from 'chai' import { getCpmInEur } from '../../../modules/malltvAnalyticsAdapter' import * as events from 'src/events' -import constants from 'src/constants.json' +import { EVENTS } from 'src/constants.js' const auctionId = 'b0b39610-b941-4659-a87c-de9f62d3e13e' const propertyId = '123456' @@ -481,14 +481,14 @@ describe('Malltv Prebid AnalyticsAdapter Testing', function () { it('should call handleBidTimeout as BID_TIMEOUT trigger event', function() { sinon.spy(malltvAnalyticsAdapter, 'handleBidTimeout') - events.emit(constants.EVENTS.BID_TIMEOUT, {}) + events.emit(EVENTS.BID_TIMEOUT, {}) sinon.assert.callCount(malltvAnalyticsAdapter.handleBidTimeout, 1) malltvAnalyticsAdapter.handleBidTimeout.restore() }) it('should call handleAuctionEnd as AUCTION_END trigger event', function() { sinon.spy(malltvAnalyticsAdapter, 'handleAuctionEnd') - events.emit(constants.EVENTS.AUCTION_END, {}) + events.emit(EVENTS.AUCTION_END, {}) sinon.assert.callCount(malltvAnalyticsAdapter.handleAuctionEnd, 1) malltvAnalyticsAdapter.handleAuctionEnd.restore() }) diff --git a/test/spec/modules/mediafilterRtdProvider_spec.js b/test/spec/modules/mediafilterRtdProvider_spec.js index 3395c7be691..fe9fb855629 100644 --- a/test/spec/modules/mediafilterRtdProvider_spec.js +++ b/test/spec/modules/mediafilterRtdProvider_spec.js @@ -1,7 +1,7 @@ import * as utils from '../../../src/utils.js'; import * as hook from '../../../src/hook.js' import * as events from '../../../src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import { MediaFilter, @@ -121,7 +121,7 @@ describe('The Media Filter RTD module', function () { eventHandler(mockEvent); - expect(eventsEmitSpy.calledWith(CONSTANTS.EVENTS.BILLABLE_EVENT, { + expect(eventsEmitSpy.calledWith(EVENTS.BILLABLE_EVENT, { 'billingId': sinon.match.string, 'configurationHash': configurationHash, 'type': 'impression', diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index e19c27cc2d3..7c3cf88dace 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -1,13 +1,13 @@ import { expect } from 'chai'; import medianetAnalytics from 'modules/medianetAnalyticsAdapter.js'; import * as utils from 'src/utils.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import * as events from 'src/events.js'; import {clearEvents} from 'src/events.js'; const { - EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON } -} = CONSTANTS; + AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON +} = EVENTS; const ERROR_WINNING_BID_ABSENT = 'winning_bid_absent'; diff --git a/test/spec/modules/nobidAnalyticsAdapter_spec.js b/test/spec/modules/nobidAnalyticsAdapter_spec.js index f6c741bb7ff..07823d3536f 100644 --- a/test/spec/modules/nobidAnalyticsAdapter_spec.js +++ b/test/spec/modules/nobidAnalyticsAdapter_spec.js @@ -1,9 +1,9 @@ import nobidAnalytics from 'modules/nobidAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); const TOP_LOCATION = 'https://www.somesite.com'; const SITE_ID = 1234; @@ -46,7 +46,7 @@ describe('NoBid Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, + events.emit(EVENTS.AUCTION_INIT, {config: initOptions, auctionId: '13', timestamp: Date.now(), bidderRequests: [{refererInfo: {topmostLocation: TOP_LOCATION}}]}); @@ -77,27 +77,27 @@ describe('NoBid Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, + events.emit(EVENTS.AUCTION_INIT, {config: initOptions, auctionId: '13', timestamp: Date.now(), bidderRequests: [{refererInfo: {topmostLocation: TOP_LOCATION}}]}); - events.emit(constants.EVENTS.BID_WON, {}); + events.emit(EVENTS.BID_WON, {}); clock.tick(5000); expect(server.requests).to.have.length(1); - events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(EVENTS.BID_REQUESTED, {}); clock.tick(5000); expect(server.requests).to.have.length(1); - events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(EVENTS.BID_RESPONSE, {}); clock.tick(5000); expect(server.requests).to.have.length(1); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); + events.emit(EVENTS.BID_TIMEOUT, {}); clock.tick(5000); expect(server.requests).to.have.length(1); - events.emit(constants.EVENTS.AD_RENDER_SUCCEEDED, {}); + events.emit(EVENTS.AD_RENDER_SUCCEEDED, {}); clock.tick(5000); expect(server.requests).to.have.length(1); @@ -191,13 +191,13 @@ describe('NoBid Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, + events.emit(EVENTS.AUCTION_INIT, {config: initOptions, auctionId: '13', timestamp: Date.now(), bidderRequests: [{refererInfo: {topmostLocation: TOP_LOCATION}}]}); // Step 3: Send bid won event - events.emit(constants.EVENTS.BID_WON, requestIncoming); + events.emit(EVENTS.BID_WON, requestIncoming); clock.tick(5000); expect(server.requests).to.have.length(1); const bidWonRequest = JSON.parse(server.requests[0].requestBody); @@ -388,13 +388,13 @@ describe('NoBid Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, + events.emit(EVENTS.AUCTION_INIT, {config: initOptions, auctionId: '13', timestamp: Date.now(), bidderRequests: [{refererInfo: {topmostLocation: `${TOP_LOCATION}_something`}}]}); // Step 3: Send bid won event - events.emit(constants.EVENTS.AUCTION_END, requestIncoming); + events.emit(EVENTS.AUCTION_END, requestIncoming); clock.tick(5000); expect(server.requests).to.have.length(1); const auctionEndRequest = JSON.parse(server.requests[0].requestBody); @@ -428,22 +428,22 @@ describe('NoBid Prebid Analytic', function () { nobidAnalytics.processServerResponse(JSON.stringify({disabled: 0})); disabled = nobidAnalytics.isAnalyticsDisabled(); expect(disabled).to.equal(false); - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '1234567890'}); + events.emit(EVENTS.AUCTION_END, {auctionId: '1234567890'}); clock.tick(1000); expect(server.requests).to.have.length(1); - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '12345678901'}); + events.emit(EVENTS.AUCTION_END, {auctionId: '12345678901'}); clock.tick(1000); expect(server.requests).to.have.length(2); nobidAnalytics.processServerResponse('disabled: true'); - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '12345678902'}); + events.emit(EVENTS.AUCTION_END, {auctionId: '12345678902'}); clock.tick(1000); expect(server.requests).to.have.length(3); nobidAnalytics.processServerResponse(JSON.stringify({disabled: 1})); disabled = nobidAnalytics.isAnalyticsDisabled(); expect(disabled).to.equal(true); - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '12345678902'}); + events.emit(EVENTS.AUCTION_END, {auctionId: '12345678902'}); clock.tick(5000); expect(server.requests).to.have.length(3); @@ -481,7 +481,7 @@ describe('NoBid Prebid Analytic', function () { nobidAnalytics.enableAnalytics(initOptions); adapterManager.enableAnalytics({ provider: 'nobid', options: initOptions }); - let eventType = constants.EVENTS.AUCTION_END; + let eventType = EVENTS.AUCTION_END; let disabled; nobidAnalytics.processServerResponse(JSON.stringify({disabled: 0})); disabled = nobidAnalytics.isAnalyticsDisabled(); @@ -508,14 +508,14 @@ describe('NoBid Prebid Analytic', function () { nobidAnalytics.processServerResponse(JSON.stringify({disabled_auctionEnd: 0})); disabled = nobidAnalytics.isAnalyticsDisabled(eventType); expect(disabled).to.equal(false); - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '1234567890'}); + events.emit(EVENTS.AUCTION_END, {auctionId: '1234567890'}); clock.tick(1000); expect(server.requests).to.have.length(1); server.requests.length = 0; expect(server.requests).to.have.length(0); - eventType = constants.EVENTS.BID_WON; + eventType = EVENTS.BID_WON; nobidAnalytics.processServerResponse(JSON.stringify({disabled_bidWon: 1})); disabled = nobidAnalytics.isAnalyticsDisabled(eventType); expect(disabled).to.equal(true); @@ -526,7 +526,7 @@ describe('NoBid Prebid Analytic', function () { server.requests.length = 0; expect(server.requests).to.have.length(0); - eventType = constants.EVENTS.AUCTION_END; + eventType = EVENTS.AUCTION_END; nobidAnalytics.processServerResponse(JSON.stringify({disabled: 1})); disabled = nobidAnalytics.isAnalyticsDisabled(eventType); expect(disabled).to.equal(true); @@ -537,16 +537,16 @@ describe('NoBid Prebid Analytic', function () { server.requests.length = 0; expect(server.requests).to.have.length(0); - eventType = constants.EVENTS.AUCTION_END; + eventType = EVENTS.AUCTION_END; nobidAnalytics.processServerResponse(JSON.stringify({disabled_auctionEnd: 1, disabled_bidWon: 0})); disabled = nobidAnalytics.isAnalyticsDisabled(eventType); expect(disabled).to.equal(true); events.emit(eventType, {auctionId: '1234567890'}); clock.tick(1000); expect(server.requests).to.have.length(0); - disabled = nobidAnalytics.isAnalyticsDisabled(constants.EVENTS.BID_WON); + disabled = nobidAnalytics.isAnalyticsDisabled(EVENTS.BID_WON); expect(disabled).to.equal(false); - events.emit(constants.EVENTS.BID_WON, {bidderCode: 'nobid'}); + events.emit(EVENTS.BID_WON, {bidderCode: 'nobid'}); clock.tick(1000); expect(server.requests).to.have.length(1); diff --git a/test/spec/modules/ooloAnalyticsAdapter_spec.js b/test/spec/modules/ooloAnalyticsAdapter_spec.js index 1224c3f0740..f5b3cebf307 100644 --- a/test/spec/modules/ooloAnalyticsAdapter_spec.js +++ b/test/spec/modules/ooloAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import ooloAnalytics, { PAGEVIEW_ID } from 'modules/ooloAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; -import constants from 'src/constants.json' +import { EVENTS } from 'src/constants.js' import * as events from 'src/events' import { config } from 'src/config'; import { buildAuctionData, generatePageViewId } from 'modules/ooloAnalyticsAdapter'; @@ -151,12 +151,12 @@ const bidWon = { } function simulateAuction () { - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); - events.emit(constants.EVENTS.BID_REQUESTED, bidRequested); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); - events.emit(constants.EVENTS.NO_BID, noBid); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.AUCTION_INIT, auctionInit); + events.emit(EVENTS.BID_REQUESTED, bidRequested); + events.emit(EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.NO_BID, noBid); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); } describe('oolo Prebid Analytic', () => { @@ -321,16 +321,16 @@ describe('oolo Prebid Analytic', () => { } }) - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); - events.emit(constants.EVENTS.BID_REQUESTED, bidRequested); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(EVENTS.AUCTION_INIT, auctionInit); + events.emit(EVENTS.BID_REQUESTED, bidRequested); + events.emit(EVENTS.BID_RESPONSE, bidResponse); // configuration returned in an arbitrary moment server.requests[0].respond(500) - events.emit(constants.EVENTS.NO_BID, noBid); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.NO_BID, noBid); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); clock.tick(1500) @@ -442,7 +442,7 @@ describe('oolo Prebid Analytic', () => { server.requests[0].respond(500) simulateAuction() - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); clock.tick(1500) // no bidWon @@ -466,7 +466,7 @@ describe('oolo Prebid Analytic', () => { })) simulateAuction() - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); clock.tick(499) // no auction data @@ -491,7 +491,7 @@ describe('oolo Prebid Analytic', () => { server.requests[0].respond(500) simulateAuction() clock.tick(1500) - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests).to.have.length(5) @@ -516,7 +516,7 @@ describe('oolo Prebid Analytic', () => { server.requests[0].respond(500) simulateAuction() clock.tick(1500) - events.emit(constants.EVENTS.AD_RENDER_FAILED, { bidId: 'abcdef', reason: 'exception' }); + events.emit(EVENTS.AD_RENDER_FAILED, { bidId: 'abcdef', reason: 'exception' }); expect(server.requests).to.have.length(5) @@ -557,12 +557,12 @@ describe('oolo Prebid Analytic', () => { } })) - events.emit(constants.EVENTS.AUCTION_INIT, { ...auctionInit }); - events.emit(constants.EVENTS.BID_REQUESTED, { ...bidRequested, bids: bidRequested.bids.map(b => { b.transactionId = '123'; return b }) }); - events.emit(constants.EVENTS.NO_BID, { ...noBid, src: 'client' }); - events.emit(constants.EVENTS.BID_RESPONSE, { ...bidResponse, adUrl: '...' }); - events.emit(constants.EVENTS.AUCTION_END, { ...auctionEnd, winningBids: [] }); - events.emit(constants.EVENTS.BID_WON, { ...bidWon, statusMessage: 'msg2' }); + events.emit(EVENTS.AUCTION_INIT, { ...auctionInit }); + events.emit(EVENTS.BID_REQUESTED, { ...bidRequested, bids: bidRequested.bids.map(b => { b.transactionId = '123'; return b }) }); + events.emit(EVENTS.NO_BID, { ...noBid, src: 'client' }); + events.emit(EVENTS.BID_RESPONSE, { ...bidResponse, adUrl: '...' }); + events.emit(EVENTS.AUCTION_END, { ...auctionEnd, winningBids: [] }); + events.emit(EVENTS.BID_WON, { ...bidWon, statusMessage: 'msg2' }); clock.tick(1500) @@ -596,12 +596,12 @@ describe('oolo Prebid Analytic', () => { } })) - events.emit(constants.EVENTS.AUCTION_INIT, { ...auctionInit, custom_1: true }); - events.emit(constants.EVENTS.BID_REQUESTED, { ...bidRequested, bids: bidRequested.bids.map(b => { b.custom_2 = true; return b }) }); - events.emit(constants.EVENTS.NO_BID, { ...noBid, custom_3: true }); - events.emit(constants.EVENTS.BID_RESPONSE, { ...bidResponse, custom_4: true }); - events.emit(constants.EVENTS.AUCTION_END, { ...auctionEnd }); - events.emit(constants.EVENTS.BID_WON, { ...bidWon, custom_5: true }); + events.emit(EVENTS.AUCTION_INIT, { ...auctionInit, custom_1: true }); + events.emit(EVENTS.BID_REQUESTED, { ...bidRequested, bids: bidRequested.bids.map(b => { b.custom_2 = true; return b }) }); + events.emit(EVENTS.NO_BID, { ...noBid, custom_3: true }); + events.emit(EVENTS.BID_RESPONSE, { ...bidResponse, custom_4: true }); + events.emit(EVENTS.AUCTION_END, { ...auctionEnd }); + events.emit(EVENTS.BID_WON, { ...bidWon, custom_5: true }); clock.tick(1500) @@ -633,7 +633,7 @@ describe('oolo Prebid Analytic', () => { } })) - events.emit(constants.EVENTS.AUCTION_INIT, { ...auctionInit, custom_1: true }); + events.emit(EVENTS.AUCTION_INIT, { ...auctionInit, custom_1: true }); clock.tick(1500) @@ -661,7 +661,7 @@ describe('oolo Prebid Analytic', () => { } })) - events.emit(constants.EVENTS.AUCTION_INIT, { ...auctionInit }); + events.emit(EVENTS.AUCTION_INIT, { ...auctionInit }); expect(server.requests[3].url).to.equal('https://pbjs.com/') }) @@ -686,8 +686,8 @@ describe('oolo Prebid Analytic', () => { } })) - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit) - events.emit(constants.EVENTS.BID_REQUESTED, bidRequested); + events.emit(EVENTS.AUCTION_INIT, auctionInit) + events.emit(EVENTS.BID_REQUESTED, bidRequested); const request = JSON.parse(server.requests[3].requestBody) diff --git a/test/spec/modules/optimonAnalyticsAdapter_spec.js b/test/spec/modules/optimonAnalyticsAdapter_spec.js index f1aa00334b5..270f3aec395 100644 --- a/test/spec/modules/optimonAnalyticsAdapter_spec.js +++ b/test/spec/modules/optimonAnalyticsAdapter_spec.js @@ -3,7 +3,6 @@ import { expect } from 'chai'; import optimonAnalyticsAdapter from '../../../modules/optimonAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; -import constants from 'src/constants.json' import {expectEvents} from '../../helpers/analytics.js'; const AD_UNIT_CODE = 'demo-adunit-1'; diff --git a/test/spec/modules/oxxionAnalyticsAdapter_spec.js b/test/spec/modules/oxxionAnalyticsAdapter_spec.js index 9d06be24f68..f9bcdb40e16 100644 --- a/test/spec/modules/oxxionAnalyticsAdapter_spec.js +++ b/test/spec/modules/oxxionAnalyticsAdapter_spec.js @@ -2,10 +2,10 @@ import oxxionAnalytics from 'modules/oxxionAnalyticsAdapter.js'; import {dereferenceWithoutRenderer} from 'modules/oxxionAnalyticsAdapter.js'; import { expect } from 'chai'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; + let adapterManager = require('src/adapterManager').default; let events = require('src/events'); -let constants = require('src/constants.json'); - describe('Oxxion Analytics', function () { let timestamp = new Date() - 256; let auctionId = '5018eb39-f900-4370-b71e-3bb5b48d324f'; @@ -303,10 +303,10 @@ describe('Oxxion Analytics', function () { } }); - events.emit(constants.EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); - events.emit(constants.EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]); + events.emit(EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); expect(server.requests.length).to.equal(1); let message = JSON.parse(server.requests[0].requestBody); expect(message).to.have.property('auctionEnd').exist; @@ -336,7 +336,7 @@ describe('Oxxion Analytics', function () { domain: 'test' } }); - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests.length).to.equal(1); let message = JSON.parse(server.requests[0].requestBody); expect(message).not.to.have.property('ad'); diff --git a/test/spec/modules/paapi_spec.js b/test/spec/modules/paapi_spec.js index 3d264e87e51..2c7c959ef19 100644 --- a/test/spec/modules/paapi_spec.js +++ b/test/spec/modules/paapi_spec.js @@ -15,7 +15,7 @@ import { reset } from 'modules/paapi.js'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import {getGlobal} from '../../../src/prebidGlobal.js'; import {auctionManager} from '../../../src/auctionManager.js'; import {stubAuctionIndex} from '../../helpers/indexStub.js'; @@ -69,7 +69,7 @@ describe('paapi module', () => { cf2 = {...fledgeAuctionConfig, id: 2, seller: 'b2'}; addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, cf1); addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, cf2); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: ['au1', 'au2', 'au3'] }); }); it('and make them available at end of auction', () => { @@ -123,9 +123,9 @@ describe('paapi module', () => { }); it('should drop auction configs after end of auction', () => { - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId}); + events.emit(EVENTS.AUCTION_END, { auctionId }); addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId}); + events.emit(EVENTS.AUCTION_END, { auctionId }); expect(getPAAPIConfig({auctionId})).to.eql({}); }); @@ -136,7 +136,7 @@ describe('paapi module', () => { ortb2: {fpd: 1}, ortb2Imp: {fpd: 2} }, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId}); + events.emit(EVENTS.AUCTION_END, { auctionId }); sinon.assert.match(getPAAPIConfig({auctionId}), { au1: { componentAuctions: [{ @@ -165,13 +165,13 @@ describe('paapi module', () => { describe('onAuctionConfig', () => { const auctionId = 'aid'; it('is invoked with null configs when there\'s no config', () => { - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au']}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: ['au'] }); submods.forEach(submod => sinon.assert.calledWith(submod.onAuctionConfig, auctionId, {au: null})); }); it('is invoked with relevant configs', () => { addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig); addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: ['au1', 'au2', 'au3'] }); submods.forEach(submod => { sinon.assert.calledWith(submod.onAuctionConfig, auctionId, { au1: {componentAuctions: [fledgeAuctionConfig]}, @@ -185,12 +185,12 @@ describe('paapi module', () => { markAsUsed('au1'); }); addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: ['au1'] }); expect(getPAAPIConfig()).to.eql({}); }); it('keeps them available if they do not', () => { addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: ['au1'] }); expect(getPAAPIConfig()).to.not.be.empty; }) }); @@ -294,7 +294,7 @@ describe('paapi module', () => { it('should populate bidfloor/bidfloorcur', () => { addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, fledgeAuctionConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, payload); + events.emit(EVENTS.AUCTION_END, payload); const signals = getPAAPIConfig({auctionId}).au.componentAuctions[0].auctionSignals; expect(signals.prebid?.bidfloor).to.eql(bidfloor); expect(signals.prebid?.bidfloorcur).to.eql(bidfloorcur); @@ -339,7 +339,7 @@ describe('paapi module', () => { configs[auctionId][adUnitCode] = cfg; addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode}, cfg); }); - events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: adUnitCodes.concat(noConfigAdUnitCodes)}); + events.emit(EVENTS.AUCTION_END, { auctionId, adUnitCodes: adUnitCodes.concat(noConfigAdUnitCodes) }); }); }); diff --git a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js index 0c4949264a7..ea0dd4ab793 100644 --- a/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js +++ b/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import pianoDmpAnalytics from 'modules/pianoDmpAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; -import constants from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import { expect } from 'chai'; describe('Piano DMP Analytics Adapter', () => { @@ -31,14 +31,14 @@ describe('Piano DMP Analytics Adapter', () => { it('should pass events to call queue', () => { const eventsList = [ - constants.EVENTS.AUCTION_INIT, - constants.EVENTS.AUCTION_END, - constants.EVENTS.BID_ADJUSTMENT, - constants.EVENTS.BID_TIMEOUT, - constants.EVENTS.BID_REQUESTED, - constants.EVENTS.BID_RESPONSE, - constants.EVENTS.NO_BID, - constants.EVENTS.BID_WON, + EVENTS.AUCTION_INIT, + EVENTS.AUCTION_END, + EVENTS.BID_ADJUSTMENT, + EVENTS.BID_TIMEOUT, + EVENTS.BID_REQUESTED, + EVENTS.BID_RESPONSE, + EVENTS.NO_BID, + EVENTS.BID_WON, ]; // Given diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 2bab144dae7..9c2ac8a23a9 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -12,7 +12,7 @@ import {deepAccess, deepClone, mergeDeep} from 'src/utils.js'; import {ajax} from 'src/ajax.js'; import {config} from 'src/config.js'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import {server} from 'test/mocks/xhr.js'; import 'modules/appnexusBidAdapter.js'; // appnexus alias test import 'modules/rubiconBidAdapter.js'; // rubicon alias test @@ -2879,7 +2879,7 @@ describe('S2S Adapter', function () { adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(400, {}, {}); BID_REQUESTS.forEach(bidderRequest => { - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.BIDDER_ERROR, sinon.match({bidderRequest})) + sinon.assert.calledWith(events.emit, EVENTS.BIDDER_ERROR, sinon.match({ bidderRequest })) }) }) @@ -3062,7 +3062,7 @@ describe('S2S Adapter', function () { sinon.assert.calledOnce(events.emit); const event = events.emit.firstCall.args; - expect(event[0]).to.equal(CONSTANTS.EVENTS.BIDDER_DONE); + expect(event[0]).to.equal(EVENTS.BIDDER_DONE); expect(event[1].bids[0]).to.have.property('serverResponseTimeMs', 8); sinon.assert.calledOnce(addBidResponse); @@ -3093,7 +3093,7 @@ describe('S2S Adapter', function () { Object.assign(responding.ext.seatnonbid, [{auctionId: 2}]) server.requests[0].respond(200, {}, JSON.stringify(responding)); const event = events.emit.secondCall.args; - expect(event[0]).to.equal(CONSTANTS.EVENTS.SEAT_NON_BID); + expect(event[0]).to.equal(EVENTS.SEAT_NON_BID); expect(event[1].seatnonbid[0]).to.have.property('auctionId', 2); expect(event[1].requestedBidders).to.deep.equal(['appnexus']); expect(event[1].response).to.deep.equal(responding); @@ -3584,7 +3584,7 @@ describe('S2S Adapter', function () { adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); - events.emit(CONSTANTS.EVENTS.BID_WON, { + events.emit(EVENTS.BID_WON, { auctionId: '173afb6d132ba3', adId: '1000' }); @@ -3603,7 +3603,7 @@ describe('S2S Adapter', function () { adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); - events.emit(CONSTANTS.EVENTS.BID_WON, { + events.emit(EVENTS.BID_WON, { auctionId: '173afb6d132ba3', adId: 'missingAdId' }); @@ -3619,7 +3619,7 @@ describe('S2S Adapter', function () { adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); - events.emit(CONSTANTS.EVENTS.BID_WON, { + events.emit(EVENTS.BID_WON, { auctionId: '173afb6d132ba3', adId: '1060' }); diff --git a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js index 25834e8574d..9241fda8c81 100644 --- a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +++ b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js @@ -3,9 +3,9 @@ import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; import * as utils from 'src/utils.js'; import {expectEvents} from '../../helpers/analytics.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('Prebid Manager Analytics Adapter', function () { let bidWonEvent = { @@ -66,7 +66,7 @@ describe('Prebid Manager Analytics Adapter', function () { } }); - events.emit(constants.EVENTS.BID_WON, bidWonEvent); + events.emit(EVENTS.BID_WON, bidWonEvent); prebidmanagerAnalytics.flush(); expect(server.requests.length).to.equal(1); diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js index 7ea7722b12a..7223940bc45 100644 --- a/test/spec/modules/priceFloors_spec.js +++ b/test/spec/modules/priceFloors_spec.js @@ -1,8 +1,9 @@ import {expect} from 'chai'; import * as utils from 'src/utils.js'; import { getGlobal } from 'src/prebidGlobal.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS, STATUS } from 'src/constants.js'; import { + FLOOR_SKIPPED_REASON, _floorDataForAuction, getFloorsDataForAuction, getFirstMatchingFloor, @@ -737,7 +738,7 @@ describe('the price floors module', function () { handleSetFloorsConfig(floorConfig); const floorData = createFloorsDataForAuction(adUnits, 'id'); - expect(floorData.skippedReason).to.equal(CONSTANTS.FLOOR_SKIPPED_REASON.NOT_FOUND); + expect(floorData.skippedReason).to.equal(FLOOR_SKIPPED_REASON.NOT_FOUND); }); it('should have skippedReason set to "random" if there is floor data and skipped is true', function() { @@ -746,7 +747,7 @@ describe('the price floors module', function () { handleSetFloorsConfig(floorConfig); const floorData = createFloorsDataForAuction(adUnits, 'id'); - expect(floorData.skippedReason).to.equal(CONSTANTS.FLOOR_SKIPPED_REASON.RANDOM); + expect(floorData.skippedReason).to.equal(FLOOR_SKIPPED_REASON.RANDOM); }); }); @@ -2218,7 +2219,7 @@ describe('the price floors module', function () { let next = (adUnitCode, bid) => { returnedBidResponse = bid; }; - addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(CONSTANTS.STATUS.GOOD, {auctionId: AUCTION_ID}), bidResp), reject); + addBidResponseHook(next, bidResp.adUnitCode, Object.assign(createBid(STATUS.GOOD, { auctionId: AUCTION_ID }), bidResp), reject); }; it('continues with the auction if not floors data is present without any flooring', function () { runBidResponse(); @@ -2345,7 +2346,7 @@ describe('the price floors module', function () { it('should wait 3 seconds before deleting auction floor data', function () { handleSetFloorsConfig({enabled: true}); _floorDataForAuction[AUCTION_END_EVENT.auctionId] = utils.deepClone(basicFloorConfig); - events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT); + events.emit(EVENTS.AUCTION_END, AUCTION_END_EVENT); // should still be here expect(_floorDataForAuction[AUCTION_END_EVENT.auctionId]).to.not.be.undefined; // tick for 4 seconds diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js index 951b5135260..cb13a4db234 100755 --- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ import pubmaticAnalyticsAdapter, { getMetadata } from 'modules/pubmaticAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS, REJECTION_REASON } from 'src/constants.js'; import { config } from 'src/config.js'; import { setConfig } from 'modules/currency.js'; import { server } from '../../mocks/xhr.js'; @@ -18,18 +18,16 @@ const setUAMobile = () => { window.navigator.__defineGetter__('userAgent', funct const setUANull = () => { window.navigator.__defineGetter__('userAgent', function () { return null }) }; const { - EVENTS: { - AUCTION_INIT, - AUCTION_END, - BID_REQUESTED, - BID_RESPONSE, - BID_REJECTED, - BIDDER_DONE, - BID_WON, - BID_TIMEOUT, - SET_TARGETING - } -} = CONSTANTS; + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BID_REJECTED, + BIDDER_DONE, + BID_WON, + BID_TIMEOUT, + SET_TARGETING +} = EVENTS; const BID = { 'bidder': 'pubmatic', @@ -110,7 +108,7 @@ const BID2 = Object.assign({}, BID, { }); const BID3 = Object.assign({}, BID2, { - rejectionReason: CONSTANTS.REJECTION_REASON.FLOOR_NOT_MET + rejectionReason: REJECTION_REASON.FLOOR_NOT_MET }) const MOCK = { SET_TARGETING: { diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index fda2c853e87..8aa29724ad6 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -4,7 +4,7 @@ import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; import { createEidsArray } from 'modules/userId/eids.js'; import { bidderSettings } from 'src/bidderSettings.js'; -const constants = require('src/constants.json'); +const constants = require('src/constants.js'); describe('PubMatic adapter', function () { let bidRequests; diff --git a/test/spec/modules/pubstackAnalyticsAdapter_spec.js b/test/spec/modules/pubstackAnalyticsAdapter_spec.js index fe7441e91e5..6e532698d8b 100644 --- a/test/spec/modules/pubstackAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubstackAnalyticsAdapter_spec.js @@ -2,7 +2,6 @@ import * as utils from 'src/utils.js'; import pubstackAnalytics from '../../../modules/pubstackAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; -import constants from 'src/constants.json' import {expectEvents} from '../../helpers/analytics.js'; describe('Pubstack Analytics Adapter', () => { diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js index 92d5972cc13..688a827de03 100644 --- a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -2,10 +2,10 @@ import {expect} from 'chai'; import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter.js'; import {expectEvents} from '../../helpers/analytics.js'; import {server} from '../../mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); describe('PubWise Prebid Analytics', function () { let requests; @@ -54,14 +54,14 @@ describe('PubWise Prebid Analytics', function () { sandbox.spy(pubwiseAnalytics, 'track'); expectEvents([ - constants.EVENTS.AUCTION_INIT, - constants.EVENTS.BID_REQUESTED, - constants.EVENTS.BID_RESPONSE, - constants.EVENTS.BID_WON, - constants.EVENTS.AD_RENDER_FAILED, - constants.EVENTS.TCF2_ENFORCEMENT, - constants.EVENTS.BID_TIMEOUT, - constants.EVENTS.AUCTION_END, + EVENTS.AUCTION_INIT, + EVENTS.BID_REQUESTED, + EVENTS.BID_RESPONSE, + EVENTS.BID_WON, + EVENTS.AD_RENDER_FAILED, + EVENTS.TCF2_ENFORCEMENT, + EVENTS.BID_TIMEOUT, + EVENTS.AUCTION_END, ]).to.beTrackedBy(pubwiseAnalytics.track); }); @@ -69,10 +69,10 @@ describe('PubWise Prebid Analytics', function () { pubwiseAnalytics.enableAnalytics(mock.DEFAULT_PW_CONFIG); // sent - events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); + events.emit(EVENTS.AUCTION_INIT, mock.AUCTION_INIT); + events.emit(EVENTS.BID_REQUESTED, {}); + events.emit(EVENTS.BID_RESPONSE, {}); + events.emit(EVENTS.BID_WON, {}); // force flush clock.tick(500); @@ -120,7 +120,7 @@ describe('PubWise Prebid Analytics', function () { pubwiseAnalytics.enableAnalytics(mock.DEFAULT_PW_CONFIG); // sent - events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT_EXTRAS); + events.emit(EVENTS.AUCTION_INIT, mock.AUCTION_INIT_EXTRAS); // force flush clock.tick(500); diff --git a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js index e0f4497a8c8..9af1ef185e1 100644 --- a/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubxaiAnalyticsAdapter_spec.js @@ -4,9 +4,9 @@ import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import {server} from 'test/mocks/xhr.js'; import {getGptSlotInfoForAdUnitCode} from '../../../libraries/gptUtils/gptUtils.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('pubxai analytics adapter', function() { beforeEach(function() { @@ -671,19 +671,19 @@ describe('pubxai analytics adapter', function() { it('builds and sends auction data', function() { // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); + events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); + events.emit(EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); + events.emit(EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); + events.emit(EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, prebidEvent['auctionEnd']); + events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); expect(server.requests.length).to.equal(1); @@ -692,7 +692,7 @@ describe('pubxai analytics adapter', function() { expect(realAfterBid).to.deep.equal(expectedAfterBid); // Step 6: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, prebidEvent['bidWon']); + events.emit(EVENTS.BID_WON, prebidEvent['bidWon']); expect(server.requests.length).to.equal(2); diff --git a/test/spec/modules/qortexRtdProvider_spec.js b/test/spec/modules/qortexRtdProvider_spec.js index 9baa526e4cc..c9f92e8af67 100644 --- a/test/spec/modules/qortexRtdProvider_spec.js +++ b/test/spec/modules/qortexRtdProvider_spec.js @@ -1,7 +1,7 @@ import * as utils from 'src/utils'; import * as ajax from 'src/ajax.js'; import * as events from 'src/events.js'; -import CONSTANTS from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import {loadExternalScript} from 'src/adloader.js'; import { qortexSubmodule as module, @@ -127,7 +127,7 @@ describe('qortexRtdProvider', () => { let config = cloneDeep(validModuleConfig); config.params.tagConfig = validTagConfig; - events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, (e) => { + events.on(EVENTS.BILLABLE_EVENT, (e) => { billableEvents.push(e); }) diff --git a/test/spec/modules/realTimeDataModule_spec.js b/test/spec/modules/realTimeDataModule_spec.js index 938e2e2f3c1..0f66b0253a2 100644 --- a/test/spec/modules/realTimeDataModule_spec.js +++ b/test/spec/modules/realTimeDataModule_spec.js @@ -1,7 +1,7 @@ import * as rtdModule from 'modules/rtdModule/index.js'; import {config} from 'src/config.js'; import * as sinon from 'sinon'; -import {default as CONSTANTS} from '../../../src/constants.json'; +import { EVENTS } from '../../../src/constants.js'; import * as events from '../../../src/events.js'; import 'src/prebid.js'; import {attachRealTimeDataProvider, onDataDeletionRequest} from 'modules/rtdModule/index.js'; @@ -255,11 +255,11 @@ describe('Real time module', function () { }); describe('event', () => { - const EVENTS = { - [CONSTANTS.EVENTS.AUCTION_INIT]: 'onAuctionInitEvent', - [CONSTANTS.EVENTS.AUCTION_END]: 'onAuctionEndEvent', - [CONSTANTS.EVENTS.BID_RESPONSE]: 'onBidResponseEvent', - [CONSTANTS.EVENTS.BID_REQUESTED]: 'onBidRequestEvent' + const TEST_EVENTS = { + [EVENTS.AUCTION_INIT]: 'onAuctionInitEvent', + [EVENTS.AUCTION_END]: 'onAuctionEndEvent', + [EVENTS.BID_RESPONSE]: 'onBidResponseEvent', + [EVENTS.BID_REQUESTED]: 'onBidRequestEvent' } const conf = { 'realTimeData': { @@ -281,7 +281,7 @@ describe('Real time module', function () { name: name, init: () => true, } - Object.values(EVENTS).forEach((ev) => provider[ev] = sinon.spy()); + Object.values(TEST_EVENTS).forEach((ev) => provider[ev] = sinon.spy()); return provider; } @@ -303,13 +303,13 @@ describe('Real time module', function () { adUnitCodes: ['a1'], adUnits: [{code: 'a1'}] }; - mockEmitEvent(CONSTANTS.EVENTS.AUCTION_END, auction); + mockEmitEvent(EVENTS.AUCTION_END, auction); providers.forEach(p => { expect(p.getTargetingData.calledWith(auction.adUnitCodes)).to.be.true; }); }); - Object.entries(EVENTS).forEach(([event, hook]) => { + Object.entries(TEST_EVENTS).forEach(([event, hook]) => { it(`'${event}' should be propagated to providers through '${hook}'`, () => { const eventArg = {}; mockEmitEvent(event, eventArg); diff --git a/test/spec/modules/relevantAnalyticsAdapter_spec.js b/test/spec/modules/relevantAnalyticsAdapter_spec.js index 5c818fe01d4..e3d0eca1b7b 100644 --- a/test/spec/modules/relevantAnalyticsAdapter_spec.js +++ b/test/spec/modules/relevantAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import relevantAnalytics from '../../../modules/relevantAnalyticsAdapter.js'; import adapterManager from 'src/adapterManager'; import * as events from 'src/events'; -import constants from 'src/constants.json' +import { EVENTS } from 'src/constants.js' import { expect } from 'chai'; describe('Relevant Analytics Adapter', () => { @@ -18,8 +18,8 @@ describe('Relevant Analytics Adapter', () => { it('should pass all events to the global array', () => { // Given const testEvents = [ - { ev: constants.EVENTS.AUCTION_INIT, args: { test: 1 } }, - { ev: constants.EVENTS.BID_REQUESTED, args: { test: 2 } }, + { ev: EVENTS.AUCTION_INIT, args: { test: 1 } }, + { ev: EVENTS.BID_REQUESTED, args: { test: 2 } }, ]; // When diff --git a/test/spec/modules/relevantdigitalBidAdapter_spec.js b/test/spec/modules/relevantdigitalBidAdapter_spec.js index 0e21453c8ba..1575c5c6b94 100644 --- a/test/spec/modules/relevantdigitalBidAdapter_spec.js +++ b/test/spec/modules/relevantdigitalBidAdapter_spec.js @@ -1,7 +1,7 @@ import {spec, resetBidderConfigs} from 'modules/relevantdigitalBidAdapter.js'; import { parseUrl, deepClone } from 'src/utils.js'; import { config } from 'src/config.js'; -import CONSTANTS from 'src/constants.json'; +import { S2S } from 'src/constants.js'; import adapterManager, { } from 'src/adapterManager.js'; @@ -16,7 +16,7 @@ const TEST_PAGE = `https://${TEST_DOMAIN}/page.html`; const CONFIG = { enabled: true, - endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT, + endpoint: S2S.DEFAULT_ENDPOINT, timeout: 1000, maxBids: 1, adapter: 'prebidServer', diff --git a/test/spec/modules/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js index 9add7ed5f7d..6aab92b6b5d 100644 --- a/test/spec/modules/rivrAnalyticsAdapter_spec.js +++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js @@ -19,7 +19,7 @@ import { import {expect} from 'chai'; import adapterManager from 'src/adapterManager.js'; import * as ajax from 'src/ajax.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; const events = require('../../../src/events'); @@ -98,7 +98,7 @@ describe('RIVR Analytics adapter', () => { expect(rivraddonsTrackPbjsEventStub.callCount).to.be.equal(0); - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000}); + events.emit(EVENTS.AUCTION_INIT, { auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000 }); expect(rivraddonsTrackPbjsEventStub.callCount).to.be.equal(0); @@ -111,12 +111,12 @@ describe('RIVR Analytics adapter', () => { expect(rivraddonsTrackPbjsEventStub.callCount).to.be.equal(0); - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000}); + events.emit(EVENTS.AUCTION_INIT, { auctionId: EMITTED_AUCTION_ID, config: {}, timeout: 3000 }); expect(rivraddonsTrackPbjsEventStub.callCount).to.be.equal(1); const firstArgument = rivraddonsTrackPbjsEventStub.getCall(0).args[0]; - expect(firstArgument.eventType).to.be.equal(CONSTANTS.EVENTS.AUCTION_INIT); + expect(firstArgument.eventType).to.be.equal(EVENTS.AUCTION_INIT); expect(firstArgument.args.auctionId).to.be.equal(EMITTED_AUCTION_ID); window.rivraddon.analytics.trackPbjsEvent.restore(); diff --git a/test/spec/modules/roxotAnalyticsAdapter_spec.js b/test/spec/modules/roxotAnalyticsAdapter_spec.js index 79c58e36735..6fc7f356333 100644 --- a/test/spec/modules/roxotAnalyticsAdapter_spec.js +++ b/test/spec/modules/roxotAnalyticsAdapter_spec.js @@ -1,9 +1,9 @@ import roxotAnalytic from 'modules/roxotAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('Roxot Prebid Analytic', function () { let roxotConfigServerUrl = 'config-server'; @@ -181,18 +181,18 @@ describe('Roxot Prebid Analytic', function () { expect(server.requests[0].url).to.equal('https://' + roxotConfigServerUrl + '/c?publisherId=' + publisherId + '&host=localhost'); server.requests[0].respond(200, {'Content-Type': 'application/json'}, '{"a": 1, "i": 1, "bat": 1}'); - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); - events.emit(constants.EVENTS.BID_REQUESTED, bidRequested); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentWithBid); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseWithBid); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentNoBid); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseNoBid); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentAfterTimeout); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseAfterTimeout); - events.emit(constants.EVENTS.BIDDER_DONE, bidderDone); - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.AUCTION_INIT, auctionInit); + events.emit(EVENTS.BID_REQUESTED, bidRequested); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentWithBid); + events.emit(EVENTS.BID_RESPONSE, bidResponseWithBid); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentNoBid); + events.emit(EVENTS.BID_RESPONSE, bidResponseNoBid); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentAfterTimeout); + events.emit(EVENTS.BID_RESPONSE, bidResponseAfterTimeout); + events.emit(EVENTS.BIDDER_DONE, bidderDone); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests.length).to.equal(4); @@ -260,18 +260,18 @@ describe('Roxot Prebid Analytic', function () { expect(server.requests[0].url).to.equal('https://' + roxotConfigServerUrl + '/c?publisherId=' + publisherId + '&host=localhost'); server.requests[0].respond(200, {'Content-Type': 'application/json'}, '{"a": 1, "i": 1, "bat": 1}'); - events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); - events.emit(constants.EVENTS.BID_REQUESTED, bidRequested); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentWithBid); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseWithBid); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentNoBid); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseNoBid); - events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); - events.emit(constants.EVENTS.BID_ADJUSTMENT, bidAdjustmentAfterTimeout); - events.emit(constants.EVENTS.BID_RESPONSE, bidResponseAfterTimeout); - events.emit(constants.EVENTS.BIDDER_DONE, bidderDone); - events.emit(constants.EVENTS.BID_WON, bidWon); + events.emit(EVENTS.AUCTION_INIT, auctionInit); + events.emit(EVENTS.BID_REQUESTED, bidRequested); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentWithBid); + events.emit(EVENTS.BID_RESPONSE, bidResponseWithBid); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentNoBid); + events.emit(EVENTS.BID_RESPONSE, bidResponseNoBid); + events.emit(EVENTS.BID_TIMEOUT, bidTimeout); + events.emit(EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.BID_ADJUSTMENT, bidAdjustmentAfterTimeout); + events.emit(EVENTS.BID_RESPONSE, bidResponseAfterTimeout); + events.emit(EVENTS.BIDDER_DONE, bidderDone); + events.emit(EVENTS.BID_WON, bidWon); expect(server.requests.length).to.equal(3); diff --git a/test/spec/modules/scaleableAnalyticsAdapter_spec.js b/test/spec/modules/scaleableAnalyticsAdapter_spec.js index c65740252d2..5f86073894a 100644 --- a/test/spec/modules/scaleableAnalyticsAdapter_spec.js +++ b/test/spec/modules/scaleableAnalyticsAdapter_spec.js @@ -1,13 +1,13 @@ import scaleableAnalytics from 'modules/scaleableAnalyticsAdapter.js'; import { expect } from 'chai'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import { server } from 'test/mocks/xhr.js'; -const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; -const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; -const BID_WON = CONSTANTS.EVENTS.BID_WON; -const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; +const BID_TIMEOUT = EVENTS.BID_TIMEOUT; +const AUCTION_INIT = EVENTS.AUCTION_INIT; +const BID_WON = EVENTS.BID_WON; +const AUCTION_END = EVENTS.AUCTION_END; describe('Scaleable Analytics Adapter', function() { const bidsReceivedObj = { diff --git a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js index 6cdc3c448b9..1d8e38f19ec 100644 --- a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js +++ b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js @@ -4,7 +4,6 @@ import {expectEvents} from '../../helpers/analytics.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); describe('sigmoid Prebid Analytic', function () { after(function () { diff --git a/test/spec/modules/sonobiAnalyticsAdapter_spec.js b/test/spec/modules/sonobiAnalyticsAdapter_spec.js index ed8ccd22eea..c34de91dd9f 100644 --- a/test/spec/modules/sonobiAnalyticsAdapter_spec.js +++ b/test/spec/modules/sonobiAnalyticsAdapter_spec.js @@ -1,9 +1,10 @@ import sonobiAnalytics, {DEFAULT_EVENT_URL} from 'modules/sonobiAnalyticsAdapter.js'; import {expect} from 'chai'; import {server} from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); describe('Sonobi Prebid Analytic', function () { var clock; @@ -55,25 +56,25 @@ describe('Sonobi Prebid Analytic', function () { }); // Step 2: Send init auction event - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, auctionId: '13', timestamp: Date.now()}); + events.emit(EVENTS.AUCTION_INIT, { config: initOptions, auctionId: '13', timestamp: Date.now() }); expect(sonobiAnalytics.initOptions).to.have.property('pubId', 'A3B254F'); expect(sonobiAnalytics.initOptions).to.have.property('siteId', '1234'); expect(sonobiAnalytics.initOptions).to.have.property('delay', 100); // Step 3: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, { bids: [bid], auctionId: '13' }); + events.emit(EVENTS.BID_REQUESTED, { bids: [bid], auctionId: '13' }); // Step 4: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, bid); + events.emit(EVENTS.BID_RESPONSE, bid); // Step 5: Send bid won event - events.emit(constants.EVENTS.BID_WON, bid); + events.emit(EVENTS.BID_WON, bid); // Step 6: Send bid timeout event - events.emit(constants.EVENTS.BID_TIMEOUT, {auctionId: '13'}); + events.emit(EVENTS.BID_TIMEOUT, { auctionId: '13' }); // Step 7: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, {auctionId: '13', bidsReceived: [bid]}); + events.emit(EVENTS.AUCTION_END, { auctionId: '13', bidsReceived: [bid] }); clock.tick(5000); const req = server.requests.find(req => req.url.indexOf(DEFAULT_EVENT_URL) !== -1); diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js index d0363eab144..7945bdc9910 100644 --- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js +++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js @@ -4,11 +4,11 @@ import {config} from 'src/config.js'; import adaptermanager from 'src/adapterManager.js'; import {server} from 'test/mocks/xhr.js'; import {expectEvents, fireEvents} from '../../helpers/analytics.js'; +import { EVENTS } from 'src/constants.js'; var assert = require('assert'); let events = require('src/events'); -let constants = require('src/constants.json'); /** * Emit analytics events @@ -18,7 +18,7 @@ let constants = require('src/constants.json'); */ function emitEvent(eventType, event, auctionId) { event.auctionId = auctionId; - events.emit(constants.EVENTS[eventType], event); + events.emit(EVENTS[eventType], event); } let auctionStartTimestamp = Date.now(); diff --git a/test/spec/modules/staqAnalyticsAdapter_spec.js b/test/spec/modules/staqAnalyticsAdapter_spec.js index f8e3ba83bbe..3f28098e1d1 100644 --- a/test/spec/modules/staqAnalyticsAdapter_spec.js +++ b/test/spec/modules/staqAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import analyticsAdapter, { ExpiringQueue, getUmtSource, storage } from 'modules/staqAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; const events = require('../../../src/events'); @@ -216,14 +216,14 @@ describe('', function() { }); it('should handle auction init event', function() { - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, { config: {}, timeout: 3000 }); + events.emit(EVENTS.AUCTION_INIT, { config: {}, timeout: 3000 }); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(1); expect(ev[0]).to.be.eql({ event: 'auctionInit', auctionId: undefined }); }); it('should handle bid request event', function() { - events.emit(CONSTANTS.EVENTS.BID_REQUESTED, REQUEST); + events.emit(EVENTS.BID_REQUESTED, REQUEST); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(2); expect(ev[1]).to.be.eql({ @@ -236,7 +236,7 @@ describe('', function() { }); it('should handle bid response event', function() { - events.emit(CONSTANTS.EVENTS.BID_RESPONSE, RESPONSE); + events.emit(EVENTS.BID_RESPONSE, RESPONSE); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(3); expect(ev[2]).to.be.eql({ @@ -255,7 +255,7 @@ describe('', function() { }); it('should handle timeouts properly', function() { - events.emit(CONSTANTS.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); + events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(5); // remember, we added 2 timeout events @@ -268,7 +268,7 @@ describe('', function() { }); it('should handle winning bid', function() { - events.emit(CONSTANTS.EVENTS.BID_WON, RESPONSE); + events.emit(EVENTS.BID_WON, RESPONSE); const ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(6); expect(ev[5]).to.be.eql({ @@ -287,7 +287,7 @@ describe('', function() { it('should handle auction end event', function() { timer.tick(447); - events.emit(CONSTANTS.EVENTS.AUCTION_END, RESPONSE); + events.emit(EVENTS.AUCTION_END, RESPONSE); let ev = analyticsAdapter.context.queue.peekAll(); expect(ev).to.have.length(0); expect(ajaxStub.calledOnce).to.be.equal(true); diff --git a/test/spec/modules/terceptAnalyticsAdapter_spec.js b/test/spec/modules/terceptAnalyticsAdapter_spec.js index a1384bfd919..8a0d04ff6b3 100644 --- a/test/spec/modules/terceptAnalyticsAdapter_spec.js +++ b/test/spec/modules/terceptAnalyticsAdapter_spec.js @@ -3,9 +3,9 @@ import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { server } from 'test/mocks/xhr.js'; +import { EVENTS } from 'src/constants.js'; let events = require('src/events'); -let constants = require('src/constants.json'); describe('tercept analytics adapter', function () { beforeEach(function () { @@ -753,19 +753,19 @@ describe('tercept analytics adapter', function () { it('builds and sends auction data', function () { // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); + events.emit(EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); + events.emit(EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); + events.emit(EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); + events.emit(EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, prebidEvent['auctionEnd']); + events.emit(EVENTS.AUCTION_END, prebidEvent['auctionEnd']); expect(server.requests.length).to.equal(1); @@ -774,7 +774,7 @@ describe('tercept analytics adapter', function () { expect(realAfterBid).to.deep.equal(expectedAfterBid); // Step 6: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, prebidEvent['bidWon']); + events.emit(EVENTS.BID_WON, prebidEvent['bidWon']); expect(server.requests.length).to.equal(2); diff --git a/test/spec/modules/trionBidAdapter_spec.js b/test/spec/modules/trionBidAdapter_spec.js index d7f09c2a057..2d0438e37e5 100644 --- a/test/spec/modules/trionBidAdapter_spec.js +++ b/test/spec/modules/trionBidAdapter_spec.js @@ -3,7 +3,7 @@ import * as utils from 'src/utils.js'; import {spec, acceptPostMessage, getStorageData, setStorageData} from 'modules/trionBidAdapter.js'; import {deepClone} from 'src/utils.js'; -const CONSTANTS = require('src/constants.json'); +const CONSTANTS = require('src/constants.js'); const adloader = require('src/adloader'); const PLACEMENT_CODE = 'ad-tag'; diff --git a/test/spec/modules/ucfunnelAnalyticsAdapter_spec.js b/test/spec/modules/ucfunnelAnalyticsAdapter_spec.js index 2b7f047c85a..997586c195e 100644 --- a/test/spec/modules/ucfunnelAnalyticsAdapter_spec.js +++ b/test/spec/modules/ucfunnelAnalyticsAdapter_spec.js @@ -6,7 +6,7 @@ import { import {expect} from 'chai'; const events = require('src/events'); -const constants = require('src/constants.json'); +const constants = require('src/constants.js'); const pbuid = 'pbuid-AA778D8A796AEA7A0843E2BBEB677766'; const adid = 'test-ad-83444226E44368D1E32E49EEBE6D29'; diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index 1e909d79ed4..2ff19424e09 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -18,7 +18,7 @@ import {config} from 'src/config.js'; import * as utils from 'src/utils.js'; import {getPrebidInternal} from 'src/utils.js'; import * as events from 'src/events.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import {getGlobal} from 'src/prebidGlobal.js'; import {resetConsentData, } from 'modules/consentManagement.js'; import {server} from 'test/mocks/xhr.js'; @@ -1714,7 +1714,7 @@ describe('User ID', function () { // check user sync is delayed after auction is ended mockIdCallback.calledOnce.should.equal(false); events.on.calledOnce.should.equal(true); - events.on.calledWith(CONSTANTS.EVENTS.AUCTION_END, sinon.match.func); + events.on.calledWith(EVENTS.AUCTION_END, sinon.match.func); // once auction is ended, sync user ids after delay events.on.callArg(1); @@ -1748,7 +1748,7 @@ describe('User ID', function () { // sync delay after auction is ended mockIdCallback.calledOnce.should.equal(false); events.on.calledOnce.should.equal(true); - events.on.calledWith(CONSTANTS.EVENTS.AUCTION_END, sinon.match.func); + events.on.calledWith(EVENTS.AUCTION_END, sinon.match.func); // once auction is ended, if no sync delay, fetch ids events.on.callArg(1); @@ -3104,7 +3104,7 @@ describe('User ID', function () { }); function endAuction() { - events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); + events.emit(EVENTS.AUCTION_END, {}); return new Promise((resolve) => setTimeout(resolve)); } diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js index 1ccd9766eab..58af1a15e43 100644 --- a/test/spec/modules/videoModule/pbVideo_spec.js +++ b/test/spec/modules/videoModule/pbVideo_spec.js @@ -1,7 +1,7 @@ import 'src/prebid.js'; import { expect } from 'chai'; import { PbVideo } from 'modules/videoModule'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; let ortbVideoMock; let ortbContentMock; @@ -225,7 +225,7 @@ describe('Prebid Video', function () { const pbEvents = { emit: () => {}, on: (event, callback) => { - if (event === CONSTANTS.EVENTS.AUCTION_END) { + if (event === EVENTS.AUCTION_END) { auctionEndCallback = callback } }, @@ -337,7 +337,7 @@ describe('Prebid Video', function () { const pbEvents = { on: (event, callback) => { - if (event === CONSTANTS.EVENTS.BID_ADJUSTMENT) { + if (event === EVENTS.BID_ADJUSTMENT) { bidAdjustmentCb = callback; } else if (event === 'videoAdImpression') { adImpressionCb = callback; diff --git a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js index ea52f89773e..88438f383ee 100644 --- a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +++ b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js @@ -2,9 +2,10 @@ import yieldoneAnalytics from 'modules/yieldoneAnalyticsAdapter.js'; import { targeting } from 'src/targeting.js'; import { expect } from 'chai'; import _ from 'lodash'; +import { EVENTS } from 'src/constants.js'; + let events = require('src/events'); let adapterManager = require('src/adapterManager').default; -let constants = require('src/constants.json'); describe('Yieldone Prebid Analytic', function () { let sendStatStub; @@ -187,38 +188,38 @@ describe('Yieldone Prebid Analytic', function () { const expectedEvents = [ { - eventType: constants.EVENTS.AUCTION_INIT, + eventType: EVENTS.AUCTION_INIT, params: { config: initOptions, auctionId: auctionId } }, { - eventType: constants.EVENTS.BID_REQUESTED, + eventType: EVENTS.BID_REQUESTED, params: Object.assign(request[0]) }, { - eventType: constants.EVENTS.BID_REQUESTED, + eventType: EVENTS.BID_REQUESTED, params: Object.assign(request[1]) }, { - eventType: constants.EVENTS.BID_REQUESTED, + eventType: EVENTS.BID_REQUESTED, params: Object.assign(request[2]) }, { - eventType: constants.EVENTS.BID_RESPONSE, + eventType: EVENTS.BID_RESPONSE, params: Object.assign(preparedResponses[0]) }, { - eventType: constants.EVENTS.BID_RESPONSE, + eventType: EVENTS.BID_RESPONSE, params: Object.assign(preparedResponses[1]) }, { - eventType: constants.EVENTS.BID_RESPONSE, + eventType: EVENTS.BID_RESPONSE, params: Object.assign(preparedResponses[2]) }, { - eventType: constants.EVENTS.BID_TIMEOUT, + eventType: EVENTS.BID_TIMEOUT, params: Object.assign(request[2]) } ]; @@ -235,7 +236,7 @@ describe('Yieldone Prebid Analytic', function () { delete preparedWinnerParams.ad; const wonExpectedEvents = [ { - eventType: constants.EVENTS.BID_WON, + eventType: EVENTS.BID_WON, params: preparedWinnerParams } ]; @@ -251,29 +252,29 @@ describe('Yieldone Prebid Analytic', function () { options: initOptions }); - events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, auctionId: auctionId}); + events.emit(EVENTS.AUCTION_INIT, { config: initOptions, auctionId: auctionId }); - events.emit(constants.EVENTS.BID_REQUESTED, request[0]); - events.emit(constants.EVENTS.BID_REQUESTED, request[1]); - events.emit(constants.EVENTS.BID_REQUESTED, request[2]); + events.emit(EVENTS.BID_REQUESTED, request[0]); + events.emit(EVENTS.BID_REQUESTED, request[1]); + events.emit(EVENTS.BID_REQUESTED, request[2]); - events.emit(constants.EVENTS.BID_RESPONSE, responses[0]); - events.emit(constants.EVENTS.BID_RESPONSE, responses[1]); - events.emit(constants.EVENTS.BID_RESPONSE, responses[2]); + events.emit(EVENTS.BID_RESPONSE, responses[0]); + events.emit(EVENTS.BID_RESPONSE, responses[1]); + events.emit(EVENTS.BID_RESPONSE, responses[2]); - events.emit(constants.EVENTS.BID_TIMEOUT, [responses[3], responses[4]]); + events.emit(EVENTS.BID_TIMEOUT, [responses[3], responses[4]]); - events.emit(constants.EVENTS.AUCTION_END, auctionEnd); + events.emit(EVENTS.AUCTION_END, auctionEnd); sinon.assert.match(yieldoneAnalytics.eventsStorage[auctionId], expectedResult); delete yieldoneAnalytics.eventsStorage[auctionId]; setTimeout(function() { - events.emit(constants.EVENTS.BID_WON, winner); + events.emit(EVENTS.BID_WON, winner); sinon.assert.callCount(sendStatStub, 2) - const billableEventIndex = yieldoneAnalytics.eventsStorage[auctionId].events.findIndex(event => event.eventType === constants.EVENTS.BILLABLE_EVENT); + const billableEventIndex = yieldoneAnalytics.eventsStorage[auctionId].events.findIndex(event => event.eventType === EVENTS.BILLABLE_EVENT); if (billableEventIndex > -1) { yieldoneAnalytics.eventsStorage[auctionId].events.splice(billableEventIndex, 1); } diff --git a/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js b/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js index e8eb4ab73be..c0de9a0e2fa 100644 --- a/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js +++ b/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js @@ -1,7 +1,8 @@ import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter.js'; import { expect } from 'chai'; +import { EVENTS } from 'src/constants.js'; + let events = require('src/events'); -let constants = require('src/constants.json'); let prebidAuction = { 'auctionInit': { @@ -402,7 +403,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); + events.emit(EVENTS.AUCTION_INIT, prebidAuction[EVENTS.AUCTION_INIT]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -417,7 +418,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); + events.emit(EVENTS.BID_REQUESTED, prebidAuction[EVENTS.BID_REQUESTED]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -432,7 +433,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); + events.emit(EVENTS.NO_BID, prebidAuction[EVENTS.NO_BID]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -447,7 +448,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); + events.emit(EVENTS.BID_TIMEOUT, prebidAuction[EVENTS.BID_TIMEOUT]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -462,7 +463,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); + events.emit(EVENTS.BID_RESPONSE, prebidAuction[EVENTS.BID_RESPONSE]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -477,7 +478,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + events.emit(EVENTS.AUCTION_END, prebidAuction[EVENTS.AUCTION_END]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -488,11 +489,11 @@ describe('yuktamedia analytics adapter', function () { } }); - events.emit(constants.EVENTS.AUCTION_INIT, {}); - events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_REQUESTED, {}); - events.emit(constants.EVENTS.BID_RESPONSE, {}); - events.emit(constants.EVENTS.BID_WON, {}); + events.emit(EVENTS.AUCTION_INIT, {}); + events.emit(EVENTS.AUCTION_END, {}); + events.emit(EVENTS.BID_REQUESTED, {}); + events.emit(EVENTS.BID_RESPONSE, {}); + events.emit(EVENTS.BID_WON, {}); sinon.assert.callCount(yuktamediaAnalyticsAdapter.track, 0); }); @@ -508,7 +509,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_INIT, prebidNativeAuction[constants.EVENTS.AUCTION_INIT]); + events.emit(EVENTS.AUCTION_INIT, prebidNativeAuction[EVENTS.AUCTION_INIT]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -523,7 +524,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_REQUESTED, prebidNativeAuction[constants.EVENTS.BID_REQUESTED]); + events.emit(EVENTS.BID_REQUESTED, prebidNativeAuction[EVENTS.BID_REQUESTED]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -538,7 +539,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_REQUESTED, prebidNativeAuction[constants.EVENTS.BID_REQUESTED + '1']); + events.emit(EVENTS.BID_REQUESTED, prebidNativeAuction[EVENTS.BID_REQUESTED + '1']); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -553,7 +554,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.NO_BID, prebidNativeAuction[constants.EVENTS.NO_BID]); + events.emit(EVENTS.NO_BID, prebidNativeAuction[EVENTS.NO_BID]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -568,7 +569,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_TIMEOUT, prebidNativeAuction[constants.EVENTS.BID_TIMEOUT]); + events.emit(EVENTS.BID_TIMEOUT, prebidNativeAuction[EVENTS.BID_TIMEOUT]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -583,7 +584,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.BID_RESPONSE, prebidNativeAuction[constants.EVENTS.BID_RESPONSE]); + events.emit(EVENTS.BID_RESPONSE, prebidNativeAuction[EVENTS.BID_RESPONSE]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -598,7 +599,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_END, prebidNativeAuction[constants.EVENTS.AUCTION_END]); + events.emit(EVENTS.AUCTION_END, prebidNativeAuction[EVENTS.AUCTION_END]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); @@ -613,7 +614,7 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_END, prebidNativeAuction[constants.EVENTS.BID_WON]); + events.emit(EVENTS.AUCTION_END, prebidNativeAuction[EVENTS.BID_WON]); sinon.assert.called(yuktamediaAnalyticsAdapter.track); }); }); @@ -681,12 +682,12 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); - events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); - events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); - events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); - events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); - events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + events.emit(EVENTS.AUCTION_INIT, prebidAuction[EVENTS.AUCTION_INIT]); + events.emit(EVENTS.BID_REQUESTED, prebidAuction[EVENTS.BID_REQUESTED]); + events.emit(EVENTS.NO_BID, prebidAuction[EVENTS.NO_BID]); + events.emit(EVENTS.BID_TIMEOUT, prebidAuction[EVENTS.BID_TIMEOUT]); + events.emit(EVENTS.BID_RESPONSE, prebidAuction[EVENTS.BID_RESPONSE]); + events.emit(EVENTS.AUCTION_END, prebidAuction[EVENTS.AUCTION_END]); expect(localStorage.getItem('yuktamediaAnalytics_session_id')).to.not.equal(null); }); @@ -701,12 +702,12 @@ describe('yuktamedia analytics adapter', function () { enableUserIdCollection: true } }); - events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); - events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); - events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); - events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); - events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); - events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + events.emit(EVENTS.AUCTION_INIT, prebidAuction[EVENTS.AUCTION_INIT]); + events.emit(EVENTS.BID_REQUESTED, prebidAuction[EVENTS.BID_REQUESTED]); + events.emit(EVENTS.NO_BID, prebidAuction[EVENTS.NO_BID]); + events.emit(EVENTS.BID_TIMEOUT, prebidAuction[EVENTS.BID_TIMEOUT]); + events.emit(EVENTS.BID_RESPONSE, prebidAuction[EVENTS.BID_RESPONSE]); + events.emit(EVENTS.AUCTION_END, prebidAuction[EVENTS.AUCTION_END]); expect(localStorage.getItem('yuktamediaAnalytics_session_id')).to.equal(null); }); }); diff --git a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js index 54b61f19506..fa4b50d7693 100644 --- a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js @@ -1,13 +1,13 @@ import zetaAnalyticsAdapter from 'modules/zeta_global_sspAnalyticsAdapter.js'; import {config} from 'src/config'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import {server} from '../../mocks/xhr.js'; import {logError} from '../../../src/utils'; let utils = require('src/utils'); let events = require('src/events'); -const EVENTS = { +const SAMPLE_EVENTS = { AUCTION_END: { 'auctionId': '75e394d9', 'timestamp': 1638441234544, @@ -388,22 +388,22 @@ describe('Zeta Global SSP Analytics Adapter', function() { it('Move ZetaParams through analytics events', function() { this.timeout(3000); - events.emit(CONSTANTS.EVENTS.AUCTION_END, EVENTS.AUCTION_END); - events.emit(CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, EVENTS.AD_RENDER_SUCCEEDED); + events.emit(EVENTS.AUCTION_END, SAMPLE_EVENTS.AUCTION_END); + events.emit(EVENTS.AD_RENDER_SUCCEEDED, SAMPLE_EVENTS.AD_RENDER_SUCCEEDED); expect(requests.length).to.equal(2); const auctionEnd = JSON.parse(requests[0].requestBody); const auctionSucceeded = JSON.parse(requests[1].requestBody); - expect(auctionSucceeded.bid.params[0]).to.be.deep.equal(EVENTS.AUCTION_END.adUnits[0].bids[0].params); - expect(EVENTS.AUCTION_END.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp'); + expect(auctionSucceeded.bid.params[0]).to.be.deep.equal(SAMPLE_EVENTS.AUCTION_END.adUnits[0].bids[0].params); + expect(SAMPLE_EVENTS.AUCTION_END.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp'); }); it('Keep only needed fields', function() { this.timeout(3000); - events.emit(CONSTANTS.EVENTS.AUCTION_END, EVENTS.AUCTION_END); - events.emit(CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, EVENTS.AD_RENDER_SUCCEEDED); + events.emit(EVENTS.AUCTION_END, SAMPLE_EVENTS.AUCTION_END); + events.emit(EVENTS.AD_RENDER_SUCCEEDED, SAMPLE_EVENTS.AD_RENDER_SUCCEEDED); expect(requests.length).to.equal(2); const auctionEnd = JSON.parse(requests[0].requestBody); diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js index 9184601a76d..5d1a43cc57f 100644 --- a/test/spec/native_spec.js +++ b/test/spec/native_spec.js @@ -16,7 +16,7 @@ import { fireClickTrackers, setNativeResponseProperties, } from 'src/native.js'; -import CONSTANTS from 'src/constants.json'; +import { NATIVE_KEYS } from 'src/constants.js'; import { stubAuctionIndex } from '../helpers/indexStub.js'; import { convertOrtbRequestToProprietaryNative, fromOrtbNativeRequest } from '../../src/native.js'; import {auctionManager} from '../../src/auctionManager.js'; @@ -199,9 +199,9 @@ describe('native.js', function () { it('gets native targeting keys', function () { const targeting = getNativeTargeting(bid); - expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal(bid.native.title); - expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal(bid.native.body); - expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal( + expect(targeting[NATIVE_KEYS.title]).to.equal(bid.native.title); + expect(targeting[NATIVE_KEYS.body]).to.equal(bid.native.body); + expect(targeting[NATIVE_KEYS.clickUrl]).to.equal( bid.native.clickUrl ); expect(targeting.hb_native_foo).to.equal(bid.native.foo); @@ -230,11 +230,11 @@ describe('native.js', function () { }; const targeting = getNativeTargeting(bid, deps(adUnit)); - expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal(bid.native.title); - expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal( + expect(targeting[NATIVE_KEYS.title]).to.equal(bid.native.title); + expect(targeting[NATIVE_KEYS.body]).to.equal( 'hb_native_body:123' ); - expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal( + expect(targeting[NATIVE_KEYS.clickUrl]).to.equal( 'hb_native_linkurl:123' ); expect(targeting.hb_native_foo).to.equal(bid.native.ext.foo); @@ -244,9 +244,9 @@ describe('native.js', function () { it('sends placeholdes targetings with ortb native response', function () { const targeting = getNativeTargeting(completeNativeBid); - expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal('Native Creative'); - expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal('Cool description great stuff'); - expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal('https://www.link.example'); + expect(targeting[NATIVE_KEYS.title]).to.equal('Native Creative'); + expect(targeting[NATIVE_KEYS.body]).to.equal('Cool description great stuff'); + expect(targeting[NATIVE_KEYS.clickUrl]).to.equal('https://www.link.example'); }); it('should only include native targeting keys with values', function () { @@ -269,9 +269,9 @@ describe('native.js', function () { const targeting = getNativeTargeting(bidWithUndefinedFields, deps(adUnit)); expect(Object.keys(targeting)).to.deep.equal([ - CONSTANTS.NATIVE_KEYS.title, - CONSTANTS.NATIVE_KEYS.sponsoredBy, - CONSTANTS.NATIVE_KEYS.clickUrl, + NATIVE_KEYS.title, + NATIVE_KEYS.sponsoredBy, + NATIVE_KEYS.clickUrl, 'hb_native_foo', ]); }); @@ -294,7 +294,7 @@ describe('native.js', function () { }; const targeting = getNativeTargeting(bid, deps(adUnit)); - expect(Object.keys(targeting)).to.deep.equal([CONSTANTS.NATIVE_KEYS.title]); + expect(Object.keys(targeting)).to.deep.equal([NATIVE_KEYS.title]); }); it('should only include targeting if sendTargetingKeys not set to false', function () { @@ -342,10 +342,10 @@ describe('native.js', function () { const targeting = getNativeTargeting(bid, deps(adUnit)); expect(Object.keys(targeting)).to.deep.equal([ - CONSTANTS.NATIVE_KEYS.title, - CONSTANTS.NATIVE_KEYS.body, - CONSTANTS.NATIVE_KEYS.image, - CONSTANTS.NATIVE_KEYS.clickUrl, + NATIVE_KEYS.title, + NATIVE_KEYS.body, + NATIVE_KEYS.image, + NATIVE_KEYS.clickUrl, 'hb_native_foo', ]); }); @@ -353,7 +353,7 @@ describe('native.js', function () { it('should include rendererUrl in targeting', function () { const rendererUrl = 'https://www.renderer.com/'; const targeting = getNativeTargeting({...bid, native: {...bid.native, rendererUrl: {url: rendererUrl}}}, deps({})); - expect(targeting[CONSTANTS.NATIVE_KEYS.rendererUrl]).to.eql(rendererUrl); + expect(targeting[NATIVE_KEYS.rendererUrl]).to.eql(rendererUrl); }); it('fires impression trackers', function () { diff --git a/test/spec/unit/adRendering_spec.js b/test/spec/unit/adRendering_spec.js index c2f62842c7e..df837e5547e 100644 --- a/test/spec/unit/adRendering_spec.js +++ b/test/spec/unit/adRendering_spec.js @@ -7,7 +7,7 @@ import { handleNativeMessage, handleRender } from '../../../src/adRendering.js'; -import CONSTANTS from 'src/constants.json'; +import { AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS } from 'src/constants.js'; import {expect} from 'chai/index.mjs'; import {config} from 'src/config.js'; import {VIDEO} from '../../../src/mediaTypes.js'; @@ -65,7 +65,7 @@ describe('adRendering', () => { }); function expectAdRenderFailedEvent(reason) { - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({adId, reason})); + sinon.assert.calledWith(events.emit, EVENTS.AD_RENDER_FAILED, sinon.match({ adId, reason })); } describe('doRender', () => { @@ -103,7 +103,7 @@ describe('adRendering', () => { it('emits AD_RENDER_SUCCEDED', () => { doRender({renderFn, bidResponse}); - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, sinon.match({ + sinon.assert.calledWith(events.emit, EVENTS.AD_RENDER_SUCCEEDED, sinon.match({ bid: bidResponse, adId: bidResponse.adId })); @@ -114,7 +114,7 @@ describe('adRendering', () => { it('should emit AD_RENDER_FAILED on video bids', () => { bidResponse.mediaType = VIDEO; doRender({renderFn, bidResponse}); - expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT) + expectAdRenderFailedEvent(AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT) }); } @@ -159,26 +159,26 @@ describe('adRendering', () => { describe('should emit AD_RENDER_FAILED', () => { it('when bidResponse is missing', () => { handleRender({adId}); - expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD); + expectAdRenderFailedEvent(AD_RENDER_FAILED_REASON.CANNOT_FIND_AD); sinon.assert.notCalled(doRenderStub); }); it('on exceptions', () => { doRenderStub.throws(new Error()); handleRender({adId, bidResponse}); - expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION); + expectAdRenderFailedEvent(AD_RENDER_FAILED_REASON.EXCEPTION); }); }) describe('when bid was already rendered', () => { beforeEach(() => { - bidResponse.status = CONSTANTS.BID_STATUS.RENDERED; + bidResponse.status = BID_STATUS.RENDERED; }); afterEach(() => { config.resetConfig(); }) it('should emit STALE_RENDER', () => { handleRender({adId, bidResponse}); - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.STALE_RENDER, bidResponse); + sinon.assert.calledWith(events.emit, EVENTS.STALE_RENDER, bidResponse); sinon.assert.called(doRenderStub); }); it('should skip rendering if suppressStaleRender', () => { @@ -190,7 +190,7 @@ describe('adRendering', () => { it('should mark bid as won and emit BID_WON', () => { handleRender({renderFn, bidResponse}); - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.BID_WON, bidResponse); + sinon.assert.calledWith(events.emit, EVENTS.BID_WON, bidResponse); sinon.assert.calledWith(auctionManager.addWinningBid, bidResponse); }) }) @@ -201,17 +201,17 @@ describe('adRendering', () => { beforeEach(() => { sandbox.stub(events, 'emit'); bid = { - status: CONSTANTS.BID_STATUS.RENDERED + status: BID_STATUS.RENDERED } }); it('emits AD_RENDER_FAILED with given reason', () => { - handleCreativeEvent({event: CONSTANTS.EVENTS.AD_RENDER_FAILED, info: {reason: 'reason', message: 'message'}}, bid); - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({bid, reason: 'reason', message: 'message'})); + handleCreativeEvent({ event: EVENTS.AD_RENDER_FAILED, info: { reason: 'reason', message: 'message' } }, bid); + sinon.assert.calledWith(events.emit, EVENTS.AD_RENDER_FAILED, sinon.match({ bid, reason: 'reason', message: 'message' })); }); it('emits AD_RENDER_SUCCEEDED', () => { - handleCreativeEvent({event: CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED}, bid); - sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, sinon.match({bid})); + handleCreativeEvent({ event: EVENTS.AD_RENDER_SUCCEEDED }, bid); + sinon.assert.calledWith(events.emit, EVENTS.AD_RENDER_SUCCEEDED, sinon.match({ bid })); }); it('logs an error on other events', () => { diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index dac70696b4b..590d4829b49 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -12,7 +12,7 @@ import { getServerTestingsAds, getBidRequests } from 'test/fixtures/fixtures.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS, S2S } from 'src/constants.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; import { registerBidder } from 'src/adapters/bidderFactory.js'; @@ -28,7 +28,7 @@ var events = require('../../../../src/events'); const CONFIG = { enabled: true, - endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT, + endpoint: S2S.DEFAULT_ENDPOINT, timeout: 1000, maxBids: 1, adapter: 'prebidServer', @@ -172,7 +172,7 @@ describe('adapterManager tests', function () { // function to count BID_REQUESTED events let cnt = 0; let count = () => cnt++; - events.on(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.on(EVENTS.BID_REQUESTED, count); let bidRequests = [{ 'bidderCode': 'appnexus', 'auctionId': '1863e370099523', @@ -207,7 +207,7 @@ describe('adapterManager tests', function () { adapterManager.callBids(adUnits, bidRequests, () => {}, () => {}); expect(cnt).to.equal(1); sinon.assert.calledOnce(appnexusAdapterMock.callBids); - events.off(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.off(EVENTS.BID_REQUESTED, count); }); it('should give bidders access to bidder-specific config', function(done) { @@ -390,7 +390,7 @@ describe('adapterManager tests', function () { }); it('should NOT call onBidWon when the bid is S2S', () => { - bids[0].src = CONSTANTS.S2S.SRC + bids[0].src = S2S.SRC adapterManager.callBidWonBidder(bids[0].bidder, bids[0], adUnits); sinon.assert.notCalled(criteoSpec.onBidWon); }) @@ -407,7 +407,7 @@ describe('adapterManager tests', function () { }); it('should NOT call onSetTargeting when bid is S2S', () => { - bids[0].src = CONSTANTS.S2S.SRC; + bids[0].src = S2S.SRC; adapterManager.callSetTargetingBidder(bids[0].bidder, bids[0], adUnits); sinon.assert.notCalled(criteoSpec.onSetTargeting); }) @@ -421,7 +421,7 @@ describe('adapterManager tests', function () { sinon.assert.called(criteoSpec.onBidViewable); }); it('should NOT call onBidViewable when bid is S2S', () => { - bids[0].src = CONSTANTS.S2S.SRC; + bids[0].src = S2S.SRC; adapterManager.callBidViewableBidder(bids[0].bidder, bids[0]); sinon.assert.notCalled(criteoSpec.onBidViewable); }) @@ -649,11 +649,11 @@ describe('adapterManager tests', function () { beforeEach(function () { prebidServerAdapterMock.callBids.reset(); cnt = 0; - events.on(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.on(EVENTS.BID_REQUESTED, count); }); afterEach(function () { - events.off(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.off(EVENTS.BID_REQUESTED, count); }); it('should fire for s2s requests', function () { @@ -1037,11 +1037,11 @@ describe('adapterManager tests', function () { beforeEach(function () { prebidServerAdapterMock.callBids.reset(); cnt = 0; - events.on(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.on(EVENTS.BID_REQUESTED, count); }); afterEach(function () { - events.off(CONSTANTS.EVENTS.BID_REQUESTED, count); + events.off(EVENTS.BID_REQUESTED, count); }); it('should fire for s2s requests', function () { @@ -1691,7 +1691,7 @@ describe('adapterManager tests', function () { }) } - events.on(CONSTANTS.EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); + events.on(EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); adapterManager.makeBidRequests( adUnits, Date.now(), @@ -1700,7 +1700,7 @@ describe('adapterManager tests', function () { }, [] ); - events.off(CONSTANTS.EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); + events.off(EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); expect(adUnits.map((u) => u.nativeParams).some(i => i == null)).to.be.false; }); } @@ -2075,11 +2075,11 @@ describe('adapterManager tests', function () { const ortb2Fragments = {}; const req = { bidderCode: 'appnexus', - src: CONSTANTS.S2S.SRC, + src: S2S.SRC, adUnitsS2SCopy: adUnits, bids: [{ bidder: 'appnexus', - src: CONSTANTS.S2S.SRC + src: S2S.SRC }] }; adapterManager.callBids(adUnits, [req], sinon.stub(), sinon.stub(), {request: sinon.stub(), done: sinon.stub()}, 1000, sinon.stub(), ortb2Fragments); diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index 5fe5a1accfc..1e70c938a57 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -5,7 +5,7 @@ import {expect} from 'chai'; import {userSync} from 'src/userSync.js'; import * as utils from 'src/utils.js'; import {config} from 'src/config.js'; -import CONSTANTS from 'src/constants.json'; +import { EVENTS } from 'src/constants.js'; import * as events from 'src/events.js'; import {hook} from '../../../../src/hook.js'; import {auctionManager} from '../../../../src/auctionManager.js'; @@ -552,7 +552,7 @@ describe('bidderFactory', () => { expect(ajaxStub.calledTwice).to.equal(true); expect(eventEmitterSpy.getCalls() - .filter(call => call.args[0] === CONSTANTS.EVENTS.BEFORE_BIDDER_HTTP) + .filter(call => call.args[0] === EVENTS.BEFORE_BIDDER_HTTP) ).to.length(2); eventEmitterSpy.restore(); @@ -863,7 +863,7 @@ describe('bidderFactory', () => { expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE); expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock); expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST); - sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, { + sinon.assert.calledWith(eventEmitterStub, EVENTS.BIDDER_ERROR, { error: xhrErrorMock, bidderRequest: MOCK_BIDS_REQUEST }); @@ -889,7 +889,7 @@ describe('bidderFactory', () => { expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE); expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock); expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST); - sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, { + sinon.assert.calledWith(eventEmitterStub, EVENTS.BIDDER_ERROR, { error: xhrErrorMock, bidderRequest: MOCK_BIDS_REQUEST }); @@ -915,7 +915,7 @@ describe('bidderFactory', () => { expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE); expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock); expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST); - sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, { + sinon.assert.calledWith(eventEmitterStub, EVENTS.BIDDER_ERROR, { error: xhrErrorMock, bidderRequest: MOCK_BIDS_REQUEST }); @@ -941,7 +941,7 @@ describe('bidderFactory', () => { expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE); expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock); expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST); - sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, { + sinon.assert.calledWith(eventEmitterStub, EVENTS.BIDDER_ERROR, { error: xhrErrorMock, bidderRequest: MOCK_BIDS_REQUEST }); diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index ba9aeff70d1..54ea942e373 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -7,7 +7,7 @@ import { } from 'src/targeting.js'; import {config} from 'src/config.js'; import {createBidReceived} from 'test/fixtures/fixtures.js'; -import CONSTANTS from 'src/constants.json'; +import { DEFAULT_TARGETING_KEYS, JSON_MAPPING, NATIVE_KEYS, STATUS, TARGETING_KEYS } from 'src/constants.js'; import {auctionManager} from 'src/auctionManager.js'; import * as utils from 'src/utils.js'; import {deepClone} from 'src/utils.js'; @@ -15,7 +15,7 @@ import {createBid} from '../../../../src/bidfactory.js'; import {hook} from '../../../../src/hook.js'; import {getHighestCpm} from '../../../../src/utils/reducers.js'; -function mkBid(bid, status = CONSTANTS.STATUS.GOOD) { +function mkBid(bid, status = STATUS.GOOD) { return Object.assign(createBid(status), bid); } @@ -40,10 +40,10 @@ const sampleBid = { 'size': '300x250', 'adserverTargeting': { 'foobar': '300x250', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'rubicon', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '148018fe5e', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '0.53', - [CONSTANTS.TARGETING_KEYS.DEAL]: '1234' + [TARGETING_KEYS.BIDDER]: 'rubicon', + [TARGETING_KEYS.AD_ID]: '148018fe5e', + [TARGETING_KEYS.PRICE_BUCKET]: '0.53', + [TARGETING_KEYS.DEAL]: '1234' }, 'dealId': '1234', 'netRevenue': true, @@ -74,9 +74,9 @@ const bid2 = mkBid({ 'size': '300x250', 'adserverTargeting': { 'foobar': '300x250', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'rubicon', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '5454545', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '0.25' + [TARGETING_KEYS.BIDDER]: 'rubicon', + [TARGETING_KEYS.AD_ID]: '5454545', + [TARGETING_KEYS.PRICE_BUCKET]: '0.25' }, 'netRevenue': true, 'currency': 'USD', @@ -104,9 +104,9 @@ const bid3 = mkBid({ 'size': '300x600', 'adserverTargeting': { 'foobar': '300x600', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'rubicon', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '48747745', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '0.75' + [TARGETING_KEYS.BIDDER]: 'rubicon', + [TARGETING_KEYS.AD_ID]: '48747745', + [TARGETING_KEYS.PRICE_BUCKET]: '0.75' }, 'netRevenue': true, 'currency': 'USD', @@ -166,18 +166,18 @@ const nativeBid1 = mkBid({ 'pbCg': '', 'size': '0x0', 'adserverTargeting': { - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '591e7c9354b633', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.SIZE]: '0x0', - [CONSTANTS.TARGETING_KEYS.SOURCE]: 'client', - [CONSTANTS.TARGETING_KEYS.FORMAT]: 'native', - [CONSTANTS.NATIVE_KEYS.title]: 'This is a Prebid Native Creative', - [CONSTANTS.NATIVE_KEYS.body]: 'This is a Prebid Native Creative. There are many like it, but this one is mine.', - [CONSTANTS.NATIVE_KEYS.sponsoredBy]: 'Prebid.org', - [CONSTANTS.NATIVE_KEYS.clickUrl]: 'http://prebid.org/dev-docs/show-native-ads.html', - [CONSTANTS.NATIVE_KEYS.image]: 'http://vcdn.adnxs.com/p/creative-image/94/22/cd/0f/9422cd0f-f400-45d3-80f5-2b92629d9257.jpg', - [CONSTANTS.NATIVE_KEYS.icon]: 'http://vcdn.adnxs.com/p/creative-image/bd/59/a6/c6/bd59a6c6-0851-411d-a16d-031475a51312.png' + [TARGETING_KEYS.BIDDER]: 'appnexus', + [TARGETING_KEYS.AD_ID]: '591e7c9354b633', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.SIZE]: '0x0', + [TARGETING_KEYS.SOURCE]: 'client', + [TARGETING_KEYS.FORMAT]: 'native', + [NATIVE_KEYS.title]: 'This is a Prebid Native Creative', + [NATIVE_KEYS.body]: 'This is a Prebid Native Creative. There are many like it, but this one is mine.', + [NATIVE_KEYS.sponsoredBy]: 'Prebid.org', + [NATIVE_KEYS.clickUrl]: 'http://prebid.org/dev-docs/show-native-ads.html', + [NATIVE_KEYS.image]: 'http://vcdn.adnxs.com/p/creative-image/94/22/cd/0f/9422cd0f-f400-45d3-80f5-2b92629d9257.jpg', + [NATIVE_KEYS.icon]: 'http://vcdn.adnxs.com/p/creative-image/bd/59/a6/c6/bd59a6c6-0851-411d-a16d-031475a51312.png' } }); @@ -225,17 +225,17 @@ const nativeBid2 = mkBid({ 'pbCg': '', 'size': '0x0', 'adserverTargeting': { - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'dgads', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '6e0aba55ed54e5', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '1.90', - [CONSTANTS.TARGETING_KEYS.SIZE]: '0x0', - [CONSTANTS.TARGETING_KEYS.SOURCE]: 'client', - [CONSTANTS.TARGETING_KEYS.FORMAT]: 'native', - [CONSTANTS.NATIVE_KEYS.image]: 'https://ads-tr.bigmining.com/img/300x250.png', - [CONSTANTS.NATIVE_KEYS.title]: 'Test Title', - [CONSTANTS.NATIVE_KEYS.body]: 'Test Description', - [CONSTANTS.NATIVE_KEYS.sponsoredBy]: 'test.com', - [CONSTANTS.NATIVE_KEYS.clickUrl]: 'http://prebid.org/' + [TARGETING_KEYS.BIDDER]: 'dgads', + [TARGETING_KEYS.AD_ID]: '6e0aba55ed54e5', + [TARGETING_KEYS.PRICE_BUCKET]: '1.90', + [TARGETING_KEYS.SIZE]: '0x0', + [TARGETING_KEYS.SOURCE]: 'client', + [TARGETING_KEYS.FORMAT]: 'native', + [NATIVE_KEYS.image]: 'https://ads-tr.bigmining.com/img/300x250.png', + [NATIVE_KEYS.title]: 'Test Title', + [NATIVE_KEYS.body]: 'Test Description', + [NATIVE_KEYS.sponsoredBy]: 'test.com', + [NATIVE_KEYS.clickUrl]: 'http://prebid.org/' } }); @@ -351,7 +351,7 @@ describe('targeting tests', function () { return [ { 'code': adUnitCode, - [CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]: adServerTargeting + [JSON_MAPPING.ADSERVER_TARGETING]: adServerTargeting } ]; }); @@ -489,7 +489,7 @@ describe('targeting tests', function () { }); const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); - let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_') != -1) + let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(TARGETING_KEYS.PRICE_BUCKET + '_') != -1) expect(limitedBids.length).to.equal(1); }); @@ -502,7 +502,7 @@ describe('targeting tests', function () { }); const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); - let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_') != -1) + let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(TARGETING_KEYS.PRICE_BUCKET + '_') != -1) expect(limitedBids.length).to.equal(2); }); @@ -515,7 +515,7 @@ describe('targeting tests', function () { }); const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); - let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_') != -1) + let limitedBids = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(TARGETING_KEYS.PRICE_BUCKET + '_') != -1) expect(limitedBids.length).to.equal(2); }); @@ -611,7 +611,7 @@ describe('targeting tests', function () { beforeEach(function () { bidsReceived = [bid1, bid2, nativeBid1, nativeBid2].map(deepClone); bidsReceived.forEach((bid) => { - bid.adserverTargeting[CONSTANTS.TARGETING_KEYS.SOURCE] = 'test-source'; + bid.adserverTargeting[TARGETING_KEYS.SOURCE] = 'test-source'; bid.adUnitCode = 'adunit'; if (winningBid == null || bid.cpm > winningBid.cpm) { winningBid = bid; @@ -642,7 +642,7 @@ describe('targeting tests', function () { addTargetingKeys: ['SOURCE'] } }); - expect(targetingResult()).to.include.all.keys(...expandKey(CONSTANTS.TARGETING_KEYS.SOURCE)); + expect(targetingResult()).to.include.all.keys(...expandKey(TARGETING_KEYS.SOURCE)); }); it('should keep default and native keys', function() { @@ -651,9 +651,9 @@ describe('targeting tests', function () { addTargetingKeys: ['SOURCE'] } }); - const defaultKeys = new Set(Object.values(CONSTANTS.DEFAULT_TARGETING_KEYS)); + const defaultKeys = new Set(Object.values(DEFAULT_TARGETING_KEYS)); if (FEATURES.NATIVE) { - Object.values(CONSTANTS.NATIVE_KEYS).forEach((k) => defaultKeys.add(k)); + Object.values(NATIVE_KEYS).forEach((k) => defaultKeys.add(k)); } const expectedKeys = new Set(); @@ -670,8 +670,8 @@ describe('targeting tests', function () { it('should not be allowed together with allowTargetingKeys', function () { config.setConfig({ targetingControls: { - allowTargetingKeys: [CONSTANTS.TARGETING_KEYS.BIDDER], - addTargetingKeys: [CONSTANTS.TARGETING_KEYS.SOURCE] + allowTargetingKeys: [TARGETING_KEYS.BIDDER], + addTargetingKeys: [TARGETING_KEYS.SOURCE] } }); expect(targetingResult).to.throw(); @@ -849,12 +849,12 @@ describe('targeting tests', function () { // we should only get the targeting data for the one requested adunit expect(Object.keys(targeting).length).to.equal(1); - let sendAllBidCpm = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_') != -1) + let sendAllBidCpm = Object.keys(targeting['/123456/header-bid-tag-0']).filter(key => key.indexOf(TARGETING_KEYS.PRICE_BUCKET + '_') != -1) // we shouldn't get more than 1 key for hb_pb_${bidder} expect(sendAllBidCpm.length).to.equal(1); // expect the winning CPM to be equal to the sendAllBidCPM - expect(targeting['/123456/header-bid-tag-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon']).to.deep.equal(targeting['/123456/header-bid-tag-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]); + expect(targeting['/123456/header-bid-tag-0'][TARGETING_KEYS.PRICE_BUCKET + '_rubicon']).to.deep.equal(targeting['/123456/header-bid-tag-0'][TARGETING_KEYS.PRICE_BUCKET]); }); if (FEATURES.NATIVE) { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 7f55a2cddf0..deb80873cfa 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -27,6 +27,7 @@ import {enrichFPD} from '../../../src/fpd/enrichment.js'; import {mockFpdEnrichments} from '../../helpers/fpd.js'; import {generateUUID} from '../../../src/utils.js'; import {getCreativeRenderer} from '../../../src/creativeRenderers.js'; +import { BID_STATUS, EVENTS, GRANULARITY_OPTIONS, TARGETING_KEYS } from 'src/constants.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -34,7 +35,6 @@ var expect = require('chai').expect; var utils = require('src/utils'); var adapterManager = require('src/adapterManager').default; var events = require('src/events'); -var CONSTANTS = require('src/constants.json'); // These bid adapters are required to be loaded for the following tests to work require('modules/appnexusBidAdapter'); @@ -284,7 +284,7 @@ describe('Unit: Prebid Module', function () { it('should return targeting info as a string', function () { const adUnitCode = config.adUnitCodes[0]; $$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true }); - var expected = 'foobar=0x0%2C300x250%2C300x600&' + CONSTANTS.TARGETING_KEYS.SIZE + '=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_triplelift=0x0&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + CONSTANTS.TARGETING_KEYS.SIZE + '_appnexus=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pagescience=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brightcom=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brealtime=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + CONSTANTS.TARGETING_KEYS.SIZE + '_rubicon=300x600&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_rubicon=rubicon'; + var expected = 'foobar=0x0%2C300x250%2C300x600&' + TARGETING_KEYS.SIZE + '=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + TARGETING_KEYS.BIDDER + '=appnexus&' + TARGETING_KEYS.SIZE + '_triplelift=0x0&' + TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + TARGETING_KEYS.SIZE + '_appnexus=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + TARGETING_KEYS.SIZE + '_pagescience=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + TARGETING_KEYS.SIZE + '_brightcom=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + TARGETING_KEYS.SIZE + '_brealtime=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + TARGETING_KEYS.SIZE + '_rubicon=300x600&' + TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + TARGETING_KEYS.BIDDER + '_rubicon=rubicon'; var result = $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCodeStr(adUnitCode); assert.equal(expected, result, 'returns expected string of ad targeting info'); }); @@ -330,17 +330,17 @@ describe('Unit: Prebid Module', function () { var expected = { '/19968336/header-bid-tag-0': { foobar: '0x0,300x250,300x600', - [CONSTANTS.TARGETING_KEYS.SIZE]: '300x250', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '300x250', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '233bcbee889d46d', + [TARGETING_KEYS.BIDDER]: 'appnexus' }, '/19968336/header-bid-tag1': { foobar: '728x90', - [CONSTANTS.TARGETING_KEYS.SIZE]: '728x90', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '728x90', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', + [TARGETING_KEYS.BIDDER]: 'appnexus' } }; assert.deepEqual(targeting, expected); @@ -378,17 +378,17 @@ describe('Unit: Prebid Module', function () { '/19968336/header-bid-tag-0': { foobar: '300x250,300x600', always_use_me: 'abc', - [CONSTANTS.TARGETING_KEYS.SIZE]: '300x250', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '300x250', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '233bcbee889d46d', + [TARGETING_KEYS.BIDDER]: 'appnexus' }, '/19968336/header-bid-tag1': { foobar: '728x90', - [CONSTANTS.TARGETING_KEYS.SIZE]: '728x90', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '728x90', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', + [TARGETING_KEYS.BIDDER]: 'appnexus' } }; assert.deepEqual(targeting, expected); @@ -407,7 +407,7 @@ describe('Unit: Prebid Module', function () { $$PREBID_GLOBAL$$.bidderSettings = { 'standard': { adserverTargeting: [{ - key: CONSTANTS.TARGETING_KEYS.BIDDER, + key: TARGETING_KEYS.BIDDER, val: function(bidResponse) { return bidResponse.bidderCode; } @@ -417,7 +417,7 @@ describe('Unit: Prebid Module', function () { return bidResponse.adId; } }, { - key: CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + key: TARGETING_KEYS.PRICE_BUCKET, val: function(bidResponse) { return bidResponse.pbMg; } @@ -436,17 +436,17 @@ describe('Unit: Prebid Module', function () { '/19968336/header-bid-tag-0': { foobar: '300x250', custom_ad_id: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.SIZE]: '300x250', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '300x250', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '233bcbee889d46d', + [TARGETING_KEYS.BIDDER]: 'appnexus' }, '/19968336/header-bid-tag1': { foobar: '728x90', - [CONSTANTS.TARGETING_KEYS.SIZE]: '728x90', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus', + [TARGETING_KEYS.SIZE]: '728x90', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', + [TARGETING_KEYS.BIDDER]: 'appnexus', custom_ad_id: '24bd938435ec3fc' } }; @@ -607,32 +607,32 @@ describe('Unit: Prebid Module', function () { indexStub.restore(); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 0 to 5', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 0 to 5', function () { RESPONSE.tags[0].ads[0].cpm = 2.1234; auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('2.12'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('2.12'); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 5 to 8', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 5 to 8', function () { RESPONSE.tags[0].ads[0].cpm = 6.78; auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('6.75'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('6.75'); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 8 to 20', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 8 to 20', function () { RESPONSE.tags[0].ads[0].cpm = 19.5234; auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('19.50'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('19.50'); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 20 to 25', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' when using bid.cpm is between 20 to 25', function () { RESPONSE.tags[0].ads[0].cpm = 21.5234; auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('21.00'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('21.00'); }); }); @@ -867,7 +867,7 @@ describe('Unit: Prebid Module', function () { indexStub.restore(); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 0 - 5', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 0 - 5', function () { initTestConfig({ adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')], adUnitCodes: ['div-gpt-ad-1460505748561-0'] @@ -878,10 +878,10 @@ describe('Unit: Prebid Module', function () { auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.25'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.25'); }); - it('should get correct ' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 21 - 100', function() { + it('should get correct ' + TARGETING_KEYS.PRICE_BUCKET + ' with cpm between 21 - 100', function () { initTestConfig({ adUnits: [createAdUnit('div-gpt-ad-1460505748561-0')], adUnitCodes: ['div-gpt-ad-1460505748561-0'] @@ -892,7 +892,7 @@ describe('Unit: Prebid Module', function () { auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('43.00'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('43.00'); }); it('should only apply price granularity if bid media type matches', function () { @@ -906,7 +906,7 @@ describe('Unit: Prebid Module', function () { auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.25'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.25'); if (FEATURES.VIDEO) { ajaxStub.restore(); @@ -921,7 +921,7 @@ describe('Unit: Prebid Module', function () { auction.callBids(cbTimeout); let bidTargeting = targeting.getAllTargeting(); - expect(bidTargeting['div-gpt-ad-1460505748561-0'][CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.00'); + expect(bidTargeting['div-gpt-ad-1460505748561-0'][TARGETING_KEYS.PRICE_BUCKET]).to.equal('3.00'); } }); }); @@ -1067,7 +1067,7 @@ describe('Unit: Prebid Module', function () { $$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true }); $$PREBID_GLOBAL$$.setTargetingForGPTAsync('/19968336/header-bid-tag-0'); - expect(slots[0].spySetTargeting.args).to.deep.contain.members([[CONSTANTS.TARGETING_KEYS.BIDDER, 'appnexus'], [CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]); + expect(slots[0].spySetTargeting.args).to.deep.contain.members([[TARGETING_KEYS.BIDDER, 'appnexus'], [TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]); }); it('should set targeting when passed an array of ad unit codes with enableSendAllBids', function () { @@ -1076,7 +1076,7 @@ describe('Unit: Prebid Module', function () { $$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true }); $$PREBID_GLOBAL$$.setTargetingForGPTAsync(['/19968336/header-bid-tag-0']); - expect(slots[0].spySetTargeting.args).to.deep.contain.members([[CONSTANTS.TARGETING_KEYS.BIDDER, 'appnexus'], [CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]); + expect(slots[0].spySetTargeting.args).to.deep.contain.members([[TARGETING_KEYS.BIDDER, 'appnexus'], [TARGETING_KEYS.AD_ID + '_appnexus', '233bcbee889d46d'], [TARGETING_KEYS.PRICE_BUCKET + '_appnexus', '10.00']]); }); it('should set targeting from googletag data', function () { @@ -1123,19 +1123,19 @@ describe('Unit: Prebid Module', function () { var expected = [ [ - CONSTANTS.TARGETING_KEYS.BIDDER, + TARGETING_KEYS.BIDDER, 'appnexus' ], [ - CONSTANTS.TARGETING_KEYS.AD_ID, + TARGETING_KEYS.AD_ID, '233bcbee889d46d' ], [ - CONSTANTS.TARGETING_KEYS.PRICE_BUCKET, + TARGETING_KEYS.PRICE_BUCKET, '10.00' ], [ - CONSTANTS.TARGETING_KEYS.SIZE, + TARGETING_KEYS.SIZE, '300x250' ], [ @@ -1360,8 +1360,8 @@ describe('Unit: Prebid Module', function () { var onWonEvent = sinon.stub(); var onStaleEvent = sinon.stub(); - $$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.BID_WON, onWonEvent); - $$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.STALE_RENDER, onStaleEvent); + $$PREBID_GLOBAL$$.onEvent(EVENTS.BID_WON, onWonEvent); + $$PREBID_GLOBAL$$.onEvent(EVENTS.STALE_RENDER, onStaleEvent); pushBidResponseToAuction({ ad: "" @@ -1377,7 +1377,7 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledWith(onWonEvent, adResponse); sinon.assert.notCalled(onStaleEvent); - expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED); + expect(adResponse).to.have.property('status', BID_STATUS.RENDERED); // Reset call history for spies and stubs spyLogMessage.resetHistory(); @@ -1398,8 +1398,8 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledWith(onStaleEvent, adResponse); // Clean up - $$PREBID_GLOBAL$$.offEvent(CONSTANTS.EVENTS.BID_WON, onWonEvent); - $$PREBID_GLOBAL$$.offEvent(CONSTANTS.EVENTS.STALE_RENDER, onStaleEvent); + $$PREBID_GLOBAL$$.offEvent(EVENTS.BID_WON, onWonEvent); + $$PREBID_GLOBAL$$.offEvent(EVENTS.STALE_RENDER, onStaleEvent); }); it('should stop stale rendering', function () { @@ -1411,8 +1411,8 @@ describe('Unit: Prebid Module', function () { // Setting suppressStaleRender to true explicitly configObj.setConfig({'auctionOptions': {'suppressStaleRender': true}}); - $$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.BID_WON, onWonEvent); - $$PREBID_GLOBAL$$.onEvent(CONSTANTS.EVENTS.STALE_RENDER, onStaleEvent); + $$PREBID_GLOBAL$$.onEvent(EVENTS.BID_WON, onWonEvent); + $$PREBID_GLOBAL$$.onEvent(EVENTS.STALE_RENDER, onStaleEvent); pushBidResponseToAuction({ ad: "" @@ -1425,7 +1425,7 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledOnce(spyAddWinningBid); sinon.assert.calledWith(spyAddWinningBid, adResponse); - expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED); + expect(adResponse).to.have.property('status', BID_STATUS.RENDERED); sinon.assert.calledWith(onWonEvent, adResponse); sinon.assert.notCalled(onStaleEvent); @@ -1448,8 +1448,8 @@ describe('Unit: Prebid Module', function () { sinon.assert.calledWith(onStaleEvent, adResponse); // Clean up - $$PREBID_GLOBAL$$.offEvent(CONSTANTS.EVENTS.BID_WON, onWonEvent); - $$PREBID_GLOBAL$$.offEvent(CONSTANTS.EVENTS.STALE_RENDER, onStaleEvent); + $$PREBID_GLOBAL$$.offEvent(EVENTS.BID_WON, onWonEvent); + $$PREBID_GLOBAL$$.offEvent(EVENTS.STALE_RENDER, onStaleEvent); configObj.setConfig({'auctionOptions': {}}); }); }); @@ -2766,16 +2766,16 @@ describe('Unit: Prebid Module', function () { let expected = { '/19968336/header-bid-tag-0': { 'foobar': '0x0,300x250,300x600', - [CONSTANTS.TARGETING_KEYS.SIZE]: '300x250', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus' + [TARGETING_KEYS.SIZE]: '300x250', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.AD_ID]: '233bcbee889d46d', + [TARGETING_KEYS.BIDDER]: 'appnexus' }, '/19968336/header-bid-tag1': { - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.SIZE]: '728x90', + [TARGETING_KEYS.BIDDER]: 'appnexus', + [TARGETING_KEYS.AD_ID]: '24bd938435ec3fc', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.SIZE]: '728x90', 'foobar': '728x90' } } @@ -2813,7 +2813,7 @@ describe('Unit: Prebid Module', function () { it('should emit event BID_ACCEPTED when invoked', function () { var callback = sinon.spy(); $$PREBID_GLOBAL$$.onEvent('bidAccepted', callback); - events.emit(CONSTANTS.EVENTS.BID_ACCEPTED); + events.emit(EVENTS.BID_ACCEPTED); sinon.assert.calledOnce(callback); }); @@ -3059,7 +3059,7 @@ describe('Unit: Prebid Module', function () { describe('emit', function () { it('should be able to emit event without arguments', function () { var spyEventsEmit = sinon.spy(events, 'emit'); - events.emit(CONSTANTS.EVENTS.REQUEST_BIDS); + events.emit(EVENTS.REQUEST_BIDS); assert.ok(spyEventsEmit.calledWith('requestBids')); events.emit.restore(); }); @@ -3179,7 +3179,7 @@ describe('Unit: Prebid Module', function () { let priceGranularity = configObj.getConfig('priceGranularity'); let newCustomPriceBucket = configObj.getConfig('customPriceBucket'); expect(goodConfig).to.deep.equal(newCustomPriceBucket); - expect(priceGranularity).to.equal(CONSTANTS.GRANULARITY_OPTIONS.CUSTOM); + expect(priceGranularity).to.equal(GRANULARITY_OPTIONS.CUSTOM); }); }); @@ -3319,11 +3319,11 @@ describe('Unit: Prebid Module', function () { 'auctionId': 123456, 'adserverTargeting': { 'foobar': '300x250', - [CONSTANTS.TARGETING_KEYS.BIDDER]: 'appnexus', - [CONSTANTS.TARGETING_KEYS.AD_ID]: '233bcbee889d46d', - [CONSTANTS.TARGETING_KEYS.PRICE_BUCKET]: '10.00', - [CONSTANTS.TARGETING_KEYS.SIZE]: '300x250', - [CONSTANTS.TARGETING_KEYS.DEAL + '_appnexusDummyName']: '1234' + [TARGETING_KEYS.BIDDER]: 'appnexus', + [TARGETING_KEYS.AD_ID]: '233bcbee889d46d', + [TARGETING_KEYS.PRICE_BUCKET]: '10.00', + [TARGETING_KEYS.SIZE]: '300x250', + [TARGETING_KEYS.DEAL + '_appnexusDummyName']: '1234' } } ]; @@ -3363,7 +3363,7 @@ describe('Unit: Prebid Module', function () { auction.getBidsReceived = function() { return _bidsReceived }; const highestBid1 = $$PREBID_GLOBAL$$.getHighestUnusedBidResponseForAdUnitCode('/19968336/header-bid-tag-0'); expect(highestBid1).to.deep.equal(_bidsReceived[1]) - _bidsReceived[1].status = CONSTANTS.BID_STATUS.RENDERED + _bidsReceived[1].status = BID_STATUS.RENDERED const highestBid2 = $$PREBID_GLOBAL$$.getHighestUnusedBidResponseForAdUnitCode('/19968336/header-bid-tag-0'); expect(highestBid2).to.deep.equal(_bidsReceived[2]) }) @@ -3457,7 +3457,7 @@ describe('Unit: Prebid Module', function () { const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids, bid => bid.adId === winningBid.adId); - expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED); + expect(markedBid.status).to.equal(BID_STATUS.RENDERED); }); it('try and mark the bid object, but fail because we supplied the wrong adId', function () { @@ -3465,7 +3465,7 @@ describe('Unit: Prebid Module', function () { const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids, bid => bid.adId === winningBid.adId); - expect(markedBid.status).to.not.equal(CONSTANTS.BID_STATUS.RENDERED); + expect(markedBid.status).to.not.equal(BID_STATUS.RENDERED); }); it('marks the winning bid object as used for the given adUnitCode', function () { @@ -3474,7 +3474,7 @@ describe('Unit: Prebid Module', function () { const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids, bid => bid.adId === winningBid.adId); - expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED); + expect(markedBid.status).to.equal(BID_STATUS.RENDERED); }); it('marks a bid object as used for the given adId', function () { @@ -3483,7 +3483,7 @@ describe('Unit: Prebid Module', function () { const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids, bid => bid.adId === winningBid.adId); - expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED); + expect(markedBid.status).to.equal(BID_STATUS.RENDERED); }); }); } @@ -3553,11 +3553,11 @@ describe('Unit: Prebid Module', function () { expect(window.apntag.tags[adUnitCode].keywords).to.deep.equal({}); }); - it('should not find ' + CONSTANTS.TARGETING_KEYS.AD_ID + ' key in lowercase for all bidders', function() { + it('should not find ' + TARGETING_KEYS.AD_ID + ' key in lowercase for all bidders', function () { const adUnitCode = '/19968336/header-bid-tag-0'; $$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: true }); targeting.setTargetingForAst(); - const keywords = Object.keys(window.apntag.tags[adUnitCode].keywords).filter(keyword => (keyword.substring(0, CONSTANTS.TARGETING_KEYS.AD_ID.length) === CONSTANTS.TARGETING_KEYS.AD_ID)); + const keywords = Object.keys(window.apntag.tags[adUnitCode].keywords).filter(keyword => (keyword.substring(0, TARGETING_KEYS.AD_ID.length) === TARGETING_KEYS.AD_ID)); expect(keywords.length).to.equal(0); }); }); diff --git a/test/spec/unit/secureCreatives_spec.js b/test/spec/unit/secureCreatives_spec.js index a7be4e327f0..189066f7f88 100644 --- a/test/spec/unit/secureCreatives_spec.js +++ b/test/spec/unit/secureCreatives_spec.js @@ -13,7 +13,7 @@ import 'modules/nativeRendering.js'; import {expect} from 'chai'; -var CONSTANTS = require('src/constants.json'); +import { AD_RENDER_FAILED_REASON, BID_STATUS, EVENTS } from 'src/constants.js'; describe('secureCreatives', () => { let sandbox; @@ -160,10 +160,10 @@ describe('secureCreatives', () => { sinon.assert.calledWith(spyAddWinningBid, adResponse); sinon.assert.calledOnce(adResponse.renderer.render); sinon.assert.calledWith(adResponse.renderer.render, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); - sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); + sinon.assert.neverCalledWith(stubEmit, EVENTS.STALE_RENDER); - expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED); + expect(adResponse).to.have.property('status', BID_STATUS.RENDERED); }); it('should allow stale rendering without config', function () { @@ -187,10 +187,10 @@ describe('secureCreatives', () => { sinon.assert.calledWith(spyAddWinningBid, adResponse); sinon.assert.calledOnce(adResponse.renderer.render); sinon.assert.calledWith(adResponse.renderer.render, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); - sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); + sinon.assert.neverCalledWith(stubEmit, EVENTS.STALE_RENDER); - expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED); + expect(adResponse).to.have.property('status', BID_STATUS.RENDERED); resetHistories(adResponse.renderer.render); @@ -201,8 +201,8 @@ describe('secureCreatives', () => { sinon.assert.calledWith(spyAddWinningBid, adResponse); sinon.assert.calledOnce(adResponse.renderer.render); sinon.assert.calledWith(adResponse.renderer.render, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER, adResponse); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); + sinon.assert.calledWith(stubEmit, EVENTS.STALE_RENDER, adResponse); }); it('should stop stale rendering with config', function () { @@ -228,10 +228,10 @@ describe('secureCreatives', () => { sinon.assert.calledWith(spyAddWinningBid, adResponse); sinon.assert.calledOnce(adResponse.renderer.render); sinon.assert.calledWith(adResponse.renderer.render, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); - sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); + sinon.assert.neverCalledWith(stubEmit, EVENTS.STALE_RENDER); - expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED); + expect(adResponse).to.have.property('status', BID_STATUS.RENDERED); resetHistories(adResponse.renderer.render); @@ -240,8 +240,8 @@ describe('secureCreatives', () => { sinon.assert.calledWith(spyLogWarn, warning); sinon.assert.notCalled(spyAddWinningBid); sinon.assert.notCalled(adResponse.renderer.render); - sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER, adResponse); + sinon.assert.neverCalledWith(stubEmit, EVENTS.BID_WON, adResponse); + sinon.assert.calledWith(stubEmit, EVENTS.STALE_RENDER, adResponse); configObj.setConfig({'auctionOptions': {}}); }); @@ -254,8 +254,8 @@ describe('secureCreatives', () => { }) }); receiveMessage(ev); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({ - reason: CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, + sinon.assert.calledWith(stubEmit, EVENTS.AD_RENDER_FAILED, sinon.match({ + reason: AD_RENDER_FAILED_REASON.CANNOT_FIND_AD, adId: 'missing' })); }); @@ -272,8 +272,8 @@ describe('secureCreatives', () => { }) }); receiveMessage(ev) - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({ - reason: CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION, + sinon.assert.calledWith(stubEmit, EVENTS.AD_RENDER_FAILED, sinon.match({ + reason: AD_RENDER_FAILED_REASON.EXCEPTION, adId: bidId })); }); @@ -368,9 +368,9 @@ describe('secureCreatives', () => { sinon.assert.calledWith(stubGetAllAssetsMessage, data, adResponse); sinon.assert.calledOnce(ev.source.postMessage); sinon.assert.notCalled(stubFireNativeTrackers); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); sinon.assert.calledOnce(spyAddWinningBid); - sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.STALE_RENDER); + sinon.assert.neverCalledWith(stubEmit, EVENTS.STALE_RENDER); }); it('Prebid native should not fire BID_WON when receiveMessage is called more than once', () => { @@ -392,17 +392,17 @@ describe('secureCreatives', () => { }); receiveMessage(ev); - sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse); + sinon.assert.calledWith(stubEmit, EVENTS.BID_WON, adResponse); receiveMessage(ev); - stubEmit.withArgs(CONSTANTS.EVENTS.BID_WON, adResponse).calledOnce; + stubEmit.withArgs(EVENTS.BID_WON, adResponse).calledOnce; }); }); describe('Prebid Event', () => { Object.entries({ 'unrendered': [false, (bid) => { delete bid.status; }], - 'rendered': [true, (bid) => { bid.status = CONSTANTS.BID_STATUS.RENDERED }] + 'rendered': [true, (bid) => { bid.status = BID_STATUS.RENDERED }] }).forEach(([test, [shouldEmit, prepBid]]) => { describe(`for ${test} bids`, () => { beforeEach(() => { @@ -414,7 +414,7 @@ describe('secureCreatives', () => { const event = makeEvent({ data: JSON.stringify({ message: 'Prebid Event', - event: CONSTANTS.EVENTS.AD_RENDER_FAILED, + event: EVENTS.AD_RENDER_FAILED, adId: bidId, info: { reason: 'Fail reason', @@ -423,7 +423,7 @@ describe('secureCreatives', () => { }) }); receiveMessage(event); - expect(stubEmit.calledWith(CONSTANTS.EVENTS.AD_RENDER_FAILED, { + expect(stubEmit.calledWith(EVENTS.AD_RENDER_FAILED, { adId: bidId, bid: adResponse, reason: 'Fail reason', @@ -435,12 +435,12 @@ describe('secureCreatives', () => { const event = makeEvent({ data: JSON.stringify({ message: 'Prebid Event', - event: CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, + event: EVENTS.AD_RENDER_SUCCEEDED, adId: bidId, }) }); receiveMessage(event); - expect(stubEmit.calledWith(CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, { + expect(stubEmit.calledWith(EVENTS.AD_RENDER_SUCCEEDED, { adId: bidId, bid: adResponse, doc: null diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index c84fe124db6..e0a114d8cf6 100644 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -1,6 +1,6 @@ import {getAdServerTargeting} from 'test/fixtures/fixtures.js'; import {expect} from 'chai'; -import CONSTANTS from 'src/constants.json'; +import { TARGETING_KEYS } from 'src/constants.js'; import * as utils from 'src/utils.js'; import {getHighestCpm, getLatestHighestCpmBid, getOldestHighestCpmBid} from '../../src/utils/reducers.js'; import {binarySearch, deepEqual, memoize, waitForElementToLoad} from 'src/utils.js'; @@ -65,7 +65,7 @@ describe('Utils', function () { var obj = getAdServerTargeting(); var output = utils.transformAdServerTargetingObj(obj[Object.keys(obj)[0]]); - var expected = 'foobar=0x0%2C300x250%2C300x600&' + CONSTANTS.TARGETING_KEYS.SIZE + '=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_triplelift=0x0&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + CONSTANTS.TARGETING_KEYS.SIZE + '_appnexus=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pagescience=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brightcom=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brealtime=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + CONSTANTS.TARGETING_KEYS.SIZE + '_rubicon=300x600&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_rubicon=rubicon'; + var expected = 'foobar=0x0%2C300x250%2C300x600&' + TARGETING_KEYS.SIZE + '=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + TARGETING_KEYS.BIDDER + '=appnexus&' + TARGETING_KEYS.SIZE + '_triplelift=0x0&' + TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + TARGETING_KEYS.SIZE + '_appnexus=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + TARGETING_KEYS.SIZE + '_pagescience=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + TARGETING_KEYS.SIZE + '_brightcom=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + TARGETING_KEYS.SIZE + '_brealtime=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + TARGETING_KEYS.SIZE + '_rubicon=300x600&' + TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + TARGETING_KEYS.BIDDER + '_rubicon=rubicon'; assert.equal(output, expected); }); From 269437b5f8100aa0ad39f50adcba92dc949ee794 Mon Sep 17 00:00:00 2001 From: Antonios Sarhanis Date: Tue, 16 Apr 2024 10:28:22 +1000 Subject: [PATCH 020/147] Adnuntius Bid Adapter: network-scope metadata from adserver. (#11324) --- .../gpt/adnuntius_example.html | 8 +- modules/adnuntiusBidAdapter.js | 80 ++++++++++++------- test/spec/modules/adnuntiusBidAdapter_spec.js | 13 +-- 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/integrationExamples/gpt/adnuntius_example.html b/integrationExamples/gpt/adnuntius_example.html index b61c4e0674e..541a5888f3b 100644 --- a/integrationExamples/gpt/adnuntius_example.html +++ b/integrationExamples/gpt/adnuntius_example.html @@ -17,7 +17,7 @@ bidder: 'adnuntius', params: { auId: "201208", - network: "adnuntius", + network: "1287", bidType: 'netBid' } }] @@ -50,6 +50,12 @@ } }); + pbjs.bidderSettings = { + standard: { + storageAllowed: true + } + }; + pbjs.addAdUnits(adUnits); pbjs.requestBids({bidsBackHandler: initAdserver}); }); diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index 97419fb94bd..78f9f4c19aa 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -15,7 +15,8 @@ const GVLID = 855; const DEFAULT_VAST_VERSION = 'vast4' const MAXIMUM_DEALS_LIMIT = 5; const VALID_BID_TYPES = ['netBid', 'grossBid']; -const META_DATA_KEY = 'adn.metaData'; +const METADATA_KEY = 'adn.metaData'; +const METADATA_KEY_SEPARATOR = '@@@'; export const misc = { getUnixTimestamp: function (addDays, asMinutes) { @@ -28,23 +29,28 @@ const storageTool = (function () { const storage = getStorageManager({ bidderCode: BIDDER_CODE }); let metaInternal; - const getMetaInternal = function () { + const getMetaDataFromLocalStorage = function (pNetwork) { if (!storage.localStorageIsEnabled()) { return []; } let parsedJson; try { - parsedJson = JSON.parse(storage.getDataFromLocalStorage(META_DATA_KEY)); + parsedJson = JSON.parse(storage.getDataFromLocalStorage(METADATA_KEY)); } catch (e) { return []; } + let network = pNetwork; + if (Array.isArray(pNetwork)) { + network = (pNetwork.find((p) => p.network) || {}).network; + } + let filteredEntries = parsedJson ? parsedJson.filter((datum) => { if (datum.key === 'voidAuIds' && Array.isArray(datum.value)) { return true; } - return datum.key && datum.value && datum.exp && datum.exp > misc.getUnixTimestamp(); + return datum.key && datum.value && datum.exp && datum.exp > misc.getUnixTimestamp() && (!network || network === datum.network); }) : []; const voidAuIdsEntry = filteredEntries.find(entry => entry.key === 'voidAuIds'); if (voidAuIdsEntry) { @@ -57,7 +63,7 @@ const storageTool = (function () { return filteredEntries; }; - const setMetaInternal = function (apiResponse) { + const setMetaInternal = function (apiRespMetadata, network) { if (!storage.localStorageIsEnabled()) { return; } @@ -74,41 +80,48 @@ const storageTool = (function () { return notNewExistingAuIds.concat(apiIdsArray) || []; } - const metaAsObj = getMetaInternal().reduce((a, entry) => ({ ...a, [entry.key]: { value: entry.value, exp: entry.exp } }), {}); - for (const key in apiResponse) { + // use the metadata key separator to distinguish the same key for different networks. + const metaAsObj = getMetaDataFromLocalStorage().reduce((a, entry) => ({ ...a, [entry.key + METADATA_KEY_SEPARATOR + (entry.network ? entry.network : '')]: { value: entry.value, exp: entry.exp, network: entry.network } }), {}); + for (const key in apiRespMetadata) { if (key !== 'voidAuIds') { - metaAsObj[key] = { - value: apiResponse[key], - exp: misc.getUnixTimestamp(100) + metaAsObj[key + METADATA_KEY_SEPARATOR + network] = { + value: apiRespMetadata[key], + exp: misc.getUnixTimestamp(100), + network: network } } } - const currentAuIds = updateVoidAuIds(metaAsObj.voidAuIds || [], apiResponse.voidAuIds); + const currentAuIds = updateVoidAuIds(metaAsObj.voidAuIds || [], apiRespMetadata.voidAuIds); if (currentAuIds.length > 0) { metaAsObj.voidAuIds = { value: currentAuIds }; } const metaDataForSaving = Object.entries(metaAsObj).map((entrySet) => { - if (entrySet[0] === 'voidAuIds') { + if (entrySet.length !== 2) { + return {}; + } + const key = entrySet[0].split(METADATA_KEY_SEPARATOR)[0]; + if (key === 'voidAuIds') { return { - key: entrySet[0], + key: key, value: entrySet[1].value }; } return { - key: entrySet[0], + key: key, value: entrySet[1].value, - exp: entrySet[1].exp + exp: entrySet[1].exp, + network: entrySet[1].network } - }); - storage.setDataInLocalStorage(META_DATA_KEY, JSON.stringify(metaDataForSaving)); + }).filter(entry => entry.key); + storage.setDataInLocalStorage(METADATA_KEY, JSON.stringify(metaDataForSaving)); }; - const getUsi = function (meta, ortb2, bidderRequest) { + const getUsi = function (meta, ortb2, bidParams) { // Fetch user id from parameters. - for (let i = 0; i < (bidderRequest.bids || []).length; i++) { - const bid = bidderRequest.bids[i]; - if (bid.params && bid.params.userId) { - return bid.params.userId; + for (let i = 0; i < bidParams.length; i++) { + const bidParam = bidParams[i]; + if (bidParam.userId) { + return bidParam.userId; } } if (ortb2 && ortb2.user && ortb2.user.id) { @@ -136,8 +149,11 @@ const storageTool = (function () { return { refreshStorage: function (bidderRequest) { const ortb2 = bidderRequest.ortb2 || {}; - metaInternal = getMetaInternal().reduce((a, entry) => ({ ...a, [entry.key]: entry.value }), {}); - metaInternal.usi = getUsi(metaInternal, ortb2, bidderRequest); + const bidParams = (bidderRequest.bids || []).map((b) => { + return b.params ? b.params : {}; + }); + metaInternal = getMetaDataFromLocalStorage(bidParams).reduce((a, entry) => ({ ...a, [entry.key]: entry.value }), {}); + metaInternal.usi = getUsi(metaInternal, ortb2, bidParams); if (!metaInternal.usi) { delete metaInternal.usi; } @@ -148,15 +164,17 @@ const storageTool = (function () { } metaInternal.segments = getSegmentsFromOrtb(ortb2); }, - saveToStorage: function (serverData) { - setMetaInternal(serverData); + saveToStorage: function (serverData, network) { + setMetaInternal(serverData, network); }, getUrlRelatedData: function () { + // getting the URL information is theoretically not network-specific const { segments, usi, voidAuIdsArray } = metaInternal; return { segments, usi, voidAuIdsArray }; }, - getPayloadRelatedData: function () { - const { segments, usi, userId, voidAuIdsArray, voidAuIds, ...payloadRelatedData } = metaInternal; + getPayloadRelatedData: function (network) { + // getting the payload data should be network-specific + const { segments, usi, userId, voidAuIdsArray, voidAuIds, ...payloadRelatedData } = getMetaDataFromLocalStorage(network).reduce((a, entry) => ({...a, [entry.key]: entry.value}), {}); return payloadRelatedData; } }; @@ -223,7 +241,7 @@ export const spec = { networks[network].adUnits = networks[network].adUnits || []; if (bidderRequest && bidderRequest.refererInfo) networks[network].context = bidderRequest.refererInfo.page; - const payloadRelatedData = storageTool.getPayloadRelatedData(); + const payloadRelatedData = storageTool.getPayloadRelatedData(bid.params.network); if (Object.keys(payloadRelatedData).length > 0) { networks[network].metaData = payloadRelatedData; } @@ -239,7 +257,7 @@ export const spec = { } const requests = []; - const networkKeys = Object.keys(networks) + const networkKeys = Object.keys(networks); for (let j = 0; j < networkKeys.length; j++) { const network = networkKeys[j]; if (network.indexOf('_video') > -1) { queryParamsAndValues.push('tt=' + DEFAULT_VAST_VERSION) } @@ -257,7 +275,7 @@ export const spec = { interpretResponse: function (serverResponse, bidRequest) { if (serverResponse.body.metaData) { - storageTool.saveToStorage(serverResponse.body.metaData); + storageTool.saveToStorage(serverResponse.body.metaData, serverResponse.body.network); } const adUnits = serverResponse.body.adUnits; diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index 0e0206c2933..2fa1a52e863 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -12,7 +12,7 @@ describe('adnuntiusBidAdapter', function() { const EURO_URL = 'https://europe.delivery.adnuntius.com/i?tzo='; const usi = utils.generateUUID() - const meta = [{key: 'valueless'}, {value: 'keyless'}, {key: 'voidAuIds'}, {key: 'voidAuIds', value: [{auId: '11118b6bc', exp: misc.getUnixTimestamp()}, {exp: misc.getUnixTimestamp(1)}]}, {key: 'valid', value: 'also-valid', exp: misc.getUnixTimestamp(1)}, {key: 'expired', value: 'fwefew', exp: misc.getUnixTimestamp()}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp()}, {key: 'usi', value: usi, exp: misc.getUnixTimestamp(100)}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp()}] + const meta = [{key: 'valueless'}, {value: 'keyless'}, {key: 'voidAuIds'}, {key: 'voidAuIds', value: [{auId: '11118b6bc', exp: misc.getUnixTimestamp()}, {exp: misc.getUnixTimestamp(1)}]}, {key: 'valid-withnetwork', value: 'also-valid-network', network: 'the-network', exp: misc.getUnixTimestamp(1)}, {key: 'valid', value: 'also-valid', exp: misc.getUnixTimestamp(1)}, {key: 'expired', value: 'fwefew', exp: misc.getUnixTimestamp()}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp(), network: 'adnuntius'}, {key: 'usi', value: usi, exp: misc.getUnixTimestamp(100), network: 'adnuntius'}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp()}] let storage; before(() => { @@ -257,7 +257,8 @@ describe('adnuntiusBidAdapter', function() { 'usi': 'from-api-server dude', 'voidAuIds': '00000000000abcde;00000000000fffff', 'randomApiKey': 'randomApiValue' - } + }, + 'network': 'some-network-id' } } const serverVideoResponse = { @@ -464,7 +465,7 @@ describe('adnuntiusBidAdapter', function() { expect(request[0]).to.have.property('url'); expect(request[0].url).to.equal(ENDPOINT_URL); expect(request[0]).to.have.property('data'); - expect(request[0].data).to.equal('{"adUnits":[{"auId":"000000000008b6bc","targetId":"123","maxDeals":1,"dimensions":[[640,480],[600,400]]},{"auId":"0000000000000551","targetId":"adn-0000000000000551","dimensions":[[1640,1480],[1600,1400]]}],"metaData":{"valid":"also-valid"}}'); + expect(request[0].data).to.equal('{"adUnits":[{"auId":"000000000008b6bc","targetId":"123","maxDeals":1,"dimensions":[[640,480],[600,400]]},{"auId":"0000000000000551","targetId":"adn-0000000000000551","dimensions":[[1640,1480],[1600,1400]]}]}'); }); it('Test requests with no local storage', function() { @@ -695,7 +696,7 @@ describe('adnuntiusBidAdapter', function() { network: 'adnuntius' } } - ] + ]; const request = config.runWithBidder('adnuntius', () => spec.buildRequests(req, { bids: req })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') @@ -913,10 +914,11 @@ describe('adnuntiusBidAdapter', function() { expect(interpretedResponse[1].dealCount).to.equal(0); const results = JSON.parse(storage.getDataFromLocalStorage('adn.metaData')); - const usiEntry = results.find(entry => entry.key === 'usi'); + const usiEntry = results.find(entry => entry.key === 'usi' && entry.network === 'some-network-id'); expect(usiEntry.key).to.equal('usi'); expect(usiEntry.value).to.equal('from-api-server dude'); expect(usiEntry.exp).to.be.greaterThan(misc.getUnixTimestamp(90)); + expect(usiEntry.network).to.equal('some-network-id') const voidAuIdsEntry = results.find(entry => entry.key === 'voidAuIds'); expect(voidAuIdsEntry.key).to.equal('voidAuIds'); @@ -937,6 +939,7 @@ describe('adnuntiusBidAdapter', function() { const randomApiEntry = results.find(entry => entry.key === 'randomApiKey'); expect(randomApiEntry.key).to.equal('randomApiKey'); expect(randomApiEntry.value).to.equal('randomApiValue'); + expect(randomApiEntry.network).to.equal('some-network-id'); expect(randomApiEntry.exp).to.be.greaterThan(misc.getUnixTimestamp(90)); }); From d2117febee739efe5128d5609abfdaaedeaab7b8 Mon Sep 17 00:00:00 2001 From: Carlos Felix Date: Tue, 16 Apr 2024 06:19:50 -0500 Subject: [PATCH 021/147] encode the 33across `fp` query parameter (#11342) --- modules/33acrossIdSystem.js | 2 +- test/spec/modules/33acrossIdSystem_spec.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/33acrossIdSystem.js b/modules/33acrossIdSystem.js index 33086562111..e0f7435a1ec 100644 --- a/modules/33acrossIdSystem.js +++ b/modules/33acrossIdSystem.js @@ -80,7 +80,7 @@ function calculateQueryStringParams(pid, gdprConsentData, storageConfig) { const fp = getStoredValue(STORAGE_FPID_KEY, storageConfig); if (fp) { - params.fp = fp; + params.fp = encodeURIComponent(fp); } return params; diff --git a/test/spec/modules/33acrossIdSystem_spec.js b/test/spec/modules/33acrossIdSystem_spec.js index cbc5b277e30..364f7d2845c 100644 --- a/test/spec/modules/33acrossIdSystem_spec.js +++ b/test/spec/modules/33acrossIdSystem_spec.js @@ -493,7 +493,7 @@ describe('33acrossIdSystem', () => { }); context('when a first-party ID is present in local storage', () => { - it('should call endpoint with the first-party ID included', () => { + it('should call endpoint with the encoded first-party ID included', () => { const completeCallback = () => {}; const { callback } = thirthyThreeAcrossIdSubmodule.getId({ params: { @@ -506,13 +506,13 @@ describe('33acrossIdSystem', () => { sinon.stub(storage, 'getDataFromLocalStorage') .withArgs('33acrossIdFp') - .returns('33acrossIdFpValue'); + .returns('33acrossIdFpValue+'); callback(completeCallback); const [request] = server.requests; - expect(request.url).to.contain('fp=33acrossIdFpValue'); + expect(request.url).to.contain('fp=33acrossIdFpValue%2B'); storage.getDataFromLocalStorage.restore(); }); From 5ee5129a65c6da97b6ca8189ba2d26a74ee93461 Mon Sep 17 00:00:00 2001 From: Paulius Imbrasas <880130+CremboC@users.noreply.github.com> Date: Tue, 16 Apr 2024 12:52:07 +0100 Subject: [PATCH 022/147] permutiveRtdProvider: add support for topics (#11330) --- modules/permutiveRtdProvider.js | 23 ++++++++++++-- .../spec/modules/permutiveRtdProvider_spec.js | 30 ++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/modules/permutiveRtdProvider.js b/modules/permutiveRtdProvider.js index 5a63990f84f..c42a15d9197 100644 --- a/modules/permutiveRtdProvider.js +++ b/modules/permutiveRtdProvider.js @@ -104,6 +104,7 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) { const ssps = segmentData?.ssp?.ssps ?? [] const sspCohorts = segmentData?.ssp?.cohorts ?? [] + const topics = segmentData?.topics ?? {} const bidders = new Set([...acBidders, ...ssps]) bidders.forEach(function (bidder) { @@ -121,7 +122,7 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) { cohorts = [...new Set([...cohorts, ...sspCohorts])].slice(0, maxSegs) } - const nextConfig = updateOrtbConfig(bidder, currConfig, cohorts, sspCohorts, transformationConfigs, segmentData) + const nextConfig = updateOrtbConfig(bidder, currConfig, cohorts, sspCohorts, topics, transformationConfigs, segmentData) bidderOrtb2[bidder] = nextConfig.ortb2 }) } @@ -134,10 +135,11 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) { * the transformations on user data to include the ORTB2 object * @param {string[]} segmentIDs - Permutive segment IDs * @param {string[]} sspSegmentIDs - Permutive SSP segment IDs + * @param {Object} topics - Privacy Sandbox Topics, keyed by IAB taxonomy version (600, 601, etc.) * @param {Object} segmentData - The segments available for targeting * @return {Object} Merged ortb2 object */ -function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, transformationConfigs, segmentData) { +function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, topics, transformationConfigs, segmentData) { logger.logInfo(`Current ortb2 config`, { bidder, config: currConfig }) const customCohortsData = deepAccess(segmentData, bidder) || [] @@ -161,9 +163,21 @@ function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, transfo const ortbConfig = mergeDeep({}, currConfig) const currentUserData = deepAccess(ortbConfig, 'ortb2.user.data') || [] + let topicsUserData = [] + for (const [k, value] of Object.entries(topics)) { + topicsUserData.push({ + name, + ext: { + segtax: Number(k) + }, + segment: value.map(topic => ({ id: topic.toString() })), + }) + } + const updatedUserData = currentUserData .filter(el => el.name !== permutiveUserData.name && el.name !== customCohortsUserData.name) .concat(permutiveUserData, transformedUserData, customCohortsUserData) + .concat(topicsUserData) logger.logInfo(`Updating ortb2.user.data`, { bidder, user_data: updatedUserData }) deepSetValue(ortbConfig, 'ortb2.user.data', updatedUserData) @@ -311,6 +325,7 @@ export function getSegments (maxSegs) { cohorts: [], ssps: [] }), + topics: readSegments('_ppsts', {}), } for (const bidder in segments) { @@ -318,6 +333,10 @@ export function getSegments (maxSegs) { if (segments[bidder].cohorts && Array.isArray(segments[bidder].cohorts)) { segments[bidder].cohorts = segments[bidder].cohorts.slice(0, maxSegs) } + } else if (bidder === 'topics') { + for (const taxonomy in segments[bidder]) { + segments[bidder][taxonomy] = segments[bidder][taxonomy].slice(0, maxSegs) + } } else { segments[bidder] = segments[bidder].slice(0, maxSegs) } diff --git a/test/spec/modules/permutiveRtdProvider_spec.js b/test/spec/modules/permutiveRtdProvider_spec.js index 942ec2eaa46..73218fee7b9 100644 --- a/test/spec/modules/permutiveRtdProvider_spec.js +++ b/test/spec/modules/permutiveRtdProvider_spec.js @@ -212,6 +212,28 @@ describe('permutiveRtdProvider', function () { return { id: seg } }), }, + { + name: 'permutive.com', + ext: { + segtax: 600 + }, + segment: [ + { id: '1' }, + { id: '2' }, + { id: '3' }, + ], + }, + { + name: 'permutive.com', + ext: { + segtax: 601 + }, + segment: [ + { id: '100' }, + { id: '101' }, + { id: '102' }, + ], + }, ]) }) }) @@ -553,6 +575,10 @@ describe('permutiveRtdProvider', function () { for (const key in segments) { if (key === 'ssp') { expect(segments[key].cohorts).to.have.length(max) + } else if (key === 'topics') { + for (const topic in segments[key]) { + expect(segments[key][topic]).to.have.length(max) + } } else { expect(segments[key]).to.have.length(max) } @@ -684,6 +710,7 @@ function transformedTargeting (data = getTargetingData()) { rubicon: data._prubicons, gam: data._pdfps, ssp: data._pssps, + topics: data._ppsts, } } @@ -696,7 +723,8 @@ function getTargetingData () { _ppam: ['ppam1', 'ppam2'], _pindexs: ['pindex1', 'pindex2'], _pcrprs: ['pcrprs1', 'pcrprs2', 'dup'], - _pssps: { ssps: ['xyz', 'abc', 'dup'], cohorts: ['123', 'abc'] } + _pssps: { ssps: ['xyz', 'abc', 'dup'], cohorts: ['123', 'abc'] }, + _ppsts: { '600': [1, 2, 3], '601': [100, 101, 102] }, } } From 2307f938d1428cb1fe319f3906435b9234bb4ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sok=C3=B3=C5=82?= <88041828+krzysztofequativ@users.noreply.github.com> Date: Tue, 16 Apr 2024 15:46:29 +0200 Subject: [PATCH 023/147] SAS Bid Adapter: Fledge support (#11348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Smartadserver Bid Adapter: Add support for SDA user and site * Smartadserver Bid Adapter: Fix SDA support getConfig and add to unit testing * support floors per media type * Add GPP support * Rework payloads enriching * Add gpid support * Support additional video params * vpmt as array of numbers * Fix comment * Update default startDelay * Include videoMediaType's startdelay * Handle specified midroll * support paapi --------- Co-authored-by: Meven Courouble Co-authored-by: Krzysztof Sokół <88041828+smart-adserver@users.noreply.github.com> Co-authored-by: Dariusz O --- modules/smartadserverBidAdapter.js | 16 ++++- .../modules/smartadserverBidAdapter_spec.js | 65 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 7edaaa36957..5bc50190b11 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -226,6 +226,11 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } + const ae = deepAccess(bid, 'ortb2Imp.ext.ae'); + if (bidderRequest && bidderRequest.fledgeEnabled && ae) { + payload.ae = ae; + } + const bannerMediaType = deepAccess(bid, 'mediaTypes.banner'); const videoMediaType = deepAccess(bid, 'mediaTypes.video'); const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); @@ -266,7 +271,7 @@ export const spec = { */ interpretResponse: function (serverResponse, bidRequestString) { const bidResponses = []; - let response = serverResponse.body; + const response = serverResponse.body; try { if (response && !response.isNoAd && (response.ad || response.adUrl)) { const bidRequest = JSON.parse(bidRequestString.data); @@ -296,10 +301,19 @@ export const spec = { } bidResponses.push(bidResponse); + + const fledgeAuctionConfigs = response.auctionConfigs; + if (fledgeAuctionConfigs && Array.isArray(fledgeAuctionConfigs)) { + return { + bids: bidResponses, + fledgeAuctionConfigs + }; + } } } catch (error) { logError('Error while parsing smart server response', error); } + return bidResponses; }, diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index b01d95e2a4c..a2d053f841f 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -458,6 +458,27 @@ describe('Smart bid adapter tests', function () { expect(syncs).to.have.lengthOf(0); }); + it('Verify auctionConfigs', function () { + const request = spec.buildRequests(DEFAULT_PARAMS); + const auctionConfigs = [{ + bidId: '02g93e54w9ps', + config: { + decisionLogicUrl: 'https://seller.sas.com/decision_logic.js', + interestGroupBuyers: ['https://buyer.sas.com'], + seller: 'https://seller.sas.com' + } + }]; + const bids = spec.interpretResponse({ + body: { + ...BID_RESPONSE.body, + auctionConfigs + } + }, request[0]); + + expect(bids).to.have.property('bids').and.to.satisfy(value => (value === null || Array.isArray(value))); + expect(bids.fledgeAuctionConfigs).to.be.an('array').and.to.deep.equal(auctionConfigs); + }); + describe('gdpr tests', function () { afterEach(function () { config.setConfig({ ortb2: undefined }); @@ -1505,6 +1526,50 @@ describe('Smart bid adapter tests', function () { }); }); + describe('Fledge for GPT', function () { + it('should send fledge eligibility flag when fledge enabled and ortb2Imp.ext.ae set', function () { + const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); + const ae = { + ae: 1 + }; + + bidRequests[0].ortb2Imp = { + ext: ae + }; + + const request = spec.buildRequests(bidRequests, { + fledgeEnabled: true + }); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('ae').and.to.equal(ae.ae); + }); + + it('should not send fledge eligibility flag when fledge not enabled', function () { + const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); + bidRequests[0].ortb2Imp = { + ext: { + ae: 1 + } + }; + + const request = spec.buildRequests(bidRequests); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.not.have.property('ae'); + }); + + it('should not send fledge eligibility flag when ortb2Imp.ext.ae not set', function () { + const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); + const request = spec.buildRequests(bidRequests, { + fledgeEnabled: true + }); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.not.have.property('ae'); + }); + }); + describe('#getValuableProperty method', function () { it('should return an object when calling with a number value', () => { const obj = spec.getValuableProperty('prop', 3); From 3ae46e075e09a12e16f60bd7ace6baf39bbd0c54 Mon Sep 17 00:00:00 2001 From: Andrii Pukh <152202940+apukh-magnite@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:47:47 +0300 Subject: [PATCH 024/147] Add PBS ARs flag to adUnit (#11347) --- modules/magniteAnalyticsAdapter.js | 2 ++ test/spec/modules/magniteAnalyticsAdapter_spec.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index 6d45d05cd5c..1c82a9f3255 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -905,6 +905,8 @@ magniteAdapter.track = ({ eventType, args }) => { 'source', () => bid.src === 's2s' ? 'server' : 'client', 'status', () => 'no-bid' ]); + // add a pbs flag if one of the bids has a server source + if (adUnit.bids[bid.bidId].source === 'server') adUnit.pbsRequest = 1; // set acct site zone id on adunit if ((!adUnit.siteId || !adUnit.zoneId) && rubiconAliases.indexOf(bid.bidder) !== -1) { if (deepAccess(bid, 'params.accountId') == accountId) { diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index 1798c96c341..c46e79614ce 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -1520,6 +1520,8 @@ describe('magnite analytics adapter', function () { // bid source should be 'server' expectedMessage.auctions[0].adUnits[0].bids[0].source = 'server'; + // if one of bids.source === server should add pbsRequest flag to adUnit + expectedMessage.auctions[0].adUnits[0].pbsRequest = 1; expectedMessage.bidsWon[0].source = 'server'; expect(message).to.deep.equal(expectedMessage); }); From 8cafa680f5024ae01bd861262b7f622d3987f999 Mon Sep 17 00:00:00 2001 From: Jordi Garcia Date: Tue, 16 Apr 2024 15:48:52 +0200 Subject: [PATCH 025/147] AzerionEdge RTD Module: Documentation: Required parameters (#11346) * Azerion Edge RTD Module: Initial release ### Type of change [x] Feature: New RTD Submodule ### Description of change Adds new Azerion Edge RTD module. Maintainer: azerion.com Contact: @garciapuig @mserrate @gguridi * Azerion Edge RTD Module: Initial release. Typo * AzerionEdge RTD Module: Documentation: Required parameters Type of change: Documentation/Feature Description of change: Specifying new required parameters on documentation. Updating examples. --------- Co-authored-by: Gorka Guridi --- integrationExamples/gpt/azerionedgeRtdProvider_example.html | 6 +++--- modules/azerionedgeRtdProvider.md | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/integrationExamples/gpt/azerionedgeRtdProvider_example.html b/integrationExamples/gpt/azerionedgeRtdProvider_example.html index 880fe5ed706..e85ab705235 100644 --- a/integrationExamples/gpt/azerionedgeRtdProvider_example.html +++ b/integrationExamples/gpt/azerionedgeRtdProvider_example.html @@ -40,17 +40,17 @@ { name: "azerionedge", waitForIt: true, - params: { bidders: ["appnexus"] }, + params: { bidders: ["improvedigital"] }, }, ], }, }); - pbjs.setBidderConfig({ bidders: ["appnexus"], config: {} }); + pbjs.setBidderConfig({ bidders: ["improvedigital"], config: {} }); pbjs.addAdUnits([ { code: TEST_DIV, mediaTypes: { banner: { sizes: TEST_SIZES } }, - bids: [{ bidder: "appnexus", params: { placementId: 13144370 } }], + bids: [{ bidder: "improvedigital", params: { placementId: 13144370 } }], }, ]); pbjs.requestBids({ diff --git a/modules/azerionedgeRtdProvider.md b/modules/azerionedgeRtdProvider.md index 2849bef3f63..6658907c480 100644 --- a/modules/azerionedgeRtdProvider.md +++ b/modules/azerionedgeRtdProvider.md @@ -1,6 +1,6 @@ --- layout: page_v2 -title: azerion edge RTD Provider +title: Azerion Edge RTD Provider display_name: Azerion Edge RTD Provider description: Client-side contextual cookieless audiences. page_type: module @@ -18,6 +18,8 @@ Client-side contextual cookieless audiences. Azerion Edge RTD module helps publishers to capture users' interest audiences on their site, and attach these into the bid request. +Please contact [edge@azerion.com](edge@azerion.com) for more information. + Maintainer: [azerion.com](https://www.azerion.com/) {:.no_toc} @@ -64,7 +66,7 @@ pbjs.setConfig( | :--- | :------- | :------------------ | :--------------- | | name | `String` | RTD sub module name | Always "azerionedge" | | waitForIt | `Boolean` | Required to ensure that the auction is delayed for the module to respond. | Optional. Defaults to false but recommended to true. | -| params.key | `String` | Publisher partner specific key | Optional | +| params.key | `String` | Publisher partner specific key | Mandatory. The key is required for the module to work. If you haven't received one, please reach [support@improvedigital.com](support@improvedigital.com) | | params.bidders | `Array` | Bidders with which to share segment information | Optional. Defaults to "improvedigital". | | params.process | `Object` | Configuration for the Azerion Edge script. | Optional. Defaults to `{}`. | From d9ea9a986f5b855fed6374cf68787467c1089331 Mon Sep 17 00:00:00 2001 From: Keren Gattegno Date: Tue, 16 Apr 2024 16:49:59 +0300 Subject: [PATCH 026/147] topicsFpdModule: add undertone (#11334) * * Update undertone adapter - change parameters - placementId parameter is now optional and not mandatory - undertoneBidAdapter.js * Updated undertone bid adapter tests accordingly - undertoneBidAdapter_spec.js * * Update undertone adapter - change parameters - placementId parameter is now optional and not mandatory - undertoneBidAdapter.js * Updated undertone bid adapter tests accordingly - undertoneBidAdapter_spec.js * fix lint issue in undertone adapter spec * added user sync function to undertone adapter * * Update undertone adapter - change parameters - placementId parameter is now optional and not mandatory - undertoneBidAdapter.js * Updated undertone bid adapter tests accordingly - undertoneBidAdapter_spec.js * added user sync function to undertone adapter * added user sync function to undertone adapter * revert package-lock.json * added user sync function to undertone adapter * Update undertoneBidAdapter.js * Update browsers.json * Undertone: added GPP support and video plcmt * Fix lint issues * Add undertone to topics module --------- Co-authored-by: omerko Co-authored-by: Omer Koren Co-authored-by: AnnaPerion Co-authored-by: Oran Hollaender Co-authored-by: tamirnPerion <44399211+tamirnPerion@users.noreply.github.com> Co-authored-by: tamarm Co-authored-by: tamarm <40788385+tamarm-perion@users.noreply.github.com> Co-authored-by: Idan Botbol --- modules/topicsFpdModule.js | 3 +++ modules/topicsFpdModule.md | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/modules/topicsFpdModule.js b/modules/topicsFpdModule.js index 715f1ca735a..72f4068af7f 100644 --- a/modules/topicsFpdModule.js +++ b/modules/topicsFpdModule.js @@ -44,6 +44,9 @@ const bidderIframeList = { }, { bidder: 'discovery', iframeURL: 'https://api.popin.cc/topic/prebid-topics-frame.html' + }, { + bidder: 'undertone', + iframeURL: 'https://creative-p.undertone.com/spk-public/topics_frame.html' }] } diff --git a/modules/topicsFpdModule.md b/modules/topicsFpdModule.md index 8ebddacf613..d187645f520 100644 --- a/modules/topicsFpdModule.md +++ b/modules/topicsFpdModule.md @@ -64,6 +64,10 @@ pbjs.setConfig({ bidder: 'discovery', iframeURL: 'https://api.popin.cc/topic/prebid-topics-frame.html', expiry: 7 // Configurable expiry days + }, { + bidder: 'undertone', + iframeURL: 'https://creative-p.undertone.com/spk-public/topics_frame.html', + expiry: 7 // Configurable expiry days }] } .... From 8748f8feaa362b645bde7911b7d20e8a8ae9c091 Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Tue, 16 Apr 2024 06:53:40 -0700 Subject: [PATCH 027/147] Magnite Analytics: auction index + small cleanup (#11345) * move globals up + add auctionIndex * add / update tests --- modules/magniteAnalyticsAdapter.js | 18 ++++++++++-------- .../modules/magniteAnalyticsAdapter_spec.js | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/modules/magniteAnalyticsAdapter.js b/modules/magniteAnalyticsAdapter.js index 1c82a9f3255..225607ad6d3 100644 --- a/modules/magniteAnalyticsAdapter.js +++ b/modules/magniteAnalyticsAdapter.js @@ -34,6 +34,7 @@ const LAST_SEEN_EXPIRE_TIME = 1800000; // 30 mins const END_EXPIRE_TIME = 21600000; // 6 hours const MODULE_NAME = 'Magnite Analytics'; const BID_REJECTED_IPF = 'rejected-ipf'; +const DEFAULT_INTEGRATION = 'pbjs'; // List of known rubicon aliases // This gets updated on auction init to account for any custom aliases present @@ -48,6 +49,12 @@ const pbsErrorMap = { } let cookieless; +let browser; +let pageReferer; +let auctionIndex = 0; // count of auctions on page +let accountId; +let endpoint; + let prebidGlobal = getGlobal(); const { AUCTION_INIT, @@ -105,8 +112,6 @@ config.getConfig('s2sConfig', ({ s2sConfig }) => { serverConfig = s2sConfig; }); -const DEFAULT_INTEGRATION = 'pbjs'; - const adUnitIsOnlyInstream = adUnit => { return adUnit.mediaTypes && Object.keys(adUnit.mediaTypes).length === 1 && deepAccess(adUnit, 'mediaTypes.video.context') === 'instream'; } @@ -309,8 +314,6 @@ const addFloorData = floorData => { } } -let pageReferer; - const getTopLevelDetails = () => { let payload = { channel: 'web', @@ -645,9 +648,6 @@ export const detectBrowserFromUa = userAgent => { return 'OTHER'; } -let accountId; -let endpoint; - let magniteAdapter = adapter({ analyticsType: 'endpoint' }); magniteAdapter.originEnableAnalytics = magniteAdapter.enableAnalytics; @@ -703,6 +703,7 @@ magniteAdapter.disableAnalytics = function () { magniteAdapter._oldEnable = enableMgniAnalytics; endpoint = undefined; accountId = undefined; + auctionIndex = 0; resetConfs(); getHook('callPrebidCache').getHooks({ hook: callPrebidCacheHook }).remove(); magniteAdapter.originDisableAnalytics(); @@ -791,10 +792,10 @@ const getLatencies = (args, auctionStart) => { } } -let browser; magniteAdapter.track = ({ eventType, args }) => { switch (eventType) { case AUCTION_INIT: + auctionIndex += 1; // Update session cache.sessionData = storage.localStorageIsEnabled() && updateRpaCookie(); // set the rubicon aliases @@ -810,6 +811,7 @@ magniteAdapter.track = ({ eventType, args }) => { 'timeout as clientTimeoutMillis', ]); auctionData.accountId = accountId; + auctionData.auctionIndex = auctionIndex; // get browser if (!browser) { diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js index c46e79614ce..731b4ab1682 100644 --- a/test/spec/modules/magniteAnalyticsAdapter_spec.js +++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js @@ -239,6 +239,7 @@ const ANALYTICS_MESSAGE = { }, 'auctions': [ { + 'auctionIndex': 1, 'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d', 'auctionStart': 1658868383741, 'samplingFactor': 1, @@ -601,7 +602,22 @@ describe('magnite analytics adapter', function () { it(`should parse browser from ${testData.expected} user agent correctly`, function () { expect(detectBrowserFromUa(testData.ua)).to.equal(testData.expected); }); - }) + }); + + it('should increment auctionIndex each auction', function () { + // run 3 auctions + performStandardAuction(); + performStandardAuction(); + performStandardAuction(); + + expect(server.requests.length).to.equal(3); + server.requests.forEach((request, index) => { + let message = JSON.parse(request.requestBody); + + // should be index of array + 1 + expect(message?.auctions?.[0].auctionIndex).to.equal(index + 1); + }); + }); it('should pass along 1x1 size if no sizes in adUnit', function () { const auctionInit = utils.deepClone(MOCK.AUCTION_INIT); From da3e7d2304762ac94642b2a8af6af5f3a1ed7057 Mon Sep 17 00:00:00 2001 From: maelmrgt <77864748+maelmrgt@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:05:49 +0200 Subject: [PATCH 028/147] Greenbids Analytics Adapter: debug flag analytics (#11297) * greenbids analytics adapter: always sampled when degug * Greenbids analytics adapter: lint + test * greenbids analytics adapter: bump version * greenbids analytics adapter: minor fixes * greenbids analytics adapter: change the flag from pbjs_debut to greenbids_force_sampling * remove unused import * TEST: fix --------- Co-authored-by: Jean-Baptiste Pettit --- modules/greenbidsAnalyticsAdapter.js | 9 +++++++-- .../modules/greenbidsAnalyticsAdapter_spec.js | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/greenbidsAnalyticsAdapter.js b/modules/greenbidsAnalyticsAdapter.js index fd2bc1c25ea..d6293adac82 100644 --- a/modules/greenbidsAnalyticsAdapter.js +++ b/modules/greenbidsAnalyticsAdapter.js @@ -2,11 +2,11 @@ import {ajax} from '../src/ajax.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; -import {deepClone, generateUUID, logError, logInfo, logWarn} from '../src/utils.js'; +import {deepClone, generateUUID, logError, logInfo, logWarn, getParameterByName} from '../src/utils.js'; const analyticsType = 'endpoint'; -export const ANALYTICS_VERSION = '2.2.0'; +export const ANALYTICS_VERSION = '2.2.1'; const ANALYTICS_SERVER = 'https://a.greenbids.ai'; @@ -26,6 +26,11 @@ export const BIDDER_STATUS = { const analyticsOptions = {}; export const isSampled = function(greenbidsId, samplingRate, exploratorySamplingSplit) { + const isSamplingForced = getParameterByName('greenbids_force_sampling'); + if (isSamplingForced) { + logInfo('Greenbids Analytics: sampling flag detected, forcing analytics'); + return true; + } if (samplingRate < 0 || samplingRate > 1) { logWarn('Sampling rate must be between 0 and 1'); return true; diff --git a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js index efaeb06ae53..918da50d8bc 100644 --- a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js +++ b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js @@ -4,8 +4,9 @@ import { ANALYTICS_VERSION, BIDDER_STATUS } from 'modules/greenbidsAnalyticsAdapter.js'; import { - generateUUID, + generateUUID } from '../../../src/utils.js'; +import * as utils from 'src/utils.js'; import {expect} from 'chai'; import sinon from 'sinon'; @@ -424,4 +425,16 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () { expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.0001, 0.0, 1.0)).to.be.false; }); }); + + describe('isSampled when analytic isforced', function() { + before(() => { + sinon.stub(utils, 'getParameterByName').callsFake(par => par === 'greenbids_force_sampling' ? true : undefined); + }); + it('should return determinist true when sampling flag activated', function() { + expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.0001, 0.0)).to.be.true; + }); + after(() => { + utils.getParameterByName.restore(); + }); + }); }); From 524617df46e01655e384b960bfce4448e858df1e Mon Sep 17 00:00:00 2001 From: Catalin Ciocov Date: Tue, 16 Apr 2024 17:24:27 +0300 Subject: [PATCH 029/147] Improvedigital Bid Adapter : update razr (#11290) * Improve Digital PG flag * ImproveDigital - update internal logic due to ad markup changes * Updated tests --------- Co-authored-by: Jozef Bartek --- modules/improvedigitalBidAdapter.js | 3 ++- test/spec/modules/improvedigitalBidAdapter_spec.js | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index 3a258dfa327..fbceeee6d90 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -391,7 +391,8 @@ const ID_RAZR = { const cfgStr = JSON.stringify(cfg).replace(/<\/script>/ig, '\\x3C/script>'); const s = ``; - bid.ad = bid.ad.replace(/]*>/, match => match + s); + // prepend RAZR config to ad markup: + bid.ad = s + bid.ad; this.installListener(); }, diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index a86b9be73e6..a955b716584 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -1071,7 +1071,7 @@ describe('Improve Digital Adapter Tests', function () { width: 728, height: 90, ttl: 300, - ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', creativeId: '510265', dealId: 320896, netRevenue: false, @@ -1081,7 +1081,7 @@ describe('Improve Digital Adapter Tests', function () { const multiFormatExpectedBid = [ Object.assign({}, expectedBid[0], { - ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]},"native":{},"video":{"context":"outstream","playerSize":[640,480]}},"sizes":[[300,250],[160,600]],"nativeParams":{"body":{"required":true}}},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]},"native":{},"video":{"context":"outstream","playerSize":[640,480]}},"sizes":[[300,250],[160,600]],"nativeParams":{"body":{"required":true}}},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"35adfe19-d6e9-46b9-9f7d-20da7026b965","cpm":1.9200543539802946,"currency":"EUR","width":728,"height":90,"creative_id":"510265","creativeId":"510265","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', }) ]; @@ -1094,7 +1094,7 @@ describe('Improve Digital Adapter Tests', function () { width: 300, height: 250, ttl: 300, - ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"83c8d524-0955-4d0c-b558-4c9f3600e09b","cpm":1.9200543539802946,"currency":"EUR","width":300,"height":250,"creative_id":"479163","creativeId":"479163","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', + ad: '\x3Cscript>window.__razr_config = {"prebid":{"bidRequest":{"bidder":"improvedigital","params":{"placementId":1053688,"keyValues":{"testKey":["testValue"]},"bidFloor":0.05,"bidFloorCur":"eUR","size":{"w":800,"h":600}},"adUnitCode":"div-gpt-ad-1499748733608-0","transactionId":"f183e871-fbed-45f0-a427-c8a63c4c01eb","bidId":"33e9500b21129f","bidderRequestId":"2772c1e566670b","auctionId":"192721e36a0239","mediaTypes":{"banner":{"sizes":[[300,250],[160,600]]}},"sizes":[[300,250],[160,600]]},"bid":{"mediaType":"banner","ad":"\\"\\"","requestId":"33e9500b21129f","seatBidId":"83c8d524-0955-4d0c-b558-4c9f3600e09b","cpm":1.9200543539802946,"currency":"EUR","width":300,"height":250,"creative_id":"479163","creativeId":"479163","ttl":300,"meta":{},"dealId":320896,"netRevenue":false}}};\x3C/script>  ', creativeId: '479163', dealId: 320896, netRevenue: false, From 44e8e9fcb9be27d7344646cf171d244c1afb4e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Sok=C3=B3=C5=82?= <88041828+krzysztofequativ@users.noreply.github.com> Date: Tue, 16 Apr 2024 23:32:37 +0200 Subject: [PATCH 030/147] Revert "SAS Bid Adapter: Fledge support (#11348)" (#11349) This reverts commit 2307f938d1428cb1fe319f3906435b9234bb4ac8. --- modules/smartadserverBidAdapter.js | 16 +---- .../modules/smartadserverBidAdapter_spec.js | 65 ------------------- 2 files changed, 1 insertion(+), 80 deletions(-) diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 5bc50190b11..7edaaa36957 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -226,11 +226,6 @@ export const spec = { payload.us_privacy = bidderRequest.uspConsent; } - const ae = deepAccess(bid, 'ortb2Imp.ext.ae'); - if (bidderRequest && bidderRequest.fledgeEnabled && ae) { - payload.ae = ae; - } - const bannerMediaType = deepAccess(bid, 'mediaTypes.banner'); const videoMediaType = deepAccess(bid, 'mediaTypes.video'); const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); @@ -271,7 +266,7 @@ export const spec = { */ interpretResponse: function (serverResponse, bidRequestString) { const bidResponses = []; - const response = serverResponse.body; + let response = serverResponse.body; try { if (response && !response.isNoAd && (response.ad || response.adUrl)) { const bidRequest = JSON.parse(bidRequestString.data); @@ -301,19 +296,10 @@ export const spec = { } bidResponses.push(bidResponse); - - const fledgeAuctionConfigs = response.auctionConfigs; - if (fledgeAuctionConfigs && Array.isArray(fledgeAuctionConfigs)) { - return { - bids: bidResponses, - fledgeAuctionConfigs - }; - } } } catch (error) { logError('Error while parsing smart server response', error); } - return bidResponses; }, diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index a2d053f841f..b01d95e2a4c 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -458,27 +458,6 @@ describe('Smart bid adapter tests', function () { expect(syncs).to.have.lengthOf(0); }); - it('Verify auctionConfigs', function () { - const request = spec.buildRequests(DEFAULT_PARAMS); - const auctionConfigs = [{ - bidId: '02g93e54w9ps', - config: { - decisionLogicUrl: 'https://seller.sas.com/decision_logic.js', - interestGroupBuyers: ['https://buyer.sas.com'], - seller: 'https://seller.sas.com' - } - }]; - const bids = spec.interpretResponse({ - body: { - ...BID_RESPONSE.body, - auctionConfigs - } - }, request[0]); - - expect(bids).to.have.property('bids').and.to.satisfy(value => (value === null || Array.isArray(value))); - expect(bids.fledgeAuctionConfigs).to.be.an('array').and.to.deep.equal(auctionConfigs); - }); - describe('gdpr tests', function () { afterEach(function () { config.setConfig({ ortb2: undefined }); @@ -1526,50 +1505,6 @@ describe('Smart bid adapter tests', function () { }); }); - describe('Fledge for GPT', function () { - it('should send fledge eligibility flag when fledge enabled and ortb2Imp.ext.ae set', function () { - const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); - const ae = { - ae: 1 - }; - - bidRequests[0].ortb2Imp = { - ext: ae - }; - - const request = spec.buildRequests(bidRequests, { - fledgeEnabled: true - }); - const requestContent = JSON.parse(request[0].data); - - expect(requestContent).to.have.property('ae').and.to.equal(ae.ae); - }); - - it('should not send fledge eligibility flag when fledge not enabled', function () { - const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); - bidRequests[0].ortb2Imp = { - ext: { - ae: 1 - } - }; - - const request = spec.buildRequests(bidRequests); - const requestContent = JSON.parse(request[0].data); - - expect(requestContent).to.not.have.property('ae'); - }); - - it('should not send fledge eligibility flag when ortb2Imp.ext.ae not set', function () { - const bidRequests = deepClone(DEFAULT_PARAMS_WO_OPTIONAL); - const request = spec.buildRequests(bidRequests, { - fledgeEnabled: true - }); - const requestContent = JSON.parse(request[0].data); - - expect(requestContent).to.not.have.property('ae'); - }); - }); - describe('#getValuableProperty method', function () { it('should return an object when calling with a number value', () => { const obj = spec.getValuableProperty('prop', 3); From 122a72a3ad0e3dd0a88b170ca4a116245c0d961a Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 16 Apr 2024 17:01:54 -0700 Subject: [PATCH 031/147] PAAPI: add top level auction example (#11259) * bidderFactory fledge API: accept single fledge configs * PAAPI: add top level auction example * update example formatting * provide bidfloor in top level auctionSignals * update example decisionLogic to enforce auction floor, remove reporting * PR feedback * add reportResult --- gulpfile.js | 10 +- .../gpt/top-level-paapi/decisionLogic.js | 57 ++++++ .../gpt/top-level-paapi/tl_paapi_example.html | 188 ++++++++++++++++++ .../creative-renderer-native/renderer.js | 2 +- modules/paapi.js | 22 +- test/spec/modules/paapi_spec.js | 32 ++- 6 files changed, 302 insertions(+), 9 deletions(-) create mode 100644 integrationExamples/gpt/top-level-paapi/decisionLogic.js create mode 100644 integrationExamples/gpt/top-level-paapi/tl_paapi_example.html diff --git a/gulpfile.js b/gulpfile.js index 17c421f4dc1..4dbd92587fe 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -446,7 +446,15 @@ function startLocalServer(options = {}) { port: port, host: INTEG_SERVER_HOST, root: './', - livereload: options.livereload + livereload: options.livereload, + middleware: function () { + return [ + function (req, res, next) { + res.setHeader('Ad-Auction-Allowed', 'True'); + next(); + } + ]; + } }); } diff --git a/integrationExamples/gpt/top-level-paapi/decisionLogic.js b/integrationExamples/gpt/top-level-paapi/decisionLogic.js new file mode 100644 index 00000000000..265234ffeba --- /dev/null +++ b/integrationExamples/gpt/top-level-paapi/decisionLogic.js @@ -0,0 +1,57 @@ +function logPrefix(scope) { + return [ + `%c PAAPI %c ${scope} %c`, + 'color: green; background-color:yellow; border: 1px solid black', + 'color: blue; border:1px solid black', + '', + ]; +} + +function scoreAd( + adMetadata, + bid, + auctionConfig, + trustedScoringSignals, + browserSignals, + directFromSellerSignals +) { + console.group(...logPrefix('scoreAd'), 'Buyer:', browserSignals.interestGroupOwner); + console.log('Context:', JSON.stringify({ + adMetadata, + bid, + auctionConfig: { + ...auctionConfig, + componentAuctions: '[omitted]' + }, + trustedScoringSignals, + browserSignals, + directFromSellerSignals + }, ' ', ' ')); + + const result = { + desirability: bid, + allowComponentAuction: true, + }; + const {bidfloor, bidfloorcur} = auctionConfig.auctionSignals?.prebid || {}; + if (bidfloor) { + if (browserSignals.bidCurrency !== '???' && browserSignals.bidCurrency !== bidfloorcur) { + console.log(`Floor currency (${bidfloorcur}) does not match bid currency (${browserSignals.bidCurrency}), and currency conversion is not yet implemented. Rejecting bid.`); + result.desirability = -1; + } else if (bid < bidfloor) { + console.log(`Bid (${bid}) lower than contextual winner/floor (${bidfloor}). Rejecting bid.`); + result.desirability = -1; + result.rejectReason = 'bid-below-auction-floor'; + } + } + console.log('Result:', result); + console.groupEnd(); + return result; +} + +function reportResult(auctionConfig, browserSignals) { + console.group(...logPrefix('reportResult')); + console.log('Context', JSON.stringify({auctionConfig, browserSignals}, ' ', ' ')); + console.groupEnd(); + sendReportTo(`${auctionConfig.seller}/report/win?${Object.entries(browserSignals).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')}`); + return {}; +} diff --git a/integrationExamples/gpt/top-level-paapi/tl_paapi_example.html b/integrationExamples/gpt/top-level-paapi/tl_paapi_example.html new file mode 100644 index 00000000000..9a4991d2711 --- /dev/null +++ b/integrationExamples/gpt/top-level-paapi/tl_paapi_example.html @@ -0,0 +1,188 @@ + + + + + + + + + + + +

Standalone PAAPI Prebid.js Example

+

Start local server with:

+gulp serve-fast --https +

Chrome flags:

+--enable-features=CookieDeprecationFacilitatedTesting:label/treatment_1.2/force_eligible/true + --privacy-sandbox-enrollment-overrides=https://localhost:9999 +

Join interest group at https://privacysandbox.openx.net/fledge/advertiser +

+
Div-1
+
+ +
+ + + diff --git a/libraries/creative-renderer-native/renderer.js b/libraries/creative-renderer-native/renderer.js index 509f7943af4..57d86fc8ce3 100644 --- a/libraries/creative-renderer-native/renderer.js +++ b/libraries/creative-renderer-native/renderer.js @@ -1,2 +1,2 @@ // this file is autogenerated, see creative/README.md -export const RENDERER = "!function(){\"use strict\";const e=JSON.parse('{\"X3\":{\"B5\":\"Prebid Native\"}}').X3.B5,t={title:\"text\",data:\"value\",img:\"url\",video:\"vasttag\"};function n(e,t){return new Promise(((n,r)=>{const i=t.createElement(\"script\");i.onload=n,i.onerror=r,i.src=e,t.body.appendChild(i)}))}function r(e,t,r,i,o=n){const{rendererUrl:s,assets:a,ortb:d,adTemplate:c}=t,l=i.document;return s?o(s,l).then((()=>{if(\"function\"!=typeof i.renderAd)throw new Error(`Renderer from '${s}' does not define renderAd()`);const e=a||[];return e.ortb=d,i.renderAd(e)})):Promise.resolve(r(c??l.body.innerHTML))}window.render=function({adId:n,native:i},{sendMessage:o},s,a=r){const{head:d,body:c}=s.document,l=()=>o(e,{action:\"resizeNativeHeight\",height:c.offsetHeight,width:c.offsetWidth}),u=function(e,{assets:n=[],ortb:r,nativeKeys:i={}}){const o=Object.fromEntries(n.map((({key:e,value:t})=>[e,t])));let s=Object.fromEntries(Object.entries(i).flatMap((([t,n])=>{const r=o.hasOwnProperty(t)?o[t]:void 0;return[[`##${n}##`,r],[`${n}:${e}`,r]]})));return r&&Object.assign(s,{\"##hb_native_linkurl##\":r.link?.url,\"##hb_native_privacy##\":r.privacy},Object.fromEntries((r.assets||[]).flatMap((e=>{const n=Object.keys(t).find((t=>e[t]));return[n&&[`##hb_native_asset_id_${e.id}##`,e[n][t[n]]],e.link?.url&&[`##hb_native_asset_link_id_${e.id}##`,e.link.url]].filter((e=>e))})))),s=Object.entries(s).concat([[/##hb_native_asset_(link_)?id_\\d+##/g]]),function(e){return s.reduce(((e,[t,n])=>e.replaceAll(t,n||\"\")),e)}}(n,i);return d&&(d.innerHTML=u(d.innerHTML)),a(n,i,u,s).then((t=>{c.innerHTML=t,\"function\"==typeof s.postRenderAd&&s.postRenderAd({adId:n,...i}),s.document.querySelectorAll(\".pb-click\").forEach((t=>{const n=t.getAttribute(\"hb_native_asset_id\");t.addEventListener(\"click\",(()=>o(e,{action:\"click\",assetId:n})))})),o(e,{action:\"fireNativeImpressionTrackers\"}),\"complete\"===s.document.readyState?l():s.onload=l}))}}();" \ No newline at end of file +export const RENDERER = "!function(){\"use strict\";const e=\"Prebid Native\",t={title:\"text\",data:\"value\",img:\"url\",video:\"vasttag\"};function n(e,t){return new Promise(((n,r)=>{const i=t.createElement(\"script\");i.onload=n,i.onerror=r,i.src=e,t.body.appendChild(i)}))}function r(e,t,r,i,o=n){const{rendererUrl:s,assets:a,ortb:d,adTemplate:c}=t,l=i.document;return s?o(s,l).then((()=>{if(\"function\"!=typeof i.renderAd)throw new Error(`Renderer from '${s}' does not define renderAd()`);const e=a||[];return e.ortb=d,i.renderAd(e)})):Promise.resolve(r(c??l.body.innerHTML))}window.render=function({adId:n,native:i},{sendMessage:o},s,a=r){const{head:d,body:c}=s.document,l=()=>o(e,{action:\"resizeNativeHeight\",height:c.offsetHeight,width:c.offsetWidth}),u=function(e,{assets:n=[],ortb:r,nativeKeys:i={}}){const o=Object.fromEntries(n.map((({key:e,value:t})=>[e,t])));let s=Object.fromEntries(Object.entries(i).flatMap((([t,n])=>{const r=o.hasOwnProperty(t)?o[t]:void 0;return[[`##${n}##`,r],[`${n}:${e}`,r]]})));return r&&Object.assign(s,{\"##hb_native_linkurl##\":r.link?.url,\"##hb_native_privacy##\":r.privacy},Object.fromEntries((r.assets||[]).flatMap((e=>{const n=Object.keys(t).find((t=>e[t]));return[n&&[`##hb_native_asset_id_${e.id}##`,e[n][t[n]]],e.link?.url&&[`##hb_native_asset_link_id_${e.id}##`,e.link.url]].filter((e=>e))})))),s=Object.entries(s).concat([[/##hb_native_asset_(link_)?id_\\d+##/g]]),function(e){return s.reduce(((e,[t,n])=>e.replaceAll(t,n||\"\")),e)}}(n,i);return d&&(d.innerHTML=u(d.innerHTML)),a(n,i,u,s).then((t=>{c.innerHTML=t,\"function\"==typeof s.postRenderAd&&s.postRenderAd({adId:n,...i}),s.document.querySelectorAll(\".pb-click\").forEach((t=>{const n=t.getAttribute(\"hb_native_asset_id\");t.addEventListener(\"click\",(()=>o(e,{action:\"click\",assetId:n})))})),o(e,{action:\"fireNativeImpressionTrackers\"}),\"complete\"===s.document.readyState?l():s.onload=l}))}}();" \ No newline at end of file diff --git a/modules/paapi.js b/modules/paapi.js index 5c76b2fb327..9122ecce1a0 100644 --- a/modules/paapi.js +++ b/modules/paapi.js @@ -3,7 +3,7 @@ */ import {config} from '../src/config.js'; import {getHook, module} from '../src/hook.js'; -import {deepSetValue, logInfo, logWarn, mergeDeep} from '../src/utils.js'; +import {deepSetValue, logInfo, logWarn, mergeDeep, parseSizesInput} from '../src/utils.js'; import {IMP, PBS, registerOrtbProcessor, RESPONSE} from '../src/pbjsORTB.js'; import * as events from '../src/events.js'; import {EVENTS} from '../src/constants.js'; @@ -89,19 +89,33 @@ function getSlotSignals(bidsReceived = [], bidRequests = []) { return cfg; } -function onAuctionEnd({auctionId, bidsReceived, bidderRequests, adUnitCodes}) { +function onAuctionEnd({auctionId, bidsReceived, bidderRequests, adUnitCodes, adUnits}) { + const adUnitsByCode = Object.fromEntries(adUnits?.map(au => [au.code, au]) || []) const allReqs = bidderRequests?.flatMap(br => br.bids); const paapiConfigs = {}; (adUnitCodes || []).forEach(au => { paapiConfigs[au] = null; !latestAuctionForAdUnit.hasOwnProperty(au) && (latestAuctionForAdUnit[au] = null); - }) + }); Object.entries(pendingForAuction(auctionId) || {}).forEach(([adUnitCode, auctionConfigs]) => { const forThisAdUnit = (bid) => bid.adUnitCode === adUnitCode; const slotSignals = getSlotSignals(bidsReceived?.filter(forThisAdUnit), allReqs?.filter(forThisAdUnit)); paapiConfigs[adUnitCode] = { + ...slotSignals, componentAuctions: auctionConfigs.map(cfg => mergeDeep({}, slotSignals, cfg)) }; + // TODO: need to flesh out size treatment: + // - which size should the paapi auction pick? (this uses the first one defined) + // - should we signal it to SSPs, and how? + // - what should we do if adapters pick a different one? + // - what does size mean for video and native? + const size = parseSizesInput(adUnitsByCode[adUnitCode]?.mediaTypes?.banner?.sizes)?.[0]?.split('x'); + if (size) { + paapiConfigs[adUnitCode].requestedSize = { + width: size[0], + height: size[1], + }; + } latestAuctionForAdUnit[adUnitCode] = auctionId; }); configsForAuction(auctionId, paapiConfigs); @@ -159,7 +173,7 @@ export function getPAAPIConfig({auctionId, adUnitCode} = {}, includeBlanks = fal output[au] = null; } } - }) + }); return output; } diff --git a/test/spec/modules/paapi_spec.js b/test/spec/modules/paapi_spec.js index 2c7c959ef19..c7d6d88bd12 100644 --- a/test/spec/modules/paapi_spec.js +++ b/test/spec/modules/paapi_spec.js @@ -129,6 +129,30 @@ describe('paapi module', () => { expect(getPAAPIConfig({auctionId})).to.eql({}); }); + it('should use first size as requestedSize', () => { + addComponentAuctionHook(nextFnSpy, { + auctionId, + adUnitCode: 'au1', + }, fledgeAuctionConfig); + events.emit(EVENTS.AUCTION_END, { + auctionId, + adUnits: [ + { + code: 'au1', + mediaTypes: { + banner: { + sizes: [[200, 100], [300, 200]] + } + } + } + ] + }); + expect(getPAAPIConfig({auctionId}).au1.requestedSize).to.eql({ + width: '200', + height: '100' + }) + }) + it('should augment auctionSignals with FPD', () => { addComponentAuctionHook(nextFnSpy, { auctionId, @@ -295,9 +319,11 @@ describe('paapi module', () => { it('should populate bidfloor/bidfloorcur', () => { addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, fledgeAuctionConfig); events.emit(EVENTS.AUCTION_END, payload); - const signals = getPAAPIConfig({auctionId}).au.componentAuctions[0].auctionSignals; - expect(signals.prebid?.bidfloor).to.eql(bidfloor); - expect(signals.prebid?.bidfloorcur).to.eql(bidfloorcur); + const cfg = getPAAPIConfig({auctionId}).au; + const signals = cfg.auctionSignals; + sinon.assert.match(cfg.componentAuctions[0].auctionSignals, signals || {}); + expect(signals?.prebid?.bidfloor).to.eql(bidfloor); + expect(signals?.prebid?.bidfloorcur).to.eql(bidfloorcur); }); }); }); From 43680d4aca77aa129955f9e9657d51a0834298f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Wed, 17 Apr 2024 16:21:01 +0200 Subject: [PATCH 032/147] Criteo Bid Adapter : Add support of pixel based user sync (#11303) --- modules/criteoBidAdapter.js | 50 +++++++++++++--- test/spec/modules/criteoBidAdapter_spec.js | 69 ++++++++++++++++++++-- 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 968a847708e..defe2c081e3 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -55,16 +55,18 @@ export const spec = { gvlid: GVLID, supportedMediaTypes: [BANNER, VIDEO, NATIVE], - getUserSyncs: function (syncOptions, _, gdprConsent, uspConsent) { - const fastBidVersion = config.getConfig('criteo.fastBidVersion'); - if (canFastBid(fastBidVersion)) { - return []; - } - - const refererInfo = getRefererInfo(); - const origin = 'criteoPrebidAdapter'; + getUserSyncs: function (syncOptions, _, gdprConsent, uspConsent, gppConsent = {}) { + let { gppString = '', applicableSections = [] } = gppConsent; if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent)) { + const fastBidVersion = config.getConfig('criteo.fastBidVersion'); + if (canFastBid(fastBidVersion)) { + return []; + } + + const refererInfo = getRefererInfo(); + const origin = 'criteoPrebidAdapter'; + const queryParams = []; queryParams.push(`origin=${origin}`); queryParams.push(`topUrl=${refererInfo.domain}`); @@ -79,6 +81,12 @@ export const spec = { if (uspConsent) { queryParams.push(`us_privacy=${uspConsent}`); } + queryParams.push(`gpp=${gppString}`); + if (Array.isArray(applicableSections)) { + for (const applicableSection of applicableSections) { + queryParams.push(`gpp_sid=${applicableSection}`); + } + } const requestId = Math.random().toString(); @@ -126,6 +134,32 @@ export const spec = { type: 'iframe', url: `https://gum.criteo.com/syncframe?${queryParams.join('&')}#${jsonHashSerialized}` }]; + } else if (syncOptions.pixelEnabled && hasPurpose1Consent(gdprConsent)) { + const queryParams = []; + queryParams.push(`profile=207`); + if (gdprConsent) { + if (gdprConsent.gdprApplies === true) { + queryParams.push(`gdprapplies=true`); + } + if (gdprConsent.consentString) { + queryParams.push(`gdpr=${gdprConsent.consentString}`); + } + } + if (uspConsent) { + queryParams.push(`ccpa=${uspConsent}`); + } + queryParams.push(`gpp=${gppString}`); + if (Array.isArray(applicableSections)) { + for (const applicableSection of applicableSections) { + queryParams.push(`gpp_sid=${applicableSection}`); + } + } + // gpp + // gpp_sid + return [{ + type: 'image', + url: `https://ssp-sync.criteo.com/user-sync/redirect?${queryParams.join('&')}` + }]; } return []; }, diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 083ae368afb..c460b451193 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -38,7 +38,66 @@ describe('The Criteo bidding adapter', function () { ajaxStub.restore(); }); - describe('getUserSyncs', function () { + describe('getUserSyncs in pixel mode', function () { + const syncOptions = { + pixelEnabled: true + }; + + it('should not trigger sync if publisher did not enable pixel based syncs', function () { + const userSyncs = spec.getUserSyncs({ + iframeEnabled: false + }, undefined, undefined, undefined); + + expect(userSyncs).to.eql([]); + }); + + it('should not trigger sync if purpose one is not granted', function () { + const gdprConsent = { + gdprApplies: true, + consentString: 'ABC', + vendorData: { + purpose: { + consents: { + 1: false + } + } + } + }; + const userSyncs = spec.getUserSyncs(syncOptions, undefined, gdprConsent, undefined); + + expect(userSyncs).to.eql([]); + }); + + it('should trigger sync with consent data', function () { + const usPrivacy = 'usp_string'; + + const gppConsent = { + gppString: 'gpp_string', + applicableSections: [ 1, 2 ] + }; + + const gdprConsent = { + gdprApplies: true, + consentString: 'ABC', + vendorData: { + purpose: { + consents: { + 1: true + } + } + } + }; + + const userSyncs = spec.getUserSyncs(syncOptions, undefined, gdprConsent, usPrivacy, gppConsent); + + expect(userSyncs).to.eql([{ + type: 'image', + url: 'https://ssp-sync.criteo.com/user-sync/redirect?profile=207&gdprapplies=true&gdpr=ABC&ccpa=usp_string&gpp=gpp_string&gpp_sid=1&gpp_sid=2' + }]); + }); + }); + + describe('getUserSyncs in iframe mode', function () { const syncOptionsIframeEnabled = { iframeEnabled: true }; @@ -151,7 +210,7 @@ describe('The Criteo bidding adapter', function () { expect(userSyncs).to.eql([{ type: 'iframe', - url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com#${JSON.stringify(expectedHashWithCookieData, Object.keys(expectedHashWithCookieData).sort()).replace(/"/g, '%22')}` + url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&gpp=#${JSON.stringify(expectedHashWithCookieData, Object.keys(expectedHashWithCookieData).sort()).replace(/"/g, '%22')}` }]); }); @@ -175,7 +234,7 @@ describe('The Criteo bidding adapter', function () { expect(userSyncs).to.eql([{ type: 'iframe', - url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com#${JSON.stringify(expectedHashWithLocalStorageData, Object.keys(expectedHashWithLocalStorageData).sort()).replace(/"/g, '%22')}` + url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&gpp=#${JSON.stringify(expectedHashWithLocalStorageData, Object.keys(expectedHashWithLocalStorageData).sort()).replace(/"/g, '%22')}` }]); }); @@ -195,7 +254,7 @@ describe('The Criteo bidding adapter', function () { expect(userSyncs).to.eql([{ type: 'iframe', - url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&gdpr=1&gdpr_consent=ABC#${JSON.stringify(expectedHash).replace(/"/g, '%22')}` + url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&gdpr=1&gdpr_consent=ABC&gpp=#${JSON.stringify(expectedHash).replace(/"/g, '%22')}` }]); }); @@ -204,7 +263,7 @@ describe('The Criteo bidding adapter', function () { expect(userSyncs).to.eql([{ type: 'iframe', - url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&us_privacy=ABC#${JSON.stringify(expectedHash).replace(/"/g, '%22')}` + url: `https://gum.criteo.com/syncframe?origin=criteoPrebidAdapter&topUrl=www.abc.com&us_privacy=ABC&gpp=#${JSON.stringify(expectedHash).replace(/"/g, '%22')}` }]); }); From bf4967f3fe3354d3df3d24bd30a189d51f639988 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 17 Apr 2024 14:09:12 -0700 Subject: [PATCH 033/147] Core: fix bidderRequestsCount (#11295) --- src/adUnits.js | 30 ++--- src/adapterManager.js | 20 +++- src/prebid.js | 4 - test/spec/unit/adUnits_spec.js | 2 +- test/spec/unit/core/adapterManager_spec.js | 128 ++++++++++++++------- 5 files changed, 109 insertions(+), 75 deletions(-) diff --git a/src/adUnits.js b/src/adUnits.js index cdac649c5b8..b0c728fd945 100644 --- a/src/adUnits.js +++ b/src/adUnits.js @@ -1,6 +1,9 @@ import { deepAccess } from './utils.js'; let adUnits = {}; +export function reset() { + adUnits = {} +} function ensureAdUnit(adunit, bidderCode) { let adUnit = adUnits[adunit] = adUnits[adunit] || { bidders: {} }; @@ -21,7 +24,7 @@ function incrementAdUnitCount(adunit, counter, bidderCode) { * @param {string} adunit id * @returns {number} current adunit count */ -function incrementRequestsCounter(adunit) { +export function incrementRequestsCounter(adunit) { return incrementAdUnitCount(adunit, 'requestsCounter'); } @@ -31,7 +34,7 @@ function incrementRequestsCounter(adunit) { * @param {string} bidderCode code * @returns {number} current adunit bidder requests count */ -function incrementBidderRequestsCounter(adunit, bidderCode) { +export function incrementBidderRequestsCounter(adunit, bidderCode) { return incrementAdUnitCount(adunit, 'requestsCounter', bidderCode); } @@ -41,7 +44,7 @@ function incrementBidderRequestsCounter(adunit, bidderCode) { * @param {string} bidderCode code * @returns {number} current adunit bidder requests count */ -function incrementBidderWinsCounter(adunit, bidderCode) { +export function incrementBidderWinsCounter(adunit, bidderCode) { return incrementAdUnitCount(adunit, 'winsCounter', bidderCode); } @@ -50,7 +53,7 @@ function incrementBidderWinsCounter(adunit, bidderCode) { * @param {string} adunit id * @returns {number} current adunit count */ -function getRequestsCounter(adunit) { +export function getRequestsCounter(adunit) { return deepAccess(adUnits, `${adunit}.requestsCounter`) || 0; } @@ -60,7 +63,7 @@ function getRequestsCounter(adunit) { * @param {string} bidder code * @returns {number} current adunit bidder requests count */ -function getBidderRequestsCounter(adunit, bidder) { +export function getBidderRequestsCounter(adunit, bidder) { return deepAccess(adUnits, `${adunit}.bidders.${bidder}.requestsCounter`) || 0; } @@ -70,21 +73,6 @@ function getBidderRequestsCounter(adunit, bidder) { * @param {string} bidder code * @returns {number} current adunit bidder requests count */ -function getBidderWinsCounter(adunit, bidder) { +export function getBidderWinsCounter(adunit, bidder) { return deepAccess(adUnits, `${adunit}.bidders.${bidder}.winsCounter`) || 0; } - -/** - * A module which counts how many times an adunit was called - * @module adunitCounter - */ -let adunitCounter = { - incrementRequestsCounter, - incrementBidderRequestsCounter, - incrementBidderWinsCounter, - getRequestsCounter, - getBidderRequestsCounter, - getBidderWinsCounter -} - -export { adunitCounter }; diff --git a/src/adapterManager.js b/src/adapterManager.js index cbabfa4380e..557f4c1eee4 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -27,7 +27,12 @@ import {ajaxBuilder} from './ajax.js'; import {config, RANDOM} from './config.js'; import {hook} from './hook.js'; import {find, includes} from './polyfill.js'; -import {adunitCounter} from './adUnits.js'; +import { + getBidderRequestsCounter, + getBidderWinsCounter, + getRequestsCounter, incrementBidderRequestsCounter, + incrementBidderWinsCounter, incrementRequestsCounter +} from './adUnits.js'; import {getRefererInfo} from './refererDetection.js'; import {GDPR_GVLIDS, gdprDataHandler, gppDataHandler, uspDataHandler, } from './consentHandler.js'; import * as events from './events.js'; @@ -112,6 +117,10 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics} ); } + if (src === 'client') { + incrementBidderRequestsCounter(adUnit.code, bidderCode); + } + bids.push(Object.assign({}, bid, { adUnitCode: adUnit.code, transactionId: adUnit.transactionId, @@ -122,9 +131,9 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics} auctionId, src, metrics, - bidRequestsCount: adunitCounter.getRequestsCounter(adUnit.code), - bidderRequestsCount: adunitCounter.getBidderRequestsCounter(adUnit.code, bid.bidder), - bidderWinsCount: adunitCounter.getBidderWinsCounter(adUnit.code, bid.bidder), + bidRequestsCount: getRequestsCounter(adUnit.code), + bidderRequestsCount: getBidderRequestsCounter(adUnit.code, bid.bidder), + bidderWinsCount: getBidderWinsCounter(adUnit.code, bid.bidder), })); return bids; }, []) @@ -253,6 +262,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a } // filter out bidders that cannot participate in the auction au.bids = au.bids.filter((bid) => !bid.bidder || dep.isAllowed(ACTIVITY_FETCH_BIDS, activityParams(MODULE_TYPE_BIDDER, bid.bidder))) + incrementRequestsCounter(au.code); }); adUnits = setupAdUnitMediaTypes(adUnits, labels); @@ -655,7 +665,7 @@ adapterManager.callTimedOutBidders = function(adUnits, timedOutBidders, cbTimeou adapterManager.callBidWonBidder = function(bidder, bid, adUnits) { // Adding user configured params to bidWon event data bid.params = getUserConfiguredParams(adUnits, bid.adUnitCode, bid.bidder); - adunitCounter.incrementBidderWinsCounter(bid.adUnitCode, bid.bidder); + incrementBidderWinsCounter(bid.adUnitCode, bid.bidder); tryCallBidderMethod(bidder, 'onBidWon', bid); }; diff --git a/src/prebid.js b/src/prebid.js index e96c0b36c9f..7f2d8798e2a 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -30,7 +30,6 @@ import {isBidUsable, targeting} from './targeting.js'; import {hook, wrapHook} from './hook.js'; import {loadSession} from './debugging.js'; import {includes} from './polyfill.js'; -import {adunitCounter} from './adUnits.js'; import {createBid} from './bidfactory.js'; import {storageCallbacks} from './storageManager.js'; import {default as adapterManager, getS2SBidderSet} from './adapterManager.js'; @@ -593,11 +592,8 @@ export const startAuction = hook('async', function ({ bidsBackHandler, timeout: // drop the bidder from the ad unit if it's not compatible logWarn(unsupportedBidderMessage(adUnit, bidder)); adUnit.bids = adUnit.bids.filter(bid => bid.bidder !== bidder); - } else { - adunitCounter.incrementBidderRequestsCounter(adUnit.code, bidder); } }); - adunitCounter.incrementRequestsCounter(adUnit.code); }); if (!adUnits || adUnits.length === 0) { logMessage('No adUnits configured. No bids requested.'); diff --git a/test/spec/unit/adUnits_spec.js b/test/spec/unit/adUnits_spec.js index a8443d36522..1b26f7d5601 100644 --- a/test/spec/unit/adUnits_spec.js +++ b/test/spec/unit/adUnits_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { adunitCounter } from 'src/adUnits.js'; +import * as adunitCounter from 'src/adUnits.js'; describe('Adunit Counter', function () { const ADUNIT_ID_1 = 'test1'; diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 590d4829b49..9132aaeb903 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -24,6 +24,8 @@ import {auctionManager} from '../../../../src/auctionManager.js'; import {GDPR_GVLIDS} from '../../../../src/consentHandler.js'; import {MODULE_TYPE_ANALYTICS, MODULE_TYPE_BIDDER} from '../../../../src/activities/modules.js'; import {ACTIVITY_FETCH_BIDS, ACTIVITY_REPORT_ANALYTICS} from '../../../../src/activities/activities.js'; +import {reset as resetAdUnitCounters} from '../../../../src/adUnits.js'; +import {deepClone} from 'src/utils.js'; var events = require('../../../../src/events'); const CONFIG = { @@ -1675,12 +1677,24 @@ describe('adapterManager tests', function () { describe('makeBidRequests', function () { let adUnits; beforeEach(function () { + resetAdUnitCounters(); adUnits = utils.deepClone(getAdUnits()).map(adUnit => { adUnit.bids = adUnit.bids.filter(bid => includes(['appnexus', 'rubicon'], bid.bidder)); return adUnit; }) }); + function makeBidRequests(au = adUnits) { + return adapterManager.makeBidRequests( + au, + Date.now(), + utils.getUniqueIdentifierStr(), + function callback() { + }, + [] + ); + } + if (FEATURES.NATIVE) { it('should add nativeParams to adUnits after BEFORE_REQUEST_BIDS', () => { function beforeReqBids(adUnits) { @@ -1692,14 +1706,7 @@ describe('adapterManager tests', function () { } events.on(EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); - adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() { - }, - [] - ); + makeBidRequests(); events.off(EVENTS.BEFORE_REQUEST_BIDS, beforeReqBids); expect(adUnits.map((u) => u.nativeParams).some(i => i == null)).to.be.false; }); @@ -1708,13 +1715,7 @@ describe('adapterManager tests', function () { it('should make separate bidder request objects for each bidder', () => { adUnits = [utils.deepClone(getAdUnits()[0])]; - let bidRequests = adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() {}, - [] - ); + let bidRequests = makeBidRequests(); let sizes1 = bidRequests[1].bids[0].sizes; let sizes2 = bidRequests[0].bids[0].sizes; @@ -1725,6 +1726,70 @@ describe('adapterManager tests', function () { expect(sizes1).not.to.deep.equal(sizes2); }); + it('should set and increment bidRequestsCounter', () => { + const [au1, au2] = adUnits; + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.bidRequestsCount).to.eql(1); + }) + makeBidRequests([au1]); + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.bidRequestsCount).to.eql(bid.adUnitCode === au1.code ? 3 : 2); + }); + }) + + describe('bidderRequestsCounter', () => { + it('should be set and incremented', () => { + const [au1, au2] = adUnits; + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.bidderRequestsCount).to.eql(1); + }); + const au3 = { + ...au2, + bids: [ + au2.bids[0] + ] + } + makeBidRequests([au3]); + const counts = Object.fromEntries( + makeBidRequests([au1, au2]) + .map(br => [br.bidderCode, Object.fromEntries(br.bids.map(bid => [bid.adUnitCode, bid.bidderRequestsCount]))]) + ); + expect(counts).to.eql({ + rubicon: { + [au2.code]: 2 + }, + appnexus: { + [au1.code]: 2, + [au2.code]: 3 + }, + }); + }); + + it('should NOT be incremented for s2s bids', () => { + config.setConfig({ + s2sConfig: { + enabled: true, + adapter: 'rubicon', + bidders: ['appnexus'] + } + }); + function expectBidderCounts(bidders) { + makeBidRequests().forEach(br => { + br.bids.forEach(bid => expect(bid.bidderRequestsCount).to.exist.and.eql(bidders[br.bidderCode])); + }) + } + expectBidderCounts({ + appnexus: 0, + rubicon: 1 + }); + config.resetConfig(); + expectBidderCounts({ + appnexus: 1, + rubicon: 2 + }) + }) + }); + describe('and activity controls', () => { let redactOrtb2; let redactBidRequest; @@ -1757,13 +1822,7 @@ describe('adapterManager tests', function () { componentType === MODULE_TYPE_BIDDER && allowed.includes(componentName); }); - let reqs = adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() {}, - [] - ); + let reqs = makeBidRequests(); const bidders = Array.from(new Set(reqs.flatMap(br => br.bids).map(bid => bid.bidder)).keys()); expect(bidders).to.have.members(allowed); }); @@ -1773,13 +1832,7 @@ describe('adapterManager tests', function () { adUnits = [ {code: 'one', bids: [{bidder: 'mockBidder1'}]} ]; - let reqs = adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() {}, - [] - ); + let reqs = makeBidRequests(); sinon.assert.calledWith(redactBidRequest, reqs[0].bids[0]); sinon.assert.calledWith(redactOrtb2, reqs[0].ortb2); }) @@ -1812,13 +1865,7 @@ describe('adapterManager tests', function () { {code: 'two', bids: [{module: 'pbsBidAdapter', params: {configName: 'mock1'}}, {module: 'pbsBidAdapter', params: {configName: 'mock2'}}]} ] dep.isAllowed.callsFake(({componentType}) => componentType !== 'bidder'); - let bidRequests = adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() {}, - [] - ); + let bidRequests = makeBidRequests(); expect(new Set(bidRequests.map(br => br.uniquePbsTid)).size).to.equal(3); }); @@ -1835,14 +1882,7 @@ describe('adapterManager tests', function () { } ]; dep.isAllowed.callsFake((_, {configName, componentName}) => !(componentName === 'pbsBidAdapter' && configName === 'mock1')); - let bidRequests = adapterManager.makeBidRequests( - adUnits, - Date.now(), - utils.getUniqueIdentifierStr(), - function callback() { - }, - [] - ); + let bidRequests = makeBidRequests(); expect(new Set(bidRequests.map(br => br.uniquePbsTid)).size).to.eql(2) }); }); From e576447077fd5a071c1d2bf01bd497bacc964582 Mon Sep 17 00:00:00 2001 From: PGAMSSP <142323401+PGAMSSP@users.noreply.github.com> Date: Thu, 18 Apr 2024 00:36:13 +0300 Subject: [PATCH 034/147] PgamSSP Bid Adapter: gpp support (#11354) * new adapter PGAMSSP * upd * support UID 2.0 * del obj * Add id5id * add support gpp * fix spaces --------- Co-authored-by: Chris Huie --- modules/pgamsspBidAdapter.js | 29 +++++++++-- test/spec/modules/pgamsspBidAdapter_spec.js | 54 +++++++++++++++++++-- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/modules/pgamsspBidAdapter.js b/modules/pgamsspBidAdapter.js index f3062fa4ff0..fdc6bcf302f 100644 --- a/modules/pgamsspBidAdapter.js +++ b/modules/pgamsspBidAdapter.js @@ -171,11 +171,27 @@ export const spec = { page, placements, coppa: config.getConfig('coppa') === true ? 1 : 0, - ccpa: bidderRequest.uspConsent || undefined, - gdpr: bidderRequest.gdprConsent || undefined, tmax: bidderRequest.timeout }; + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + + if (bidderRequest.gdprConsent) { + request.gdpr = { + consentString: bidderRequest.gdprConsent.consentString + }; + } + + if (bidderRequest.gppConsent) { + request.gpp = bidderRequest.gppConsent.gppString; + request.gpp_sid = bidderRequest.gppConsent.applicableSections; + } else if (bidderRequest.ortb2?.regs?.gpp) { + request.gpp = bidderRequest.ortb2.regs.gpp; + request.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; + } + const len = validBidRequests.length; for (let i = 0; i < len; i++) { const bid = validBidRequests[i]; @@ -203,9 +219,10 @@ export const spec = { return response; }, - getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { if (typeof gdprConsent.gdprApplies === 'boolean') { syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; @@ -213,10 +230,16 @@ export const spec = { syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; } } + if (uspConsent && uspConsent.consentString) { syncUrl += `&ccpa_consent=${uspConsent.consentString}`; } + if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { + syncUrl += '&gpp=' + gppConsent.gppString; + syncUrl += '&gpp_sid=' + gppConsent.applicableSections.join(','); + } + const coppa = config.getConfig('coppa') ? 1 : 0; syncUrl += `&coppa=${coppa}`; diff --git a/test/spec/modules/pgamsspBidAdapter_spec.js b/test/spec/modules/pgamsspBidAdapter_spec.js index 0766219eda8..281a012fb7a 100644 --- a/test/spec/modules/pgamsspBidAdapter_spec.js +++ b/test/spec/modules/pgamsspBidAdapter_spec.js @@ -73,7 +73,9 @@ describe('PGAMBidAdapter', function () { const bidderRequest = { uspConsent: '1---', - gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + gdprConsent: { + consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw' + }, refererInfo: { referer: 'https://test.com' }, @@ -129,7 +131,7 @@ describe('PGAMBidAdapter', function () { expect(data.host).to.be.a('string'); expect(data.page).to.be.a('string'); expect(data.coppa).to.be.a('number'); - expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.be.a('object'); expect(data.ccpa).to.be.a('string'); expect(data.tmax).to.be.a('number'); expect(data.placements).to.have.lengthOf(3); @@ -171,8 +173,8 @@ describe('PGAMBidAdapter', function () { serverRequest = spec.buildRequests(bids, bidderRequest); let data = serverRequest.data; expect(data.gdpr).to.exist; - expect(data.gdpr).to.be.a('string'); - expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.gdpr).to.be.a('object'); + expect(data.gdpr.consentString).to.equal(bidderRequest.gdprConsent.consentString); expect(data.ccpa).to.not.exist; delete bidderRequest.gdprConsent; }); @@ -195,6 +197,38 @@ describe('PGAMBidAdapter', function () { }); }); + describe('gpp consent', function () { + it('bidderRequest.gppConsent', () => { + bidderRequest.gppConsent = { + gppString: 'abc123', + applicableSections: [8] + }; + + let serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.property('gpp'); + expect(data).to.have.property('gpp_sid'); + + delete bidderRequest.gppConsent; + }) + + it('bidderRequest.ortb2.regs.gpp', () => { + bidderRequest.ortb2 = bidderRequest.ortb2 || {}; + bidderRequest.ortb2.regs = bidderRequest.ortb2.regs || {}; + bidderRequest.ortb2.regs.gpp = 'abc123'; + bidderRequest.ortb2.regs.gpp_sid = [8]; + + let serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.property('gpp'); + expect(data).to.have.property('gpp_sid'); + + bidderRequest.ortb2; + }) + }); + describe('interpretResponse', function () { it('Should interpret banner response', function () { const banner = { @@ -396,5 +430,17 @@ describe('PGAMBidAdapter', function () { expect(syncData[0].url).to.be.a('string') expect(syncData[0].url).to.equal('https://cs.pgammedia.com/image?pbjs=1&ccpa_consent=1---&coppa=0') }); + it('Should return array of objects with proper sync config , include GPP', function() { + const syncData = spec.getUserSyncs({}, {}, {}, {}, { + gppString: 'abc123', + applicableSections: [8] + }); + expect(syncData).to.be.an('array').which.is.not.empty; + expect(syncData[0]).to.be.an('object') + expect(syncData[0].type).to.be.a('string') + expect(syncData[0].type).to.equal('image') + expect(syncData[0].url).to.be.a('string') + expect(syncData[0].url).to.equal('https://cs.pgammedia.com/image?pbjs=1&gpp=abc123&gpp_sid=8&coppa=0') + }); }); }); From 75602dcab220730576317919b49ff06b95864e99 Mon Sep 17 00:00:00 2001 From: Denis Logachov Date: Thu, 18 Apr 2024 17:25:40 +0300 Subject: [PATCH 035/147] Adkernel Bid Adapter: bid.mtype support (#11355) --- modules/adkernelBidAdapter.js | 12 +++++++++--- test/spec/modules/adkernelBidAdapter_spec.js | 13 +++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index ae02a8967b1..0c353e4332a 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -51,6 +51,12 @@ const MULTI_FORMAT_SUFFIX_BANNER = 'b' + MULTI_FORMAT_SUFFIX; const MULTI_FORMAT_SUFFIX_VIDEO = 'v' + MULTI_FORMAT_SUFFIX; const MULTI_FORMAT_SUFFIX_NATIVE = 'n' + MULTI_FORMAT_SUFFIX; +const MEDIA_TYPES = { + BANNER: 1, + VIDEO: 2, + NATIVE: 4 +}; + /** * Adapter for requesting bids from AdKernel white-label display platform */ @@ -159,17 +165,17 @@ export const spec = { if (prBid.requestId.endsWith(MULTI_FORMAT_SUFFIX)) { prBid.requestId = stripMultiformatSuffix(prBid.requestId); } - if ('banner' in imp) { + if (rtbBid.mtype === MEDIA_TYPES.BANNER) { prBid.mediaType = BANNER; prBid.width = rtbBid.w; prBid.height = rtbBid.h; prBid.ad = formatAdMarkup(rtbBid); - } else if ('video' in imp) { + } else if (rtbBid.mtype === MEDIA_TYPES.VIDEO) { prBid.mediaType = VIDEO; prBid.vastUrl = rtbBid.nurl; prBid.width = imp.video.w; prBid.height = imp.video.h; - } else if ('native' in imp) { + } else if (rtbBid.mtype === MEDIA_TYPES.NATIVE) { prBid.mediaType = NATIVE; prBid.native = { ortb: buildNativeAd(rtbBid.adm) diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js index cdfc9795b85..ceb5d029203 100644 --- a/test/spec/modules/adkernelBidAdapter_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -218,7 +218,8 @@ describe('Adkernel adapter', function () { adm: '', w: 300, h: 250, - dealid: 'deal' + dealid: 'deal', + mtype: 1 }] }], ext: { @@ -234,7 +235,8 @@ describe('Adkernel adapter', function () { price: 0.00145, adid: '158801', nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl', - cid: '16855' + cid: '16855', + mtype: 2 }] }], }, usersyncOnlyResponse = { @@ -269,6 +271,7 @@ describe('Adkernel adapter', function () { cat: ['IAB1-4', 'IAB8-16', 'IAB25-5'], cid: '1', crid: '4', + mtype: 4, ext: { 'advertiser_id': 777, 'advertiser_name': 'advertiser', @@ -290,7 +293,8 @@ describe('Adkernel adapter', function () { adid: '158801', adm: '', nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl', - cid: '16855' + cid: '16855', + mtype: 1 }, { id: 'sZSYq5zYMxo_1', impid: 'Bid_01v__mf', @@ -298,7 +302,8 @@ describe('Adkernel adapter', function () { price: 0.25, adid: '158801', nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_1&f=nurl', - cid: '16855' + cid: '16855', + mtype: 2 }] }], bidid: 'pTuOlf5KHUo', From 08ac74f3ca062fb3a34c42e073d39dadfff94d46 Mon Sep 17 00:00:00 2001 From: Kevin Siow Date: Thu, 18 Apr 2024 18:13:10 +0200 Subject: [PATCH 036/147] Dailymotion Bid Adaptor: initial release (#10970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dailymotion Bid Adaptor: initial release * .md file lint issue resolved * Dailymotion Bid Adaptor: build bidder request based on param with fallbacks * Dailymotion Bid Adaptor: support video metadata * Dailymotion Bid Adaptor: add support for sending adUnitCode * Dailymotion Bid Adaptor: add support for sending startDelay * feat(LEO-528): Allow multiple IAB categories in video metadata The same way as we can have an array of IAB categories level 1 in the ORTB request, this PR introduces an array for the IAB categories level 2. To be forward compatible with level [2.2](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.2.tsv) and [3.0](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%203.0.tsv) specifications, the category IDs should be sent as strings. * Dailymotion bid adapter: Clarify the video metadata to provide in each player context * Dailymotion bid adapter: Move API key to bid params * Dailymotion bid adapter: Verify API key is string Co-authored-by: Rumesh * Dailymotion bid adapter: Move API key to bid params (fix tests) * Dailymotion Bid Adaptor: add gpp support and get coppa from request * Dailymotion Bid Adaptor: fix lint error * Dailymotion Bid Adaptor: add iabcat1 and fallback to ortb2 for iabcat2 * Dailymotion Bid Adaptor: get iabcats from ortb2.site.content.data --------- Co-authored-by: Kevin Siow Co-authored-by: Aditi Chaudhary Co-authored-by: Sébastien Millet Co-authored-by: Rumesh --- modules/dailymotionBidAdapter.js | 139 +++++++ modules/dailymotionBidAdapter.md | 140 +++++++ .../modules/dailymotionBidAdapter_spec.js | 369 ++++++++++++++++++ 3 files changed, 648 insertions(+) create mode 100644 modules/dailymotionBidAdapter.js create mode 100644 modules/dailymotionBidAdapter.md create mode 100644 test/spec/modules/dailymotionBidAdapter_spec.js diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js new file mode 100644 index 00000000000..2be5edad78e --- /dev/null +++ b/modules/dailymotionBidAdapter.js @@ -0,0 +1,139 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO } from '../src/mediaTypes.js'; +import { deepAccess } from '../src/utils.js'; + +/** + * Get video metadata from bid request + * + * @param {BidRequest} bidRequest A valid bid requests that should be sent to the Server. + * @return video metadata + */ +function getVideoMetadata(bidRequest, bidderRequest) { + const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video', {}); + const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + + const videoParams = { + ...videoAdUnit, + ...videoBidderParams, // Bidder Specific overrides + }; + + // Store as object keys to ensure uniqueness + const iabcat1 = {}; + const iabcat2 = {}; + + deepAccess(bidderRequest, 'ortb2.site.content.data', []).forEach((data) => { + if ([4, 5, 6, 7].includes(data?.ext?.segtax)) { + (Array.isArray(data.segment) ? data.segment : []).forEach((segment) => { + if (typeof segment.id === 'string') { + // See https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy + // Only take IAB cats of taxonomy V1 + if (data.ext.segtax === 4) iabcat1[segment.id] = 1; + // Only take IAB cats of taxonomy V2 or higher + if ([5, 6, 7].includes(data.ext.segtax)) iabcat2[segment.id] = 1; + } + }); + } + }); + + const videoMetadata = { + description: videoParams.description || '', + duration: videoParams.duration || 0, + iabcat1: Object.keys(iabcat1), + iabcat2: Array.isArray(videoParams.iabcat2) + ? videoParams.iabcat2 + : Object.keys(iabcat2), + id: videoParams.id || '', + lang: videoParams.lang || '', + private: videoParams.private || false, + tags: videoParams.tags || '', + title: videoParams.title || '', + topics: videoParams.topics || '', + xid: videoParams.xid || '', + }; + + return videoMetadata; +} + +export const spec = { + code: 'dailymotion', + gvlid: 573, + supportedMediaTypes: [VIDEO], + + /** + * Determines whether or not the given bid request is valid. + * The only mandatory parameter for a bid to be valid is the API key. + * Other parameters are optional. + * + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return typeof bid?.params?.apiKey === 'string' && bid.params.apiKey.length > 10; + }, + + /** + * Make a server request from the list of valid BidRequests (that already passed the isBidRequestValid call) + * + * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. + * @param {BidderRequest} bidderRequest + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: (validBidRequests = [], bidderRequest) => validBidRequests.map(bid => ({ + method: 'POST', + url: 'https://pb.dmxleo.com', + data: { + bidder_request: { + gdprConsent: { + apiVersion: bidderRequest?.gdprConsent?.apiVersion || 1, + consentString: bidderRequest?.gdprConsent?.consentString || '', + // Cast boolean in any case (eg: if value is int) to ensure type + gdprApplies: !!bidderRequest?.gdprConsent?.gdprApplies, + }, + refererInfo: { + page: bidderRequest?.refererInfo?.page || '', + }, + uspConsent: bidderRequest?.uspConsent || '', + gppConsent: { + gppString: deepAccess(bidderRequest, 'gppConsent.gppString') || + deepAccess(bidderRequest, 'ortb2.regs.gpp', ''), + applicableSections: deepAccess(bidderRequest, 'gppConsent.applicableSections') || + deepAccess(bidderRequest, 'ortb2.regs.gpp_sid', []), + }, + }, + config: { + api_key: bid.params.apiKey + }, + // Cast boolean in any case (value should be 0 or 1) to ensure type + coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'), + request: { + adUnitCode: bid.adUnitCode || '', + auctionId: bid.auctionId || '', + bidId: bid.bidId || '', + mediaTypes: { + video: { + playerSize: bid.mediaTypes?.[VIDEO]?.playerSize || [], + api: bid.mediaTypes?.[VIDEO]?.api || [], + startDelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, + }, + }, + sizes: bid.sizes || [], + }, + video_metadata: getVideoMetadata(bid, bidderRequest), + }, + options: { + withCredentials: true, + crossOrigin: true, + }, + })), + + /** + * Map the response from the server into a list of bids. + * As dailymotion prebid server returns an entry with the correct Prebid structure, + * we directly include it as the only bid in the response. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: serverResponse => serverResponse?.body ? [serverResponse.body] : [], +}; + +registerBidder(spec); diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md new file mode 100644 index 00000000000..795273c9229 --- /dev/null +++ b/modules/dailymotionBidAdapter.md @@ -0,0 +1,140 @@ +# Overview + +``` +Module Name: Dailymotion Bid Adapter +Module Type: Bidder Adapter +Maintainer: ad-leo-engineering@dailymotion.com +``` + +# Description + +Dailymotion prebid adapter. + +# Configuration options + +Before calling this adapter, you need to set at least the API key in the bid parameters: + +```javascript +const adUnits = [ + { + bids: [{ + bidder: 'dailymotion', + params: { + apiKey: 'fake_api_key' + } + }] + } +]; +``` + +`apiKey` is your publisher API key. For testing purpose, you can use "dailymotion-testing". + +# Test Parameters + +By setting the following bid parameters, you'll get a constant response to any request, to validate your adapter integration: + +```javascript +const adUnits = [ + { + bids: [{ + bidder: 'dailymotion', + params: { + apiKey: 'dailymotion-testing' + } + }] + } +]; +``` + +Please note that failing to set these will result in the adapter not bidding at all. + +# Sample video AdUnit + +To allow better targeting, you should provide as much context about the video as possible. +There are two ways of doing this depending on if you're using Dailymotion player or a third party one. + +If you are using the Dailymotion player, you should only provide the video `xid` in your ad unit, example: + +```javascript +const adUnits = [ + { + bids: [{ + bidder: 'dailymotion', + params: { + apiKey: 'dailymotion-testing' + } + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + api: [2, 7], + context: 'instream', + playerSize: [ [1280, 720] ], + startDelay: 0, + xid: 'x123456' // Dailymotion infrastructure unique video ID + }, + } + } +]; +``` + +This will automatically fetch the most up-to-date information about the video. +If you provide any other metadata in addition to the `xid`, they will be ignored. + +If you are using a third party video player, you should not provide any `xid` and instead fill the following members: + +```javascript +const adUnits = [ + { + bids: [{ + bidder: 'dailymotion', + params: { + apiKey: 'dailymotion-testing', + video: { + description: 'overriden video description' + } + } + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + api: [2, 7], + context: 'instream', + description: 'this is a video description', + duration: 556, + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + playerSize: [ [1280, 720] ], + private: false, + startDelay: 0, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', + }, + } + } +]; +``` + +Each of the following video metadata fields can be added in mediaTypes.video or bids.params.video. +If a field exists in both places, it will be overridden by bids.params.video. + +* `description` - Video description +* `duration` - Video duration in seconds +* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) +* `id` - Video unique ID in host video infrastructure +* `lang` - ISO 639-1 code for main language used in the video +* `private` - True if video is not publicly available +* `tags` - Tags for the video, comma separated +* `title` - Video title +* `topics` - Main topics for the video, comma separated +* `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player) + +# Integrating the adapter + +To use the adapter with any non-test request, you first need to ask an API key from Dailymotion. Please contact us through **DailymotionPrebid.js@dailymotion.com**. + +You will then be able to use it within the bid parameters before making a bid request. + +This API key will ensure proper identification of your inventory and allow you to get real bids. diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js new file mode 100644 index 00000000000..a102c26dca2 --- /dev/null +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -0,0 +1,369 @@ +import { config } from 'src/config.js'; +import { expect } from 'chai'; +import { spec } from 'modules/dailymotionBidAdapter.js'; +import { VIDEO } from '../../../src/mediaTypes'; + +describe('dailymotionBidAdapterTests', () => { + // Validate that isBidRequestValid only validates requests with apiKey + it('validates isBidRequestValid', () => { + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid())).to.be.false; + + const bidWithEmptyApi = { + params: { + apiKey: '', + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyApi))).to.be.false; + + const bidWithApi = { + params: { + apiKey: 'test_api_key', + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithApi))).to.be.true; + }); + + // Validate request generation + it('validates buildRequests', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + playerSize: [[1280, 720]], + api: [2, 7], + description: 'this is a test video', + duration: 300, + iabcat2: ['6', '17'], + lang: 'ENG', + startdelay: 0, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + duration: 556, + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', + xid: 'x123456', + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + site: { + content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 4 }, + segment: [{ id: 'IAB-1' }], + }, + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + const { data: reqData } = request; + + expect(request.url).to.equal('https://pb.dmxleo.com'); + + expect(reqData.bidder_request).to.eql({ + refererInfo: bidderRequestData.refererInfo, + uspConsent: bidderRequestData.uspConsent, + gdprConsent: bidderRequestData.gdprConsent, + gppConsent: bidderRequestData.gppConsent, + }); + expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); + expect(reqData.coppa).to.be.true; + expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); + expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); + expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); + expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); + expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.video_metadata).to.eql({ + description: bidRequestData[0].mediaTypes.video.description, + iabcat1: ['IAB-1'], // Taxonomy v2 or higher is excluded + iabcat2: bidRequestData[0].mediaTypes.video.iabcat2, + id: bidRequestData[0].params.video.id, + lang: bidRequestData[0].params.video.lang, + private: bidRequestData[0].params.video.private, + tags: bidRequestData[0].params.video.tags, + title: bidRequestData[0].params.video.title, + topics: bidRequestData[0].params.video.topics, + xid: bidRequestData[0].params.video.xid, + // Overriden through bidder params + duration: bidRequestData[0].params.video.duration, + }); + }); + + it('validates buildRequests with fallback values on ortb2 for gpp & iabcat', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + playerSize: [[1280, 720]], + api: [2, 7], + description: 'this is a test video', + duration: 300, + lang: 'ENG', + startdelay: 0, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + duration: 556, + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', + xid: 'x123456', + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + }, + ortb2: { + regs: { + gpp: 'xxx', + gpp_sid: [5], + coppa: 0, + }, + site: { + content: { + data: [ + undefined, // Undefined to check proper handling of edge cases + {}, // Empty object to check proper handling of edge cases + { ext: {} }, // Empty ext to check proper handling of edge cases + { + name: 'dataprovider.com', + ext: { segtax: 22 }, // Invalid segtax to check proper handling of edge cases + segment: [{ id: '400' }], + }, + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: undefined, // Invalid segment to check proper handling of edge cases + }, + { + name: 'dataprovider.com', + ext: { segtax: 4 }, + segment: undefined, // Invalid segment to check proper handling of edge cases + }, + { + name: 'dataprovider.com', + ext: { segtax: 4 }, + segment: [{ id: 2222 }], // Invalid segment id to check proper handling of edge cases + }, + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '6' }], + }, + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '6' }], // Check that same cat won't be duplicated + }, + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '17' }, { id: '20' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + const { data: reqData } = request; + + expect(request.url).to.equal('https://pb.dmxleo.com'); + + expect(reqData.bidder_request).to.eql({ + refererInfo: bidderRequestData.refererInfo, + uspConsent: bidderRequestData.uspConsent, + gdprConsent: bidderRequestData.gdprConsent, + gppConsent: { + gppString: bidderRequestData.ortb2.regs.gpp, + applicableSections: bidderRequestData.ortb2.regs.gpp_sid, + }, + }); + expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); + expect(reqData.coppa).to.be.false; + expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); + expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); + expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); + expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); + expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.video_metadata).to.eql({ + description: bidRequestData[0].mediaTypes.video.description, + // No iabcat1 here because nothing matches taxonomy + iabcat1: [], + iabcat2: ['6', '17', '20'], + id: bidRequestData[0].params.video.id, + lang: bidRequestData[0].params.video.lang, + private: bidRequestData[0].params.video.private, + tags: bidRequestData[0].params.video.tags, + title: bidRequestData[0].params.video.title, + topics: bidRequestData[0].params.video.topics, + xid: bidRequestData[0].params.video.xid, + // Overriden through bidder params + duration: bidRequestData[0].params.video.duration, + }); + }); + + it('validates buildRequests - with default values on empty bid & bidder request', () => { + const bidRequestDataWithApi = [{ + params: { + apiKey: 'test_api_key', + }, + }]; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestDataWithApi, {}), + ); + + const { data: reqData } = request; + + expect(request.url).to.equal('https://pb.dmxleo.com'); + + expect(reqData.config.api_key).to.eql(bidRequestDataWithApi[0].params.apiKey); + expect(reqData.coppa).to.be.false; + + expect(reqData.bidder_request).to.eql({ + gdprConsent: { + apiVersion: 1, + consentString: '', + gdprApplies: false, + }, + refererInfo: { + page: '', + }, + uspConsent: '', + gppConsent: { + gppString: '', + applicableSections: [], + }, + }); + + expect(reqData.request).to.eql({ + auctionId: '', + bidId: '', + adUnitCode: '', + mediaTypes: { + video: { + playerSize: [], + startDelay: 0, + api: [], + }, + }, + sizes: [], + }); + + expect(reqData.video_metadata).to.eql({ + description: '', + duration: 0, + iabcat1: [], + iabcat2: [], + id: '', + lang: '', + private: false, + tags: '', + title: '', + topics: '', + xid: '', + }); + }); + + it('validates buildRequests - with empty/undefined validBidRequests', () => { + expect(spec.buildRequests([], {})).to.have.lengthOf(0); + + expect(spec.buildRequests(undefined, {})).to.have.lengthOf(0); + }); + + it('validates interpretResponse', () => { + const serverResponse = { + body: { + ad: 'https://fakecacheserver/cache?uuid=1234', + cacheId: '1234', + cpm: 20.0, + creativeId: '5678', + currency: 'USD', + dealId: 'deal123', + nurl: 'https://bid/nurl', + requestId: 'test_requestid', + vastUrl: 'https://fakecacheserver/cache?uuid=1234', + }, + }; + + const bids = spec.interpretResponse(serverResponse); + expect(bids).to.have.lengthOf(1); + + const [bid] = bids; + expect(bid).to.eql(serverResponse.body); + }); + + it('validates interpretResponse - with empty/undefined serverResponse', () => { + expect(spec.interpretResponse({})).to.have.lengthOf(0); + + expect(spec.interpretResponse(undefined)).to.have.lengthOf(0); + }); +}); From ed7e942c3c074be9febb16a62e59663a1c017862 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 18 Apr 2024 09:14:54 -0700 Subject: [PATCH 037/147] Core: update creative code and example (#11350) --- integrationExamples/gpt/x-domain/creative.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html index bf2bd5f3fad..0d0f63cbf1b 100644 --- a/integrationExamples/gpt/x-domain/creative.html +++ b/integrationExamples/gpt/x-domain/creative.html @@ -2,7 +2,7 @@ // creative will be rendered, e.g. GAM delivering a SafeFrame // this code is autogenerated, also available in 'build/creative/creative.js' - + + + + + + + + diff --git a/integrationExamples/realTimeData/jwplayerRtdProvider_example.html b/integrationExamples/realTimeData/jwplayerRtdProvider_example.html index 4f29ef1c406..f3f0c64fb1a 100644 --- a/integrationExamples/realTimeData/jwplayerRtdProvider_example.html +++ b/integrationExamples/realTimeData/jwplayerRtdProvider_example.html @@ -35,6 +35,13 @@ }, // Replace this object to test a new Adapter! bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html index 80ea81d09b6..d0b261043e4 100644 --- a/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html @@ -20,6 +20,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html b/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html index 663765317b0..c40af32cac2 100644 --- a/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html +++ b/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html @@ -50,12 +50,17 @@ mediationLayerAdServer: "dfp", bidTimeout: 2000 }, - bidders: [ - { + bidders: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { name: "ix", siteId: "300" - } - ] + }] } } } diff --git a/integrationExamples/videoModule/jwplayer/bidsBackHandlerOverride.html b/integrationExamples/videoModule/jwplayer/bidsBackHandlerOverride.html index 66eaff26090..75a72ba3501 100644 --- a/integrationExamples/videoModule/jwplayer/bidsBackHandlerOverride.html +++ b/integrationExamples/videoModule/jwplayer/bidsBackHandlerOverride.html @@ -19,6 +19,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/eventListeners.html b/integrationExamples/videoModule/jwplayer/eventListeners.html index 39acb086107..6f04f37264b 100644 --- a/integrationExamples/videoModule/jwplayer/eventListeners.html +++ b/integrationExamples/videoModule/jwplayer/eventListeners.html @@ -23,6 +23,13 @@ // Replace this object to test a new Adapter! bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/eventsUI.html b/integrationExamples/videoModule/jwplayer/eventsUI.html index 78d72a6153d..cfd1efe7624 100644 --- a/integrationExamples/videoModule/jwplayer/eventsUI.html +++ b/integrationExamples/videoModule/jwplayer/eventsUI.html @@ -22,6 +22,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html index 018c8eba8b2..1f4331785ea 100644 --- a/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html +++ b/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html @@ -19,6 +19,13 @@ divId: 'player', // required to indicate which player is being used to render this ad unit. }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/mediaMetadata.html b/integrationExamples/videoModule/jwplayer/mediaMetadata.html index 7581af571d3..63e62aa4b82 100644 --- a/integrationExamples/videoModule/jwplayer/mediaMetadata.html +++ b/integrationExamples/videoModule/jwplayer/mediaMetadata.html @@ -20,6 +20,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/jwplayer/playlist.html b/integrationExamples/videoModule/jwplayer/playlist.html index 89efaea3d5c..9e89f606f23 100644 --- a/integrationExamples/videoModule/jwplayer/playlist.html +++ b/integrationExamples/videoModule/jwplayer/playlist.html @@ -20,6 +20,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html index d6656bc0c93..35745ab281f 100644 --- a/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html +++ b/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html @@ -35,6 +35,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/bidRequestScheduling.html b/integrationExamples/videoModule/videojs/bidRequestScheduling.html index eb10fda89a2..da6499ca4cc 100644 --- a/integrationExamples/videoModule/videojs/bidRequestScheduling.html +++ b/integrationExamples/videoModule/videojs/bidRequestScheduling.html @@ -37,6 +37,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/bidsBackHandlerOverride.html b/integrationExamples/videoModule/videojs/bidsBackHandlerOverride.html index ac8f4163e76..74217ecee2c 100644 --- a/integrationExamples/videoModule/videojs/bidsBackHandlerOverride.html +++ b/integrationExamples/videoModule/videojs/bidsBackHandlerOverride.html @@ -34,6 +34,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/eventListeners.html b/integrationExamples/videoModule/videojs/eventListeners.html index 1966f134e02..3fc2ef7137c 100644 --- a/integrationExamples/videoModule/videojs/eventListeners.html +++ b/integrationExamples/videoModule/videojs/eventListeners.html @@ -35,6 +35,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/eventsUI.html b/integrationExamples/videoModule/videojs/eventsUI.html index 9eba09f7a52..215b2de4d25 100644 --- a/integrationExamples/videoModule/videojs/eventsUI.html +++ b/integrationExamples/videoModule/videojs/eventsUI.html @@ -37,6 +37,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/gamAdServerMediation.html b/integrationExamples/videoModule/videojs/gamAdServerMediation.html index 6ffc1a67c03..d6603abbf8f 100644 --- a/integrationExamples/videoModule/videojs/gamAdServerMediation.html +++ b/integrationExamples/videoModule/videojs/gamAdServerMediation.html @@ -34,6 +34,13 @@ divId: 'player', // required to indicate which player is being used to render this ad unit. }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/mediaMetadata.html b/integrationExamples/videoModule/videojs/mediaMetadata.html index ede076fd814..084c597cddd 100644 --- a/integrationExamples/videoModule/videojs/mediaMetadata.html +++ b/integrationExamples/videoModule/videojs/mediaMetadata.html @@ -35,6 +35,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/integrationExamples/videoModule/videojs/playlist.html b/integrationExamples/videoModule/videojs/playlist.html index eb813f095f7..2563717df41 100644 --- a/integrationExamples/videoModule/videojs/playlist.html +++ b/integrationExamples/videoModule/videojs/playlist.html @@ -36,6 +36,13 @@ }, bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }, { bidder: 'ix', params: { siteId: '300', diff --git a/modules/jwplayerBidAdapter.js b/modules/jwplayerBidAdapter.js new file mode 100644 index 00000000000..151d08bf3a6 --- /dev/null +++ b/modules/jwplayerBidAdapter.js @@ -0,0 +1,412 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO } from '../src/mediaTypes.js'; +import { isArray, isFn, deepAccess, deepSetValue, getDNT, logError, logWarn } from '../src/utils.js'; +import { config } from '../src/config.js'; +import { hasPurpose1Consent } from '../src/utils/gpdr.js'; + +const BIDDER_CODE = 'jwplayer'; +const BASE_URL = 'https://vpb-server.jwplayer.com/'; +const AUCTION_URL = BASE_URL + 'openrtb2/auction'; +const USER_SYNC_URL = BASE_URL + 'setuid'; +const GVLID = 1046; +const SUPPORTED_AD_TYPES = [VIDEO]; + +const VIDEO_ORTB_PARAMS = [ + 'pos', + 'w', + 'h', + 'playbackend', + 'mimes', + 'minduration', + 'maxduration', + 'protocols', + 'startdelay', + 'placement', + 'plcmt', + 'skip', + 'skipafter', + 'minbitrate', + 'maxbitrate', + 'delivery', + 'playbackmethod', + 'api', + 'linearity' +]; + +function getBidAdapter() { + function isBidRequestValid(bid) { + const params = bid && bid.params; + if (!params) { + return false; + } + + return !!params.placementId && !!params.publisherId && !!params.siteId; + } + + function buildRequests(bidRequests, bidderRequest) { + if (!bidRequests) { + return; + } + + if (!hasContentUrl(bidderRequest.ortb2)) { + logError(`${BIDDER_CODE}: cannot bid without a valid Content URL. Please populate ortb2.site.content.url`); + return; + } + + const warnings = getWarnings(bidderRequest); + warnings.forEach(warning => { + logWarn(`${BIDDER_CODE}: ${warning}`); + }); + + return bidRequests.map(bidRequest => { + const payload = buildRequest(bidRequest, bidderRequest); + + return { + method: 'POST', + url: AUCTION_URL, + data: payload + } + }); + } + + function interpretResponse(serverResponse) { + const outgoingBidResponses = []; + const serverResponseBody = serverResponse.body; + + logResponseWarnings(serverResponseBody); + + const seatBids = serverResponseBody && serverResponseBody.seatbid; + if (!isArray(seatBids)) { + return outgoingBidResponses; + } + + const cur = serverResponseBody.cur; + + seatBids.forEach(seatBid => { + seatBid.bid.forEach(bid => { + const bidResponse = { + requestId: serverResponseBody.id, + cpm: bid.price, + currency: cur, + width: bid.w, + height: bid.h, + ad: bid.adm, + vastXml: bid.adm, + ttl: bid.ttl || 3600, + netRevenue: false, + creativeId: bid.adid, + dealId: bid.dealid, + meta: { + advertiserDomains: bid.adomain, + mediaType: VIDEO, + primaryCatId: bid.cat, + } + }; + + outgoingBidResponses.push(bidResponse); + }); + }); + + return outgoingBidResponses; + } + + function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { + if (!hasPurpose1Consent(gdprConsent)) { + return []; + } + + const userSyncs = []; + const consentQueryParams = getUserSyncConsentQueryParams(gdprConsent); + const url = `https://ib.adnxs.com/getuid?${USER_SYNC_URL}?bidder=jwplayer&uid=$UID&f=i` + consentQueryParams + + if (syncOptions.iframeEnabled) { + userSyncs.push({ + type: 'iframe', + url + }); + } + + if (syncOptions.pixelEnabled) { + userSyncs.push({ + type: 'image', + url + }); + } + + return userSyncs; + } + + return { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: SUPPORTED_AD_TYPES, + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs + } + + function getUserSyncConsentQueryParams(gdprConsent) { + if (!gdprConsent) { + return ''; + } + + const consentString = gdprConsent.consentString; + if (!consentString) { + return ''; + } + + let gdpr = 0; + const gdprApplies = gdprConsent.gdprApplies; + if (typeof gdprApplies === 'boolean') { + gdpr = Number(gdprApplies) + } + + return `&gdpr=${gdpr}&gdpr_consent=${consentString}`; + } + + function buildRequest(bidRequest, bidderRequest) { + const openrtbRequest = { + id: bidRequest.bidId, + imp: getRequestImpressions(bidRequest, bidderRequest), + site: getRequestSite(bidRequest, bidderRequest), + device: getRequestDevice(bidderRequest.ortb2), + user: getRequestUser(bidderRequest.ortb2), + }; + + // GDPR Consent Params + if (bidderRequest.gdprConsent) { + deepSetValue(openrtbRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + deepSetValue(openrtbRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); + } + + // CCPA + if (bidderRequest.uspConsent) { + deepSetValue(openrtbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (bidRequest.schain) { + deepSetValue(openrtbRequest, 'source.schain', bidRequest.schain); + } + + openrtbRequest.tmax = bidderRequest.timeout || 200; + + return JSON.stringify(openrtbRequest); + } + + function getRequestImpressions(bidRequest) { + const impressionObject = { + id: bidRequest.adUnitCode, + }; + + impressionObject.video = getImpressionVideo(bidRequest); + + const bidFloorData = getBidFloorData(bidRequest); + if (bidFloorData) { + impressionObject.bidfloor = bidFloorData.floor; + impressionObject.bidfloorcur = bidFloorData.currency; + } + + impressionObject.ext = getImpressionExtension(bidRequest); + + return [impressionObject]; + } + + function getImpressionVideo(bidRequest) { + const videoParams = deepAccess(bidRequest, 'mediaTypes.video', {}); + + const video = {}; + + VIDEO_ORTB_PARAMS.forEach((param) => { + if (videoParams.hasOwnProperty(param)) { + video[param] = videoParams[param]; + } + }); + + setPlayerSize(video, videoParams); + + if (!videoParams.plcmt) { + logWarn(`${BIDDER_CODE}: Please set a value to mediaTypes.video.plcmt`); + } + + return video; + } + + function getImpressionExtension(bidRequest) { + return { + prebid: { + bidder: { + jwplayer: { + placementId: bidRequest.params.placementId + } + } + } + }; + } + + function setPlayerSize(videoImp, videoParams) { + if (videoImp.w !== undefined && videoImp.h !== undefined) { + return; + } + + const playerSize = getNormalizedPlayerSize(videoParams.playerSize); + if (!playerSize.length) { + logWarn(logWarn(`${BIDDER_CODE}: Video size has not been set. Please set values in video.h and video.w`)); + return; + } + + if (videoImp.w === undefined) { + videoImp.w = playerSize[0]; + } + + if (videoImp.h === undefined) { + videoImp.h = playerSize[1]; + } + } + + function getNormalizedPlayerSize(playerSize) { + if (!Array.isArray(playerSize)) { + return []; + } + + if (Array.isArray(playerSize[0])) { + playerSize = playerSize[0]; + } + + if (playerSize.length < 2) { + return []; + } + + return playerSize; + } + + function getBidFloorData(bidRequest) { + const { params } = bidRequest; + const currency = params.currency || 'USD'; + + let floorData; + if (isFn(bidRequest.getFloor)) { + const bidFloorRequest = { + currency: currency, + mediaType: VIDEO, + size: '*' + }; + floorData = bidRequest.getFloor(bidFloorRequest); + } else if (params.bidFloor) { + floorData = { floor: params.bidFloor, currency: currency }; + } + + return floorData; + } + + function getRequestSite(bidRequest, bidderRequest) { + const site = bidderRequest.ortb2.site || {}; + + site.domain = site.domain || config.publisherDomain || window.location.hostname; + site.page = site.page || config.pageUrl || window.location.href; + + const referer = bidderRequest.refererInfo && bidderRequest.refererInfo.referer; + if (!site.ref && referer) { + site.ref = referer; + } + + const jwplayerPublisherExtChain = 'publisher.ext.jwplayer.'; + + deepSetValue(site, jwplayerPublisherExtChain + 'publisherId', bidRequest.params.publisherId); + deepSetValue(site, jwplayerPublisherExtChain + 'siteId', bidRequest.params.siteId); + + return site; + } + + function getRequestDevice(ortb2) { + const device = Object.assign({ + h: screen.height, + w: screen.width, + ua: navigator.userAgent, + dnt: getDNT() ? 1 : 0, + js: 1 + }, ortb2.device || {}) + + const language = getLanguage(); + if (!device.language && language) { + device.language = language; + } + + return device; + } + + function getLanguage() { + const navigatorLanguage = navigator.language; + if (!navigatorLanguage) { + return; + } + + const languageCodeSegments = navigatorLanguage.split('-'); + if (!languageCodeSegments.length) { + return; + } + + return languageCodeSegments[0]; + } + + function getRequestUser(ortb2) { + const user = ortb2.user || {}; + if (config.getConfig('coppa') === true) { + user.coppa = true; + } + + return user; + } + + function hasContentUrl(ortb2) { + const site = ortb2.site; + const content = site && site.content; + return !!(content && content.url); + } + + function getWarnings(bidderRequest) { + const content = bidderRequest.ortb2.site.content; + const contentChain = 'ortb2.site.content.'; + const warnings = []; + if (!content.id) { + warnings.push(getMissingFieldMessage(contentChain + 'id')); + } + + if (!content.title) { + warnings.push(getMissingFieldMessage(contentChain + 'title')); + } + + if (!content.ext || !content.ext.description) { + warnings.push(getMissingFieldMessage(contentChain + 'ext.description')); + } + + return warnings; + } + + function getMissingFieldMessage(fieldName) { + return `Optional field ${fieldName} is not populated; we recommend populating for maximum performance.` + } + + function logResponseWarnings(serverResponseBody) { + const warningPayload = deepAccess(serverResponseBody, 'ext.warnings'); + if (!warningPayload) { + return; + } + + const warningCategories = Object.keys(warningPayload); + warningCategories.forEach(category => { + const warnings = warningPayload[category]; + if (!isArray(warnings)) { + return; + } + + warnings.forEach(warning => { + logWarn(`${BIDDER_CODE}: [Bid Response][Warning Code: ${warning.code}] ${warning.message}`); + }); + }); + } +} + +export const spec = getBidAdapter(); + +registerBidder(spec); diff --git a/modules/jwplayerBidAdapter.md b/modules/jwplayerBidAdapter.md new file mode 100644 index 00000000000..620f8657e50 --- /dev/null +++ b/modules/jwplayerBidAdapter.md @@ -0,0 +1,72 @@ +# Overview + +``` +Module Name: JWPlayer Bid Adapter +Module Type: Bidder Adapter +Maintainer: boost-engineering@jwplayer.com +``` + +# Description + +Connects to JWPlayer's demand sources. + +JWPlayer bid adapter supports Video (instream and outstream). + +# Sample Ad Unit + +```markdown +const adUnit = { + code: 'test-ad-unit', + mediaTypes: { + video: { + pos: 0, + w: 640, + h: 480, + mimes : ['video/x-ms-wmv', 'video/mp4'], + minduration : 0, + maxduration: 60, + protocols : [2,3,7,5,6,8], + startdelay: 0, + placement: 1, + plcmt: 1, + skip: 1, + skipafter: 10, + playbackmethod: [3], + api: [2], + linearity: 1 + } + }, + bids: [{ + bidder: 'jwplayer', + params: { + publisherId: 'test-publisher-id', + siteId: 'test-site-id', + placementId: 'test-placement-id' + } + }] +}; +``` + +# Sample ortb2 config + +```markdown +pbjs.setConfig({ + ortb2: { + site: { + publisher: { + id: 'test-publisher-id' + }, + content: { + id: 'test-media-id', + url: 'test.mp4', + title: 'title of my media', + ext: { + description: 'description of my media' + } + }, + domain: 'test-domain.com', + page: 'https://www.test-domain.com/test.html', + } + } +} +``` diff --git a/test/spec/modules/jwplayerBidAdapter_spec.js b/test/spec/modules/jwplayerBidAdapter_spec.js new file mode 100644 index 00000000000..e19790a9670 --- /dev/null +++ b/test/spec/modules/jwplayerBidAdapter_spec.js @@ -0,0 +1,412 @@ +import { expect, assert } from 'chai'; +import { spec } from 'modules/jwplayerBidAdapter.js'; + +describe('jwplayerBidAdapter', function() { + beforeEach(function() { + this.defaultBidderRequest = { + gdprConsent: { + consentString: 'testConsentString', + gdprApplies: true + }, + uspConsent: 'testCCPA', + refererInfo: { + referer: 'https://example.com' + }, + ortb2: { + site: { + domain: 'page.example.com', + page: 'https://examplepage.com', + content: { + url: 'media.mp4', + id: 'testMediaId', + title: 'testTile', + data: [{ + name: 'jwplayer.com', + segment: [{ + id: '00000000' + }, { + id: '88888888' + }, { + id: '80808080' + }], + ext: { + segtax: 502, + cids: ['testMediaId', 'externalTestId'], + } + }], + ext: { + description: 'testDescription' + } + } + } + }, + timeout: 1000 + } + }); + + it('should use jwplayer bidder code', function () { + expect(spec.code).to.equal('jwplayer'); + }); + + it('should use jwplayer GVLID code', function () { + expect(spec.gvlid).to.equal(1046); + }); + + it('should support VIDEO media type only', function () { + expect(spec.supportedMediaTypes).to.have.length(1); + expect(spec.supportedMediaTypes[0]).to.equal('video'); + }); + + describe('isBidRequestValid', function() { + it('should be invalid when bidRequest is undefined', function() { + assert(spec.isBidRequestValid() === false); + }); + + it('should be invalid when bidRequest is null', function() { + assert(spec.isBidRequestValid(null) === false); + }); + + it('should be invalid when the bidRequest has no params', function() { + assert(spec.isBidRequestValid({}) === false); + }); + + it('should be invalid when the bid request only includes a publisher ID', function() { + assert(spec.isBidRequestValid({params: {publisherId: 'foo'}}) === false); + }); + + it('should be invalid when the bid request only includes a placement ID', function() { + assert(spec.isBidRequestValid({params: {placementId: 'foo'}}) === false); + }); + + it('should be invalid when the bid request only includes a site ID', function() { + assert(spec.isBidRequestValid({params: {siteId: 'foo'}}) === false); + }); + + it('should be valid when the bid includes a placement ID, a publisher ID and a site ID', function() { + assert(spec.isBidRequestValid({params: {placementId: 'foo', publisherId: 'bar', siteId: 'siteId '}}) === true); + }); + }); + + describe('buildRequests', function() { + it('should return undefined when bidRequests is undefined', function () { + expect(spec.buildRequests()).to.be.undefined; + }); + + it('should return undefined when bidRequests is null', function () { + expect(spec.buildRequests(null)).to.be.undefined; + }); + + it('should return undefined when ortb site.content.url is absent', function () { + const request = spec.buildRequests({}, { + ortb2: { + site: { + content: { + url: null, + } + } + } + }); + + expect(request).to.be.undefined; + }); + + it('should build a valid request when bid request is complete', function() { + const incomingBidRequests = [ + { + bidder: 'jwplayer', + params: { + placementId: 'testPlacementId', + publisherId: 'testPublisherId', + siteId: 'testSiteId', + bidFloor: 10, + currency: 'EUR', + }, + mediaTypes: { + video: { + pos: 3, + w: 640, + h: 480, + context: 'instream', + mimes: [ + 'video/mp4', + 'application/javascript' + ], + protocols: [2, 3, 5, 6], + maxduration: 60, + minduration: 3, + startdelay: 0, + linearity: 1, + placement: 1, + plcmt: 1, + skip: 1, + skipafter: 4, + minbitrate: 500, + maxbitrate: 1000, + api: [2], + delivery: [2], + playbackmethod: [1], + playbackend: 2 + } + }, + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'publisher.com', + sid: '00001', + hp: 1 + } + ] + }, + bidRequestsCount: 1, + adUnitCode: 'testAdUnitCode', + bidId: 'testBidId' + } + ]; + + const outgoingBidRequests = spec.buildRequests(incomingBidRequests, this.defaultBidderRequest); + + outgoingBidRequests.forEach(serverRequest => { + expect(serverRequest.url).to.equal('https://vpb-server.jwplayer.com/openrtb2/auction'); + expect(serverRequest.method).to.equal('POST'); + + const openrtbRequest = JSON.parse(serverRequest.data); + + expect(openrtbRequest.id).to.equal('testBidId'); + + expect(openrtbRequest.imp[0].id).to.equal('testAdUnitCode'); + expect(openrtbRequest.imp[0].video.w).to.equal(640); + expect(openrtbRequest.imp[0].video.h).to.equal(480); + expect(openrtbRequest.imp[0].video.mimes).to.deep.equal(['video/mp4', 'application/javascript']); + expect(openrtbRequest.imp[0].video.protocols).to.deep.equal([2, 3, 5, 6]); + expect(openrtbRequest.imp[0].video.api).to.deep.equal([2]); + expect(openrtbRequest.imp[0].video.startdelay).to.equal(0); + expect(openrtbRequest.imp[0].video.placement).to.equal(1); + expect(openrtbRequest.imp[0].video.plcmt).to.equal(1); + expect(openrtbRequest.imp[0].video.pos).to.equal(3); + expect(openrtbRequest.imp[0].video.minduration).to.equal(3); + expect(openrtbRequest.imp[0].video.maxduration).to.equal(60); + expect(openrtbRequest.imp[0].video.skip).to.equal(1); + expect(openrtbRequest.imp[0].video.skipafter).to.equal(4); + expect(openrtbRequest.imp[0].video.minbitrate).to.equal(500); + expect(openrtbRequest.imp[0].video.maxbitrate).to.equal(1000); + expect(openrtbRequest.imp[0].video.delivery).to.deep.equal([2]); + expect(openrtbRequest.imp[0].video.playbackmethod).to.deep.equal([1]); + expect(openrtbRequest.imp[0].video.playbackend).to.equal(2); + expect(openrtbRequest.imp[0].video.linearity).to.equal(1); + + expect(openrtbRequest.imp[0].bidfloor).to.equal(10); + expect(openrtbRequest.imp[0].bidfloorcur).to.equal('EUR'); + + expect(openrtbRequest.imp[0].ext.prebid.bidder.jwplayer.placementId).to.equal('testPlacementId'); + + expect(openrtbRequest.site.domain).to.equal('page.example.com'); + expect(openrtbRequest.site.page).to.equal('https://examplepage.com'); + expect(openrtbRequest.site.ref).to.equal('https://example.com'); + + expect(openrtbRequest.site.publisher.ext.jwplayer.publisherId).to.equal('testPublisherId'); + expect(openrtbRequest.site.publisher.ext.jwplayer.siteId).to.equal('testSiteId'); + + expect(openrtbRequest.site.content.url).to.equal('media.mp4'); + expect(openrtbRequest.site.content.id).to.equal('testMediaId'); + expect(openrtbRequest.site.content.title).to.equal('testTile'); + expect(openrtbRequest.site.content.ext.description).to.equal('testDescription'); + expect(openrtbRequest.site.content.data.length).to.equal(1); + const datum = openrtbRequest.site.content.data[0]; + expect(datum.name).to.equal('jwplayer.com'); + expect(datum.segment).to.deep.equal([{ + id: '00000000' + }, { + id: '88888888' + }, { + id: '80808080' + }]); + expect(datum.ext.segtax).to.equal(502); + expect(datum.ext.cids).to.deep.equal(['testMediaId', 'externalTestId']); + + expect(openrtbRequest.device.ua).to.equal(navigator.userAgent); + expect(openrtbRequest.device.w).to.not.be.undefined; + expect(openrtbRequest.device.h).to.not.be.undefined; + expect(openrtbRequest.device.dnt).to.not.be.undefined; + expect(openrtbRequest.device.js).to.equal(1); + expect(openrtbRequest.device.language).to.not.be.undefined; + + expect(openrtbRequest.user.ext.consent).to.equal('testConsentString'); + + expect(openrtbRequest.regs.ext.gdpr).to.equal(1); + expect(openrtbRequest.regs.ext.us_privacy).to.equal('testCCPA'); + + expect(openrtbRequest.source.schain).to.deep.equal({ + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'publisher.com', + sid: '00001', + hp: 1 + } + ] + }); + + expect(openrtbRequest.tmax).to.equal(1000); + }); + }); + }); + + describe('interpretResponse', function() { + const serverResponse = { + body: { + id: 'test-request-id', + cur: 'USD', + seatbid: [{ + bid: [{ + id: 'testId', + impid: 'test-imp-id', + price: 5.000, + adid: 'test-creative-id', + adm: 'test-ad-xml', + adomain: ['prebid.com'], + cat: ['test-iab-category'], + w: 200, + h: 150, + dealid: 'test-deal-id' + }], + seat: 1000 + }] + } + }; + + const bidResponses = spec.interpretResponse(serverResponse); + + expect(bidResponses).to.have.length(1); + const bid = bidResponses[0]; + expect(bid.requestId).to.equal('test-request-id'); + expect(bid.cpm).to.equal(5); + expect(bid.currency).to.equal('USD'); + expect(bid.width).to.equal(200); + expect(bid.height).to.equal(150); + expect(bid.creativeId).to.equal('test-creative-id'); + expect(bid.vastXml).to.equal('test-ad-xml'); + expect(bid.netRevenue).to.equal(false); + expect(bid.ttl).to.equal(3600); + expect(bid.ad).to.equal('test-ad-xml'); + expect(bid.dealId).to.equal('test-deal-id'); + + expect(bid.meta).to.not.be.undefined; + + expect(bid.meta.advertiserDomains).to.have.length(1); + expect(bid.meta.advertiserDomains[0]).to.equal('prebid.com'); + + expect(bid.meta.mediaType).to.equal('video'); + + expect(bid.meta.primaryCatId).to.have.length(1); + expect(bid.meta.primaryCatId[0]).to.equal('test-iab-category'); + }); + + describe('getUserSyncs', function() { + const consentString = 'test_consent_string'; + const baseGdprConsent = { + gdprApplies: true, + vendorData: { + purpose: { + consents: { + 1: true + } + } + } + }; + + const expectedBaseUrl = 'https://ib.adnxs.com/getuid?https://vpb-server.jwplayer.com/setuid?bidder=jwplayer&uid=$UID&f=i'; + + it('should return empty when Purpose 1 consent is not granted', function() { + expect(spec.getUserSyncs({}, {})).to.be.empty; + expect(spec.getUserSyncs({}, {}, {})).to.be.empty; + expect(spec.getUserSyncs({}, {}, { gdprApplies: false })).to.be.empty; + expect(spec.getUserSyncs({}, {}, { + gdprApplies: true, + vendorData: { + purpose: { + consents: { + 1: false + } + } + } + })).to.be.empty; + }); + + it('should return iframe when enabled', function () { + const userSyncs = spec.getUserSyncs({ iframeEnabled: true }, {}, baseGdprConsent); + expect(userSyncs.length).to.equal(1); + const sync = userSyncs[0]; + expect(sync.type).to.equal('iframe'); + expect(sync.url).to.equal(expectedBaseUrl); + }); + + it('should return image when enabled', function () { + const userSyncs = spec.getUserSyncs({ pixelEnabled: true }, {}, baseGdprConsent); + expect(userSyncs.length).to.equal(1); + const sync = userSyncs[0]; + expect(sync.type).to.equal('image'); + expect(sync.url).to.equal(expectedBaseUrl); + }); + + it('should return both iframe and image when enabled', function () { + const userSyncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, {}, baseGdprConsent); + expect(userSyncs.length).to.equal(2); + + const iframeSync = userSyncs[0]; + expect(iframeSync.type).to.equal('iframe'); + expect(iframeSync.url).to.equal(expectedBaseUrl); + + const imageSync = userSyncs[1]; + expect(imageSync.type).to.equal('image'); + expect(imageSync.url).to.equal(expectedBaseUrl); + }); + + it('should include gdpr consent query params in sync redirect url', function () { + const expectedUrl = expectedBaseUrl + '&gdpr=1&gdpr_consent=' + consentString; + const gdprConsent = Object.assign({ }, baseGdprConsent, { consentString }); + const userSyncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, {}, gdprConsent); + expect(userSyncs.length).to.equal(2); + + const iframeSync = userSyncs[0]; + expect(iframeSync.type).to.equal('iframe'); + expect(iframeSync.url).to.equal(expectedUrl); + + const imageSync = userSyncs[1]; + expect(imageSync.type).to.equal('image'); + expect(imageSync.url).to.equal(expectedUrl); + }); + + it('should include gdpr 0 in consent query params when gdprApplies is false', function () { + const expectedUrl = expectedBaseUrl + '&gdpr=0&gdpr_consent=' + consentString; + const gdprConsent = Object.assign({ }, baseGdprConsent, { consentString, gdprApplies: false }); + const userSyncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, {}, gdprConsent); + expect(userSyncs.length).to.equal(2); + + const iframeSync = userSyncs[0]; + expect(iframeSync.type).to.equal('iframe'); + expect(iframeSync.url).to.equal(expectedUrl); + + const imageSync = userSyncs[1]; + expect(imageSync.type).to.equal('image'); + expect(imageSync.url).to.equal(expectedUrl); + }); + + it('should include gdpr 0 in consent query params when gdprApplies is not a bool', function () { + const expectedUrl = expectedBaseUrl + '&gdpr=0&gdpr_consent=' + consentString; + const gdprConsent = Object.assign({ }, baseGdprConsent, { consentString, gdprApplies: 1 }); + const userSyncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, {}, gdprConsent); + expect(userSyncs.length).to.equal(2); + + const iframeSync = userSyncs[0]; + expect(iframeSync.type).to.equal('iframe'); + expect(iframeSync.url).to.equal(expectedUrl); + + const imageSync = userSyncs[1]; + expect(imageSync.type).to.equal('image'); + expect(imageSync.url).to.equal(expectedUrl); + }); + }); +}); From 51bcf81bc6212de26290168a789c6db16d53af90 Mon Sep 17 00:00:00 2001 From: kalidas-alkimi <92875788+kalidas-alkimi@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:54:20 +0100 Subject: [PATCH 054/147] Alkimi Bid Adapter : add handling for user-sync URL and pass custom object with bid request (#11326) * Alkimi bid adapter * Alkimi bid adapter * Alkimi bid adapter * alkimi adapter * onBidWon change * sign utils * auction ID as bid request ID * unit test fixes * change maintainer info * Updated the ad unit params * features support added * transfer adUnitCode * transfer adUnitCode: test * AlkimiBidAdapter getFloor() using * ALK-504 Multi size ad slot support * ALK-504 Multi size ad slot support * Support new OpenRTB parameters * Support new oRTB2 parameters * remove pos parameter * Add gvl_id into Alkimi adapter * Insert keywords into bid-request param * Resolve AUCTION_PRICE macro on prebid-server for VAST ads * Added support for full page auction * Added custom user object * userParams in request object * Handling user-sync url, store user id and passing custom params * Renamed the full_page_auction to fpa * Updated the review comment --------- Co-authored-by: Alexander <32703851+pro-nsk@users.noreply.github.com> Co-authored-by: Alexander Bogdanov Co-authored-by: Alexander Bogdanov Co-authored-by: motors Co-authored-by: mihanikw2g <92710748+mihanikw2g@users.noreply.github.com> Co-authored-by: Nikulin Mikhail Co-authored-by: mik --- modules/alkimiBidAdapter.js | 56 ++++++++++++++++++---- test/spec/modules/alkimiBidAdapter_spec.js | 16 +++++-- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/modules/alkimiBidAdapter.js b/modules/alkimiBidAdapter.js index d4e7cab8ed1..3bd995cc112 100644 --- a/modules/alkimiBidAdapter.js +++ b/modules/alkimiBidAdapter.js @@ -1,12 +1,15 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {deepAccess, deepClone, getDNT, generateUUID, replaceAuctionPrice} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; +import {getStorageManager} from '../src/storageManager.js'; import {VIDEO, BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; const BIDDER_CODE = 'alkimi'; const GVLID = 1169; +const USER_ID_KEY = 'alkimiUserID'; export const ENDPOINT = 'https://exchange.alkimi-onboarding.com/bid?prebid=true'; +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export const spec = { code: BIDDER_CODE, @@ -43,11 +46,16 @@ export const spec = { bidIds.push(bidRequest.bidId) }) + const ortb2 = bidderRequest.ortb2 + const site = ortb2?.site + + const id = getUserId() const alkimiConfig = config.getConfig('alkimi') - const fullPageAuction = bidderRequest.ortb2?.source?.ext?.full_page_auction - const source = fullPageAuction != undefined ? { ext: { full_page_auction: fullPageAuction } } : undefined + const fpa = ortb2?.source?.ext?.fpa + const source = fpa != undefined ? { ext: { fpa } } : undefined const walletID = alkimiConfig && alkimiConfig.walletID - const user = walletID != undefined ? { ext: { walletID: walletID } } : undefined + const userParams = alkimiConfig && alkimiConfig.userParams + const user = (walletID != undefined || userParams != undefined || id != undefined) ? { id, ext: { walletID, userParams } } : undefined let payload = { requestId: generateUUID(), @@ -66,11 +74,14 @@ export const spec = { source, user, site: { - keywords: bidderRequest.ortb2?.site?.keywords + keywords: site?.keywords, + sectioncat: site?.sectioncat, + pagecat: site?.pagecat, + cat: site?.cat }, - at: bidderRequest.ortb2?.at, - bcat: bidderRequest.ortb2?.bcat, - wseat: bidderRequest.ortb2?.wseat + at: ortb2?.at, + bcat: ortb2?.bcat, + wseat: ortb2?.wseat } } @@ -111,7 +122,7 @@ export const spec = { } const {prebidResponse} = serverBody; - if (!prebidResponse || typeof prebidResponse !== 'object') { + if (!Array.isArray(prebidResponse)) { return []; } @@ -141,6 +152,24 @@ export const spec = { return true; } return false; + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { + if (syncOptions.iframeEnabled && serverResponses.length > 0) { + const serverBody = serverResponses[0].body; + if (!serverBody || typeof serverBody !== 'object') return []; + + const { iframeList } = serverBody; + if (!Array.isArray(iframeList)) return []; + + const urls = []; + iframeList.forEach(url => { + urls.push({type: 'iframe', url}); + }) + + return urls; + } + return []; } } @@ -175,4 +204,15 @@ const getFormatType = bidRequest => { return formats } +const getUserId = () => { + if (storage.localStorageIsEnabled()) { + let userId = storage.getDataFromLocalStorage(USER_ID_KEY) + if (!userId) { + userId = generateUUID() + storage.setDataInLocalStorage(USER_ID_KEY, userId) + } + return userId + } +} + registerBidder(spec); diff --git a/test/spec/modules/alkimiBidAdapter_spec.js b/test/spec/modules/alkimiBidAdapter_spec.js index 90a9e409e69..e551d98fa07 100644 --- a/test/spec/modules/alkimiBidAdapter_spec.js +++ b/test/spec/modules/alkimiBidAdapter_spec.js @@ -91,11 +91,11 @@ describe('alkimiBidAdapter', function () { }) it('should return false when required params are not passed', function () { - let bid = Object.assign({}, REQUEST) + let bid = JSON.parse(JSON.stringify(REQUEST)) delete bid.params.token expect(spec.isBidRequestValid(bid)).to.equal(false) - bid = Object.assign({}, REQUEST) + bid = JSON.parse(JSON.stringify(REQUEST)) delete bid.params expect(spec.isBidRequestValid(bid)).to.equal(false) }) @@ -115,29 +115,35 @@ describe('alkimiBidAdapter', function () { uspConsent: 'uspConsent', ortb2: { site: { - keywords: 'test1, test2' + keywords: 'test1, test2', + cat: ['IAB2'], + pagecat: ['IAB3'], + sectioncat: ['IAB4'] }, at: 2, bcat: ['BSW1', 'BSW2'], wseat: ['16', '165'] } } - const bidderRequest = spec.buildRequests(bidRequests, requestData) it('should return a properly formatted request with eids defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.eids).to.deep.equal(REQUEST.userIdAsEids) }) it('should return a properly formatted request with gdpr defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.gdprConsent.consentRequired).to.equal(true) expect(bidderRequest.data.gdprConsent.consentString).to.equal('test-consent') }) it('should return a properly formatted request with uspConsent defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.uspConsent).to.equal('uspConsent') }) it('sends bid request to ENDPOINT via POST', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.method).to.equal('POST') expect(bidderRequest.data.requestId).to.not.equal(undefined) expect(bidderRequest.data.referer).to.equal('http://test.com/path.html') @@ -146,7 +152,7 @@ describe('alkimiBidAdapter', function () { expect(bidderRequest.data.signRequest.randomUUID).to.equal(undefined) expect(bidderRequest.data.bidIds).to.deep.contains('456') expect(bidderRequest.data.signature).to.equal(undefined) - expect(bidderRequest.data.ortb2).to.deep.contains({ at: 2, wseat: ['16', '165'], bcat: ['BSW1', 'BSW2'], site: { keywords: 'test1, test2' }, }) + expect(bidderRequest.data.ortb2).to.deep.contains({ at: 2, wseat: ['16', '165'], bcat: ['BSW1', 'BSW2'], site: { keywords: 'test1, test2', cat: ['IAB2'], pagecat: ['IAB3'], sectioncat: ['IAB4'] } }) expect(bidderRequest.options.customHeaders).to.deep.equal({ 'Rtb-Direct': true }) expect(bidderRequest.options.contentType).to.equal('application/json') expect(bidderRequest.url).to.equal(ENDPOINT) From 0fd106dea29b7cf70be35136c5e567782166cc8c Mon Sep 17 00:00:00 2001 From: skapoorViant <153030693+skapoorViant@users.noreply.github.com> Date: Thu, 25 Apr 2024 09:55:42 -0700 Subject: [PATCH 055/147] Called replaceAuctionMacro in viantOrtbBidAdapter to replace Auction_Price (#11394) * Called replaceAuctionMacro in viantOrtbBidAdapter to replace Auction_Price macro * Fixed changes --- modules/viantOrtbBidAdapter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/viantOrtbBidAdapter.js b/modules/viantOrtbBidAdapter.js index 0f7953a192a..ee4cbe2d904 100644 --- a/modules/viantOrtbBidAdapter.js +++ b/modules/viantOrtbBidAdapter.js @@ -51,8 +51,10 @@ export const spec = { onBidWon: function (bid) { if (bid.burl) { utils.triggerPixel(bid.burl); + utils.replaceAuctionPrice(bid.burl, bid.price); } else if (bid.nurl) { utils.triggerPixel(bid.nurl); + utils.replaceAuctionPrice(bid.nurl, bid.price); } } } From 49c0d87c2cab1a5ca8a0f2f7f75865c04e77d0b9 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 25 Apr 2024 17:43:48 +0000 Subject: [PATCH 056/147] Prebid 8.46.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47383455eaa..5a9f282690f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.46.0-pre", + "version": "8.46.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 2b4d9dd68c1..cd16cf746b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.46.0-pre", + "version": "8.46.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 546595f04f41bdebcec84bb96681ef1cff318a6c Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 25 Apr 2024 17:43:48 +0000 Subject: [PATCH 057/147] Increment version to 8.47.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a9f282690f..6c9bddfaf06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.46.0", + "version": "8.47.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index cd16cf746b6..7236e62b5d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.46.0", + "version": "8.47.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From cbbd524a65817fa58a6377b4d39e3f7dd3a6d055 Mon Sep 17 00:00:00 2001 From: skapoorViant <153030693+skapoorViant@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:32:03 -0700 Subject: [PATCH 058/147] ViantOrtb Bid Adapter : called replaceAuctionMacro to replace Auction_Price (#11398) * Called replaceAuctionMacro in viantOrtbBidAdapter to replace Auction_Price * fixed changes --- modules/viantOrtbBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/viantOrtbBidAdapter.js b/modules/viantOrtbBidAdapter.js index ee4cbe2d904..d056dfeb2eb 100644 --- a/modules/viantOrtbBidAdapter.js +++ b/modules/viantOrtbBidAdapter.js @@ -51,10 +51,10 @@ export const spec = { onBidWon: function (bid) { if (bid.burl) { utils.triggerPixel(bid.burl); - utils.replaceAuctionPrice(bid.burl, bid.price); + utils.triggerPixel(utils.replaceAuctionPrice(bid.burl, bid.originalCpm || bid.cpm)); } else if (bid.nurl) { utils.triggerPixel(bid.nurl); - utils.replaceAuctionPrice(bid.nurl, bid.price); + utils.triggerPixel(utils.replaceAuctionPrice(bid.nurl, bid.originalCpm || bid.cpm)); } } } From b557f048770d64371674f08dca21fe3cd8fcc7b3 Mon Sep 17 00:00:00 2001 From: jdelhommeau Date: Thu, 25 Apr 2024 22:57:51 +0200 Subject: [PATCH 059/147] UtiqMtpIdSystem: create the Utiq MTP ID submodule (#11372) * Creating new user ID module utiqMtpIdSystem to provide option for publishers using Utiq to send the martechPass. This is complementary to the UtiqIDSystem module * fixing documentation to reflect correct name utiqMtp instead of utiq-mtp * fixing inline doc and creating unit test for utiqMtpIdSystem * Adding extra documentation to notify publishers to contact Utiq in order to integrate the Utiq script on their site --------- Co-authored-by: root Co-authored-by: jdelhommeau --- modules/.submodules.json | 1 + modules/utiqMtpIdSystem.js | 138 ++++++++++++++++ modules/utiqMtpIdSystem.md | 22 +++ test/spec/modules/utiqMtpIdSystem_spec.js | 188 ++++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 modules/utiqMtpIdSystem.js create mode 100644 modules/utiqMtpIdSystem.md create mode 100644 test/spec/modules/utiqMtpIdSystem_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index cfa98b5ab32..3913f3f5734 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -39,6 +39,7 @@ "teadsIdSystem", "tncIdSystem", "utiqSystem", + "utiqMtpIdSystem", "uid2IdSystem", "euidIdSystem", "unifiedIdSystem", diff --git a/modules/utiqMtpIdSystem.js b/modules/utiqMtpIdSystem.js new file mode 100644 index 00000000000..c5d25f27ca5 --- /dev/null +++ b/modules/utiqMtpIdSystem.js @@ -0,0 +1,138 @@ +/** + * This module adds Utiq MTP provided by Utiq SA/NV to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/utiqMtpIdSystem + * @requires module:modules/userId + */ +import { logInfo } from '../src/utils.js'; +import { submodule } from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; + +const MODULE_NAME = 'utiqMtpId'; +const LOG_PREFIX = 'Utiq MTP module'; + +export const storage = getStorageManager({ + moduleType: MODULE_TYPE_UID, + moduleName: MODULE_NAME, +}); + +/** + * Get the "mtid" from html5 local storage to make it available to the UserId module. + * @param config + * @returns {{utiqMtp: (*|string)}} + */ +function getUtiqFromStorage() { + let utiqPass; + let utiqPassStorage = JSON.parse( + storage.getDataFromLocalStorage('utiqPass') + ); + logInfo( + `${LOG_PREFIX}: Local storage utiqPass: ${JSON.stringify( + utiqPassStorage + )}` + ); + + if ( + utiqPassStorage && + utiqPassStorage.connectId && + Array.isArray(utiqPassStorage.connectId.idGraph) && + utiqPassStorage.connectId.idGraph.length > 0 + ) { + utiqPass = utiqPassStorage.connectId.idGraph[0]; + } + logInfo( + `${LOG_PREFIX}: Graph of utiqPass: ${JSON.stringify( + utiqPass + )}` + ); + + return { + utiqMtp: + utiqPass && utiqPass.mtid + ? utiqPass.mtid + : null, + }; +} + +/** @type {Submodule} */ +export const utiqMtpIdSubmodule = { + /** + * Used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + /** + * Decodes the stored id value for passing to bid requests. + * @function + * @returns {{utiqMtp: string} | null} + */ + decode(bidId) { + logInfo(`${LOG_PREFIX}: Decoded ID value ${JSON.stringify(bidId)}`); + return bidId.utiqMtp ? bidId : null; + }, + /** + * Get the id from helper function and initiate a new user sync. + * @param config + * @returns {{callback: result}|{id: {utiqMtp: string}}} + */ + getId: function (config) { + const data = getUtiqFromStorage(); + if (data.utiqMtp) { + logInfo(`${LOG_PREFIX}: Local storage ID value ${JSON.stringify(data)}`); + return { id: { utiqMtp: data.utiqMtp } }; + } else { + if (!config) { + config = {}; + } + if (!config.params) { + config.params = {}; + } + if ( + typeof config.params.maxDelayTime === 'undefined' || + config.params.maxDelayTime === null + ) { + config.params.maxDelayTime = 1000; + } + // Current delay and delay step in milliseconds + let currentDelay = 0; + const delayStep = 50; + const result = (callback) => { + const data = getUtiqFromStorage(); + if (!data.utiqMtp) { + if (currentDelay > config.params.maxDelayTime) { + logInfo( + `${LOG_PREFIX}: No utiq value set after ${config.params.maxDelayTime} max allowed delay time` + ); + callback(null); + } else { + currentDelay += delayStep; + setTimeout(() => { + result(callback); + }, delayStep); + } + } else { + const dataToReturn = { utiqMtp: data.utiqMtp }; + logInfo( + `${LOG_PREFIX}: Returning ID value data of ${JSON.stringify( + dataToReturn + )}` + ); + callback(dataToReturn); + } + }; + return { callback: result }; + } + }, + eids: { + 'utiqMtp': { + source: 'utiq-mtp.com', + atype: 1, + getValue: function (data) { + return data; + }, + }, + } +}; + +submodule('userId', utiqMtpIdSubmodule); diff --git a/modules/utiqMtpIdSystem.md b/modules/utiqMtpIdSystem.md new file mode 100644 index 00000000000..9b738152969 --- /dev/null +++ b/modules/utiqMtpIdSystem.md @@ -0,0 +1,22 @@ +## Utiq User ID Submodule + +Utiq MTP ID Module. + +### Utiq installation ### + +In order to use utiq in your prebid setup, you must first integrate utiq solution on your website as per https://docs.utiq.com/ +If you are interested in using Utiq on your website, please contact Utiq on https://utiq.com/contact/ + +### Prebid integration ### + +First, make sure to add the utiq MTP submodule to your Prebid.js package with: + +``` +gulp build --modules=userId,adfBidAdapter,ixBidAdapter,prebidServerBidAdapter,utiqMtpIdSystem +``` + +## Parameter Descriptions + +| Params under userSync.userIds[] | Type | Description | Example | +| ------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------- | +| name | String | The name of the module | `"utiqMtpId"` | diff --git a/test/spec/modules/utiqMtpIdSystem_spec.js b/test/spec/modules/utiqMtpIdSystem_spec.js new file mode 100644 index 00000000000..0456d485875 --- /dev/null +++ b/test/spec/modules/utiqMtpIdSystem_spec.js @@ -0,0 +1,188 @@ +import { expect } from 'chai'; +import { utiqMtpIdSubmodule } from 'modules/utiqMtpIdSystem.js'; +import { storage } from 'modules/utiqMtpIdSystem.js'; + +describe('utiqMtpIdSystem', () => { + const utiqPassKey = 'utiqPass'; + + const getStorageData = (idGraph) => { + if (!idGraph) { + idGraph = {id: 501, domain: ''}; + } + return { + 'connectId': { + 'idGraph': [idGraph], + } + } + }; + + it('should have the correct module name declared', () => { + expect(utiqMtpIdSubmodule.name).to.equal('utiqMtpId'); + }); + + describe('utiqMtpId getId()', () => { + afterEach(() => { + storage.removeDataFromLocalStorage(utiqPassKey); + }); + + it('it should return object with key callback', () => { + expect(utiqMtpIdSubmodule.getId()).to.have.property('callback'); + }); + + it('should return object with key callback with value type - function', () => { + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData())); + expect(utiqMtpIdSubmodule.getId()).to.have.property('callback'); + expect(typeof utiqMtpIdSubmodule.getId().callback).to.be.equal('function'); + }); + + it('tests if localstorage & JSON works properly ', () => { + const idGraph = { + 'domain': 'domainValue', + 'mtid': 'mtidValue', + }; + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + expect(JSON.parse(storage.getDataFromLocalStorage(utiqPassKey))).to.have.property('connectId'); + }); + + it('returns {id: {utiq: data.utiq}} if we have the right data stored in the localstorage ', () => { + const idGraph = { + 'domain': 'test.domain', + 'mtid': 'mtidValue', + }; + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + const response = utiqMtpIdSubmodule.getId(); + expect(response).to.have.property('id'); + expect(response.id).to.have.property('utiqMtp'); + expect(response.id.utiqMtp).to.be.equal('mtidValue'); + }); + + it('returns {utiqMtp: data.utiqMtp} if we have the right data stored in the localstorage right after the callback is called', (done) => { + const idGraph = { + 'domain': 'test.domain', + 'mtid': 'mtidValue', + }; + const response = utiqMtpIdSubmodule.getId(); + expect(response).to.have.property('callback'); + expect(response.callback.toString()).contain('result(callback)'); + + if (typeof response.callback === 'function') { + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + response.callback(function (result) { + expect(result).to.not.be.null; + expect(result).to.have.property('utiqMtp'); + expect(result.utiqMtp).to.be.equal('mtidValue'); + done() + }) + } + }); + + it('returns {utiqMtp: data.utiqMtp} if we have the right data stored in the localstorage right after 500ms delay', (done) => { + const idGraph = { + 'domain': 'test.domain', + 'mtid': 'mtidValue', + }; + + const response = utiqMtpIdSubmodule.getId(); + expect(response).to.have.property('callback'); + expect(response.callback.toString()).contain('result(callback)'); + + if (typeof response.callback === 'function') { + setTimeout(() => { + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + }, 500); + response.callback(function (result) { + expect(result).to.not.be.null; + expect(result).to.have.property('utiqMtp'); + expect(result.utiqMtp).to.be.equal('mtidValue'); + done() + }) + } + }); + + it('returns null if we have the data stored in the localstorage after 500ms delay and the max (waiting) delay is only 200ms ', (done) => { + const idGraph = { + 'domain': 'test.domain', + 'mtid': 'mtidValue', + }; + + const response = utiqMtpIdSubmodule.getId({params: {maxDelayTime: 200}}); + expect(response).to.have.property('callback'); + expect(response.callback.toString()).contain('result(callback)'); + + if (typeof response.callback === 'function') { + setTimeout(() => { + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + }, 500); + response.callback(function (result) { + expect(result).to.be.null; + done() + }) + } + }); + }); + + describe('utiq decode()', () => { + const VALID_API_RESPONSES = [ + { + expected: '32a97f612', + payload: { + utiqMtp: '32a97f612' + } + }, + { + expected: '32a97f61', + payload: { + utiqMtp: '32a97f61', + } + }, + ]; + VALID_API_RESPONSES.forEach(responseData => { + it('should return a newly constructed object with the utiqMtp for a payload with {utiqMtp: value}', () => { + expect(utiqMtpIdSubmodule.decode(responseData.payload)).to.deep.equal( + {utiqMtp: responseData.expected} + ); + }); + }); + + [{}, '', {foo: 'bar'}].forEach((response) => { + it(`should return null for an invalid response "${JSON.stringify(response)}"`, () => { + expect(utiqMtpIdSubmodule.decode(response)).to.be.null; + }); + }); + }); + + describe('utiq messageHandler', () => { + afterEach(() => { + storage.removeDataFromLocalStorage(utiqPassKey); + }); + + const domains = [ + 'domain1', + 'domain2', + 'domain3', + ]; + + domains.forEach(domain => { + it(`correctly sets utiq value for domain name ${domain}`, (done) => { + const idGraph = { + 'domain': domain, + 'mtid': 'mtidValue', + }; + + storage.setDataInLocalStorage(utiqPassKey, JSON.stringify(getStorageData(idGraph))); + + const eventData = { + data: `{\"msgType\":\"MNOSELECTOR\",\"body\":{\"url\":\"https://${domain}/some/path\"}}` + }; + + window.dispatchEvent(new MessageEvent('message', eventData)); + + const response = utiqMtpIdSubmodule.getId(); + expect(response).to.have.property('id'); + expect(response.id).to.have.property('utiqMtp'); + expect(response.id.utiqMtp).to.be.equal('mtidValue'); + done(); + }); + }); + }); +}); From 2be3f2933f4cdc0de545f6ac67a0ce8db8def638 Mon Sep 17 00:00:00 2001 From: Pavlo Kyrylenko Date: Fri, 26 Apr 2024 14:51:21 +0300 Subject: [PATCH 060/147] Rename idWardRtdProvider to anonymisedRtdProvider (#10176) * rename idWardRtdProvider to anonymisedRtdProvider * ANON-4689: bidders param added. Support appnexus * updated readme file * updated readme description * pr review: restored idWardRtdProvider * Module renamed notification added * added Warning decoration * reverter needless changes * Renamed "ID Ward" mentions to "Anonymised" * 'bidders' param optional. Reusing shared code * corrected indentions * minor correction * clean up --------- Co-authored-by: Pavlo --- .../gpt/anonymised_segments_example.html | 112 +++++++++ modules/anonymisedRtdProvider.js | 122 ++++++++++ modules/anonymisedRtdProvider.md | 54 +++++ modules/idWardRtdProvider.js | 103 +-------- modules/idWardRtdProvider.md | 9 +- .../modules/anonymisedRtdProvider_spec.js | 214 ++++++++++++++++++ test/spec/modules/idWardRtdProvider_spec.js | 4 +- 7 files changed, 515 insertions(+), 103 deletions(-) create mode 100644 integrationExamples/gpt/anonymised_segments_example.html create mode 100644 modules/anonymisedRtdProvider.js create mode 100644 modules/anonymisedRtdProvider.md create mode 100644 test/spec/modules/anonymisedRtdProvider_spec.js diff --git a/integrationExamples/gpt/anonymised_segments_example.html b/integrationExamples/gpt/anonymised_segments_example.html new file mode 100644 index 00000000000..16f3f879636 --- /dev/null +++ b/integrationExamples/gpt/anonymised_segments_example.html @@ -0,0 +1,112 @@ + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+
First Party Data (ortb2) Sent to Bidding Adapter
+
+ + diff --git a/modules/anonymisedRtdProvider.js b/modules/anonymisedRtdProvider.js new file mode 100644 index 00000000000..48ac649f002 --- /dev/null +++ b/modules/anonymisedRtdProvider.js @@ -0,0 +1,122 @@ +/** + * This module adds the Anonymised RTD provider to the real time data module + * The {@link module:modules/realTimeData} module is required + * The module will populate real-time data from Anonymised + * @module modules/anonymisedRtdProvider + * @requires module:modules/realTimeData + */ +import {getStorageManager} from '../src/storageManager.js'; +import {submodule} from '../src/hook.js'; +import {isPlainObject, mergeDeep, logMessage, logError} from '../src/utils.js'; +import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; + +export function createRtdProvider(moduleName) { + const MODULE_NAME = 'realTimeData'; + const SUBMODULE_NAME = moduleName; + + const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME }); + /** + * Add real-time data & merge segments. + * @param ortb2 object to merge into + * @param {Object} rtd + */ + function addRealTimeData(ortb2, rtd) { + if (isPlainObject(rtd.ortb2)) { + logMessage(`${SUBMODULE_NAME}RtdProvider: merging original: `, ortb2); + logMessage(`${SUBMODULE_NAME}RtdProvider: merging in: `, rtd.ortb2); + mergeDeep(ortb2, rtd.ortb2); + } + } + /** + * Try parsing stringified array of segment IDs. + * @param {String} data + */ + function tryParse(data) { + try { + return JSON.parse(data); + } catch (err) { + logError(`${SUBMODULE_NAME}RtdProvider: failed to parse json:`, data); + return null; + } + } + /** + * Real-time data retrieval from Anonymised + * @param {Object} reqBidsConfigObj + * @param {function} onDone + * @param {Object} rtdConfig + * @param {Object} userConsent + */ + function getRealTimeData(reqBidsConfigObj, onDone, rtdConfig, userConsent) { + if (rtdConfig && isPlainObject(rtdConfig.params)) { + const cohortStorageKey = rtdConfig.params.cohortStorageKey; + const bidders = rtdConfig.params.bidders; + + if (cohortStorageKey !== 'cohort_ids') { + logError(`${SUBMODULE_NAME}RtdProvider: 'cohortStorageKey' should be 'cohort_ids'`) + return; + } + + const jsonData = storage.getDataFromLocalStorage(cohortStorageKey); + if (!jsonData) { + return; + } + + const segments = tryParse(jsonData); + + if (segments) { + const udSegment = { + name: 'anonymised.io', + ext: { + segtax: rtdConfig.params.segtax + }, + segment: segments.map(x => ({id: x})) + } + + logMessage(`${SUBMODULE_NAME}RtdProvider: user.data.segment: `, udSegment); + const data = { + rtd: { + ortb2: { + user: { + data: [ + udSegment + ] + } + } + } + }; + + if (bidders?.includes('appnexus')) { + data.rtd.ortb2.user.keywords = segments.map(x => `perid=${x}`).join(','); + } + + addRealTimeData(reqBidsConfigObj.ortb2Fragments?.global, data.rtd); + onDone(); + } + } + } + /** + * Module init + * @param {Object} provider + * @param {Object} userConsent + * @return {boolean} + */ + function init(provider, userConsent) { + return true; + } + /** @type {RtdSubmodule} */ + const rtdSubmodule = { + name: SUBMODULE_NAME, + getBidRequestData: getRealTimeData, + init: init + }; + + submodule(MODULE_NAME, rtdSubmodule); + + return { + getRealTimeData, + rtdSubmodule, + storage + }; +} + +export const { getRealTimeData, rtdSubmodule: anonymisedRtdSubmodule, storage } = createRtdProvider('anonymised'); diff --git a/modules/anonymisedRtdProvider.md b/modules/anonymisedRtdProvider.md new file mode 100644 index 00000000000..2ff2597690b --- /dev/null +++ b/modules/anonymisedRtdProvider.md @@ -0,0 +1,54 @@ +### Overview + +Anonymised is a data anonymization technology for privacy-preserving advertising. Publishers and advertisers are able to target and retarget custom audience segments covering 100% of consented audiences. +Anonymised’s Real-time Data Provider automatically obtains segment IDs from the Anonymised on-domain script (via localStorage) and passes them to the bid-stream. + +### Integration + + - Build the anonymisedRtd module into the Prebid.js package with: + + ```bash + gulp build --modules=anonymisedRtdProvider,... + ``` + + - Use `setConfig` to instruct Prebid.js to initilaize the anonymisedRtdProvider module, as specified below. + +### Configuration + +```javascript + pbjs.setConfig({ + realTimeData: { + dataProviders: [ + { + name: "anonymised", + waitForIt: true, + params: { + cohortStorageKey: "cohort_ids", + bidders: ["smartadserver", "appnexus"], + segtax: 1000 + } + } + ] + } + }); + ``` + + ### Config Syntax details +| Name |Type | Description | Notes | +| :------------ | :------------ | :------------ |:------------ | +| name | String | Anonymised Rtd module name | 'anonymised' always| +| waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false | +| params.cohortStorageKey | String | the `localStorage` key, under which Anonymised Marketing Tag stores the segment IDs | 'cohort_ids' always | +| params.bidders | Array | Bidders with which to share segment information | Optional | +| params.segtax | Integer | The taxonomy for Anonymised | '1000' always | + +Please note that anonymisedRtdProvider should be integrated into the publisher website along with the [Anonymised Marketing Tag](https://support.anonymised.io/integrate/marketing-tag). +Please reach out to Anonymised [representative](mailto:support@anonymised.io) if you have any questions or need further help to integrate Prebid, anonymisedRtdProvider, and Anonymised Marketing Tag + +### Testing +To view an example of available segments returned by Anonymised: +```bash +gulp serve --modules=rtdModule,anonymisedRtdProvider,pubmaticBidAdapter +``` +And then point your browser at: +"http://localhost:9999/integrationExamples/gpt/anonymised_segments_example.html" diff --git a/modules/idWardRtdProvider.js b/modules/idWardRtdProvider.js index dd08a132b2d..8e6e3c20a64 100644 --- a/modules/idWardRtdProvider.js +++ b/modules/idWardRtdProvider.js @@ -1,107 +1,10 @@ /** * This module adds the ID Ward RTD provider to the real time data module * The {@link module:modules/realTimeData} module is required - * The module will poulate real-time data from ID Ward + * The module will populate real-time data from ID Ward * @module modules/idWardRtdProvider * @requires module:modules/realTimeData */ -import {getStorageManager} from '../src/storageManager.js'; -import {submodule} from '../src/hook.js'; -import {isPlainObject, mergeDeep, logMessage, logError} from '../src/utils.js'; -import {MODULE_TYPE_RTD} from '../src/activities/modules.js'; -/** - * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule - */ - -const MODULE_NAME = 'realTimeData'; -const SUBMODULE_NAME = 'idWard'; - -export const storage = getStorageManager({moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME}); -/** - * Add real-time data & merge segments. - * @param ortb2 object to merge into - * @param {Object} rtd - */ -function addRealTimeData(ortb2, rtd) { - if (isPlainObject(rtd.ortb2)) { - logMessage('idWardRtdProvider: merging original: ', ortb2); - logMessage('idWardRtdProvider: merging in: ', rtd.ortb2); - mergeDeep(ortb2, rtd.ortb2); - } -} - -/** - * Try parsing stringified array of segment IDs. - * @param {String} data - */ -function tryParse(data) { - try { - return JSON.parse(data); - } catch (err) { - logError(`idWardRtdProvider: failed to parse json:`, data); - return null; - } -} - -/** - * Real-time data retrieval from ID Ward - * @param {Object} reqBidsConfigObj - * @param {function} onDone - * @param {Object} rtdConfig - * @param {Object} userConsent - */ -export function getRealTimeData(reqBidsConfigObj, onDone, rtdConfig, userConsent) { - if (rtdConfig && isPlainObject(rtdConfig.params)) { - const jsonData = storage.getDataFromLocalStorage(rtdConfig.params.cohortStorageKey) - - if (!jsonData) { - return; - } - - const segments = tryParse(jsonData); - - if (segments) { - const udSegment = { - name: 'id-ward.com', - ext: { - segtax: rtdConfig.params.segtax - }, - segment: segments.map(x => ({id: x})) - } - - logMessage('idWardRtdProvider: user.data.segment: ', udSegment); - const data = { - rtd: { - ortb2: { - user: { - data: [ - udSegment - ] - } - } - } - }; - addRealTimeData(reqBidsConfigObj.ortb2Fragments?.global, data.rtd); - onDone(); - } - } -} - -/** - * Module init - * @param {Object} provider - * @param {Object} userConsent - * @return {boolean} - */ -function init(provider, userConsent) { - return true; -} - -/** @type {RtdSubmodule} */ -export const idWardRtdSubmodule = { - name: SUBMODULE_NAME, - getBidRequestData: getRealTimeData, - init: init -}; +import { createRtdProvider } from './anonymisedRtdProvider.js';/* eslint prebid/validate-imports: "off" */ -submodule(MODULE_NAME, idWardRtdSubmodule); +export const { getRealTimeData, rtdSubmodule: idWardRtdSubmodule, storage } = createRtdProvider('idWard'); diff --git a/modules/idWardRtdProvider.md b/modules/idWardRtdProvider.md index 5a44bfa49f3..1c9f0654de6 100644 --- a/modules/idWardRtdProvider.md +++ b/modules/idWardRtdProvider.md @@ -1,3 +1,10 @@ +> **Warning!** +> +> The **idWardRtdProvider** module has been renamed to [anonymisedRtdProvider](anonymisedRtdProvider.md) in light of the company's rebranding. +> **idWardRtdProvider** module is maintained for backward compatibility until the next major Prebid release. +> +> Please use anonymisedRtdProvider instead of idWardRtdProvider in your Prebid integration. + ### Overview ID Ward is a data anonymization technology for privacy-preserving advertising. Publishers and advertisers are able to target and retarget custom audience segments covering 100% of consented audiences. @@ -41,4 +48,4 @@ To view an example of available segments returned by Id Ward: ‘gulp serve --modules=rtdModule,idWardRtdProvider,pubmaticBidAdapter ``` and then point your browser at: -"http://localhost:9999/integrationExamples/gpt/idward_segments_example.html" +"http://localhost:9999/integrationExamples/gpt/idward_segments_example.html" \ No newline at end of file diff --git a/test/spec/modules/anonymisedRtdProvider_spec.js b/test/spec/modules/anonymisedRtdProvider_spec.js new file mode 100644 index 00000000000..89115e5e740 --- /dev/null +++ b/test/spec/modules/anonymisedRtdProvider_spec.js @@ -0,0 +1,214 @@ +import {config} from 'src/config.js'; +import {getRealTimeData, anonymisedRtdSubmodule, storage} from 'modules/anonymisedRtdProvider.js'; + +describe('anonymisedRtdProvider', function() { + let getDataFromLocalStorageStub; + + const testReqBidsConfigObj = { + adUnits: [ + { + bids: ['bid1', 'bid2'] + } + ] + }; + + const onDone = function() { return true }; + + const cmoduleConfig = { + 'name': 'anonymised', + 'params': { + 'cohortStorageKey': 'cohort_ids' + } + } + + beforeEach(function() { + config.resetConfig(); + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage') + }); + + afterEach(function () { + getDataFromLocalStorageStub.restore(); + }); + + describe('anonymisedRtdSubmodule', function() { + it('successfully instantiates', function () { + expect(anonymisedRtdSubmodule.init()).to.equal(true); + }); + }); + + describe('Get Real-Time Data', function() { + it('gets rtd from local storage and set to ortb2.user.data', function() { + const rtdConfig = { + params: { + cohortStorageKey: 'cohort_ids', + bidders: ['smartadserver'], + segtax: 503 + } + }; + + const bidConfig = { + ortb2Fragments: { + global: {} + } + }; + + const rtdUserObj1 = { + name: 'anonymised.io', + ext: { + segtax: 503 + }, + segment: [ + { + id: 'TCZPQOWPEJG3MJOTUQUF793A' + }, + { + id: '93SUG3H540WBJMYNT03KX8N3' + } + ] + }; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3'])); + + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]); + expect(bidConfig.ortb2Fragments.global.user.keywords).to.be.undefined; + }); + + it('gets rtd from local storage and set to ortb2.user.keywords for appnexus bidders parameter', function() { + const rtdConfig = { + params: { + cohortStorageKey: 'cohort_ids', + bidders: ['smartadserver', 'appnexus'], + segtax: 503 + } + }; + + const bidConfig = { + ortb2Fragments: { + global: {} + } + }; + + const rtdUserObj1 = { + name: 'anonymised.io', + ext: { + segtax: 503 + }, + segment: [ + { + id: 'TCZPQOWPEJG3MJOTUQUF793A' + }, + { + id: '93SUG3H540WBJMYNT03KX8N3' + } + ] + }; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3'])); + + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]); + expect(bidConfig.ortb2Fragments.global.user.keywords).to.include('perid=TCZPQOWPEJG3MJOTUQUF793A'); + expect(bidConfig.ortb2Fragments.global.user.keywords).to.include('perid=93SUG3H540WBJMYNT03KX8N3'); + }); + + it('gets rtd from local storage and set to ortb2.user.data if `bidders` parameter undefined', function() { + const rtdConfig = { + params: { + cohortStorageKey: 'cohort_ids', + segtax: 503 + } + }; + + const bidConfig = { + ortb2Fragments: { + global: {} + } + }; + + const rtdUserObj1 = { + name: 'anonymised.io', + ext: { + segtax: 503 + }, + segment: [ + { + id: 'TCZPQOWPEJG3MJOTUQUF793A' + }, + { + id: '93SUG3H540WBJMYNT03KX8N3' + } + ] + }; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3'])); + + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]); + expect(bidConfig.ortb2Fragments.global.user.keywords).to.be.undefined; + }); + + it('do not set rtd if `cohortStorageKey` parameter undefined', function() { + const rtdConfig = { + params: { + bidders: ['smartadserver'] + } + }; + + const bidConfig = { + ortb2Fragments: { + global: {} + } + }; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns(JSON.stringify(['randomsegmentid'])); + + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(bidConfig.ortb2Fragments.global.user).to.be.undefined; + }); + + it('do not set rtd if local storage empty', function() { + const rtdConfig = { + params: { + cohortStorageKey: 'cohort_ids', + segtax: 503 + } + }; + + const bidConfig = {}; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns(null); + + expect(config.getConfig().ortb2).to.be.undefined; + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(config.getConfig().ortb2).to.be.undefined; + }); + + it('do not set rtd if local storage has incorrect value', function() { + const rtdConfig = { + params: { + cohortStorageKey: 'cohort_ids', + segtax: 503 + } + }; + + const bidConfig = {}; + + getDataFromLocalStorageStub.withArgs('cohort_ids') + .returns('wrong cohort ids value'); + + expect(config.getConfig().ortb2).to.be.undefined; + getRealTimeData(bidConfig, () => {}, rtdConfig, {}); + expect(config.getConfig().ortb2).to.be.undefined; + }); + + it('should initialize and return with config', function () { + expect(getRealTimeData(testReqBidsConfigObj, onDone, cmoduleConfig)).to.equal(undefined) + }); + }); +}); diff --git a/test/spec/modules/idWardRtdProvider_spec.js b/test/spec/modules/idWardRtdProvider_spec.js index 924a3794c7b..d1601f058ff 100644 --- a/test/spec/modules/idWardRtdProvider_spec.js +++ b/test/spec/modules/idWardRtdProvider_spec.js @@ -52,7 +52,7 @@ describe('idWardRtdProvider', function() { }; const rtdUserObj1 = { - name: 'id-ward.com', + name: 'anonymised.io', ext: { segtax: 503 }, @@ -109,7 +109,7 @@ describe('idWardRtdProvider', function() { expect(config.getConfig().ortb2).to.be.undefined; }); - it('should initalise and return with config', function () { + it('should initialize and return with config', function () { expect(getRealTimeData(testReqBidsConfigObj, onDone, cmoduleConfig)).to.equal(undefined) }); }); From c8353255cda3a0b3fa69ca879b98d5735e588bb6 Mon Sep 17 00:00:00 2001 From: Irakli Gotsiridze Date: Fri, 26 Apr 2024 17:14:14 +0400 Subject: [PATCH 061/147] Sovrn Bid Adapter: Fledge module integration (#11382) * fledge init * minor test fix * additional check and test fixes --- modules/sovrnBidAdapter.js | 36 ++++++- test/spec/modules/sovrnBidAdapter_spec.js | 121 ++++++++++++++++++++++ 2 files changed, 153 insertions(+), 4 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 6dc5a3dc2ef..3df025b1619 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -137,6 +137,17 @@ export const spec = { imp.ext = imp.ext || {} imp.ext.deals = segmentsString.split(',').map(deal => deal.trim()) } + + const auctionEnvironment = bid?.ortb2Imp?.ext?.ae + if (bidderRequest.fledgeEnabled && isInteger(auctionEnvironment)) { + imp.ext = imp.ext || {} + imp.ext.ae = auctionEnvironment + } else { + if (imp.ext?.ae) { + delete imp.ext.ae + } + } + sovrnImps.push(imp) }) @@ -209,14 +220,14 @@ export const spec = { /** * Format Sovrn responses as Prebid bid responses - * @param {id, seatbid} sovrnResponse A successful response from Sovrn. - * @return {Bid[]} An array of formatted bids. + * @param {id, seatbid, ext} sovrnResponse A successful response from Sovrn. + * @return An array of formatted bids (+ fledgeAuctionConfigs if available) */ - interpretResponse: function({ body: {id, seatbid} }) { + interpretResponse: function({ body: {id, seatbid, ext} }) { if (!id || !seatbid || !Array.isArray(seatbid)) return [] try { - return seatbid + let bids = seatbid .filter(seat => seat) .map(seat => seat.bid.map(sovrnBid => { const bid = { @@ -242,6 +253,23 @@ export const spec = { return bid })) .flat() + + let fledgeAuctionConfigs = deepAccess(ext, 'fledge_auction_configs'); + if (fledgeAuctionConfigs) { + fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { + return { + bidId, + config: Object.assign({ + auctionSignals: {}, + }, cfg) + } + }); + return { + bids, + fledgeAuctionConfigs, + } + } + return bids } catch (e) { logError('Could not interpret bidresponse, error details:', e) return e diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index ad195b6924a..9c7f433ef96 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -240,6 +240,53 @@ describe('sovrnBidAdapter', function() { expect(payload.imp[0]?.ext?.tid).to.equal('1a2c032473f4983') }) + it('when FLEDGE is enabled, should send ortb2imp.ext.ae', function () { + const bidderRequest = { + ...baseBidderRequest, + fledgeEnabled: true + } + const bidRequest = { + ...baseBidRequest, + ortb2Imp: { + ext: { + ae: 1 + } + }, + } + const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest).data) + expect(payload.imp[0].ext.ae).to.equal(1) + }) + + it('when FLEDGE is not enabled, should not send ortb2imp.ext.ae', function () { + const bidRequest = { + ...baseBidRequest, + ortb2Imp: { + ext: { + ae: 1 + } + }, + } + const payload = JSON.parse(spec.buildRequests([bidRequest], baseBidderRequest).data) + expect(payload.imp[0].ext.ae).to.be.undefined + }) + + it('when FLEDGE is enabled, but env is malformed, should not send ortb2imp.ext.ae', function () { + const bidderRequest = { + ...baseBidderRequest, + fledgeEnabled: true + } + const bidRequest = { + ...baseBidRequest, + ortb2Imp: { + ext: { + ae: 'malformed' + } + }, + } + const payload = JSON.parse(spec.buildRequests([bidRequest], bidderRequest).data) + expect(payload.imp[0].ext.ae).to.be.undefined + }) + it('includes the ad unit code in the request', function() { const impression = payload.imp[0] expect(impression.adunitcode).to.equal('adunit-code') @@ -780,6 +827,80 @@ describe('sovrnBidAdapter', function() { }) }) + describe('fledge response', function () { + let fledgeResponse = { + body: { + id: '37386aade21a71', + seatbid: [{ + bid: [{ + id: 'a_403370_332fdb9b064040ddbec05891bd13ab28', + crid: 'creativelycreatedcreativecreative', + impid: '263c448586f5a1', + price: 0.45882675, + nurl: '', + adm: '', + h: 90, + w: 728 + }] + }], + ext: { + fledge_auction_configs: { + 'test_bid_id': { + seller: 'ap.lijit.com', + interestGroupBuyers: ['dsp1.com'], + sellerTimeout: 0, + perBuyerSignals: { + 'dsp1.com': { + bid_macros: 0.1, + disallowed_adv_ids: [ + '8765', + '4321' + ], + } + } + } + } + } + } + } + let invalidFledgeResponse = { + body: { + id: '37386aade21a71', + seatbid: [{ + bid: [{ + id: 'a_403370_332fdb9b064040ddbec05891bd13ab28', + crid: 'creativelycreatedcreativecreative', + impid: '263c448586f5a1', + price: 0.45882675, + nurl: '', + adm: '', + h: 90, + w: 728 + }] + }], + ext: { + fledge_auction_configs: { + } + } + } + } + it('should return fledge auction configs alongside bids', function () { + const result = spec.interpretResponse(fledgeResponse) + expect(result).to.have.property('bids') + expect(result).to.have.property('fledgeAuctionConfigs') + expect(result.fledgeAuctionConfigs.length).to.equal(1) + expect(result.fledgeAuctionConfigs[0].bidId).to.equal('test_bid_id') + expect(result.fledgeAuctionConfigs[0].config).to.not.be.undefined + expect(result.fledgeAuctionConfigs[0].config).to.contain.keys('seller', 'interestGroupBuyers', 'sellerTimeout', 'perBuyerSignals') + }) + it('should ignore invalid fledge auction configs', function () { + const result = spec.interpretResponse(invalidFledgeResponse) + expect(result).to.have.property('bids') + expect(result).to.have.property('fledgeAuctionConfigs') + expect(result.fledgeAuctionConfigs.length).to.equal(0) + }) + }) + describe('interpretResponse video', function () { let videoResponse const bidAdm = 'key%3Dvalue' From 6c0648b6d84a8ad6682b964029081bd83078442d Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 26 Apr 2024 15:49:43 +0200 Subject: [PATCH 062/147] Skip response processing if empty (#11376) --- modules/adyoulikeBidAdapter.js | 4 ++++ test/spec/modules/adyoulikeBidAdapter_spec.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js index ad1c0af039e..146e1d3b24a 100644 --- a/modules/adyoulikeBidAdapter.js +++ b/modules/adyoulikeBidAdapter.js @@ -160,6 +160,10 @@ export const spec = { const bidResponses = []; var bidRequests = {}; + if (!serverResponse || !serverResponse.body) { + return bidResponses; + } + try { bidRequests = JSON.parse(request.data).Bids; } catch (err) { diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js index ffd6729397a..bafa031cd25 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -812,6 +812,12 @@ describe('Adyoulike Adapter', function () { } }); + it('handles 204 responses', function () { + serverResponse.body = ''; + let result = spec.interpretResponse(serverResponse, []); + expect(result).deep.equal([]); + }); + it('handles nobid responses', function () { let response = [{ BidID: '123dfsdf', From 4deba897f7ecefa695ac160332e05772644d425a Mon Sep 17 00:00:00 2001 From: Dmitry Sinev Date: Fri, 26 Apr 2024 18:08:59 +0300 Subject: [PATCH 063/147] Appnexus Bid Adapter: add support for ast_override_div debug feature (#11390) --- modules/appnexusBidAdapter.js | 12 +++ test/spec/modules/appnexusBidAdapter_spec.js | 82 ++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 5210d6f7562..bb80b6a8588 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -774,6 +774,18 @@ function bidToTag(bid) { } else { tag.code = bid.params.inv_code; } + // Xandr expects GET variable to be in a following format: + // page.html?ast_override_div=divId:creativeId,divId2:creativeId2 + const overrides = getParameterByName('ast_override_div'); + if (isStr(overrides) && overrides !== '') { + const adUnitOverride = overrides.split(',').find((pair) => pair.startsWith(`${bid.adUnitCode}:`)); + if (adUnitOverride) { + const forceCreativeId = adUnitOverride.split(':')[1]; + if (forceCreativeId) { + tag.force_creative_id = parseInt(forceCreativeId, 10); + } + } + } tag.allow_smaller_sizes = bid.params.allow_smaller_sizes || false; tag.use_pmt_rule = (typeof bid.params.use_payment_rule === 'boolean') ? bid.params.use_payment_rule : (typeof bid.params.use_pmt_rule === 'boolean') ? bid.params.use_pmt_rule : false; diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index cc86a8a0aaa..2a277cf1ba7 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -1442,6 +1442,88 @@ describe('AppNexusAdapter', function () { config.getConfig.restore(); }); + describe('ast_override_div', function () { + let getParamStub; + let bidRequest = Object.assign({}, bidRequests[0]); + let bidRequest2 = deepClone(bidRequests[0]); + bidRequest2.adUnitCode = 'adUnit_code_2'; + let bidRequest3 = deepClone(bidRequests[0]); + bidRequest3.adUnitCode = 'adUnit_code_3'; + + before(function () { + getParamStub = sinon.stub(utils, 'getParameterByName'); + }); + + it('should set forced creative id if one adUnitCode passed', function () { + getParamStub.callsFake(function(par) { + if (par === 'ast_override_div') return 'adunit-code:1234'; + return ''; + }); + + const request = spec.buildRequests([bidRequest, bidRequest2]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].force_creative_id).to.deep.equal(1234); + expect(payload.tags[1].force_creative_id).to.not.exist; + }); + + it('should set forced creative id if `ast_override_div` is set to override multiple adUnitCode', function () { + getParamStub.callsFake(function(par) { + if (par === 'ast_override_div') return 'adunit-code:1234,adUnit_code_2:5678'; + return ''; + }); + + const request = spec.buildRequests([bidRequest, bidRequest2, bidRequest3]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].force_creative_id).to.deep.equal(1234); + expect(payload.tags[1].force_creative_id).to.deep.equal(5678); + expect(payload.tags[2].force_creative_id).to.not.exist; + }); + + it('should not set forced creative id if `ast_override_div` is missing creativeId', function () { + getParamStub.callsFake(function(par) { + if (par === 'ast_override_div') return 'adunit-code'; + return ''; + }); + + const request = spec.buildRequests([bidRequest, bidRequest2]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].force_creative_id).to.not.exist; + expect(payload.tags[1].force_creative_id).to.not.exist; + }); + + it('should not set forced creative id if `ast_override_div` is in the wrong format', function () { + getParamStub.callsFake(function(par) { + if (par === 'ast_override_div') return 'adunit-code;adUnit_code_2:5678'; + return ''; + }); ; + + const request = spec.buildRequests([bidRequest, bidRequest2]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].force_creative_id).to.not.exist; + expect(payload.tags[1].force_creative_id).to.not.exist; + }); + + it('should not set forced creative id if `ast_override_div` is missing', function () { + getParamStub.callsFake(function(par) { + return ''; + }); ; + + const request = spec.buildRequests([bidRequest, bidRequest2]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].force_creative_id).to.not.exist; + expect(payload.tags[1].force_creative_id).to.not.exist; + }); + + after(function () { + getParamStub.restore(); + }); + }); + it('should set the X-Is-Test customHeader if test flag is enabled', function () { let bidRequest = Object.assign({}, bidRequests[0]); sinon.stub(config, 'getConfig') From 4db5ae6578d9509f6a484c7008e5b1d87826cf7d Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Fri, 26 Apr 2024 12:53:12 -0400 Subject: [PATCH 064/147] ConsentManagementGpp module: throw error on some invalid sections (#11385) * Update consentManagementGpp.js * Update consentManagementGpp.js * Update consentManagementGpp.js * Update consentManagementGpp.js * Update modules/consentManagementGpp.js Co-authored-by: Demetrio Girardi --------- Co-authored-by: Demetrio Girardi --- modules/consentManagementGpp.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/consentManagementGpp.js b/modules/consentManagementGpp.js index 416430fb1c9..a7bbca62205 100644 --- a/modules/consentManagementGpp.js +++ b/modules/consentManagementGpp.js @@ -423,6 +423,11 @@ function processCmpData(consentData) { ) { throw new GPPError('CMP returned unexpected value during lookup process.', consentData); } + ['usnatv1', 'uscav1'].forEach(section => { + if (consentData?.parsedSections?.[section]) { + logWarn(`Received invalid section from cmp: '${section}'. Some functionality may not work as expected`, consentData) + } + }) return storeConsentData(consentData); } From 1243f21f88795386d8a1e9c065a8739acbd1e619 Mon Sep 17 00:00:00 2001 From: jsnellbaker <31102355+jsnellbaker@users.noreply.github.com> Date: Sat, 27 Apr 2024 21:03:24 -0400 Subject: [PATCH 065/147] appnexusBidAdapter - video plcmt logic fix (#11403) --- modules/appnexusBidAdapter.js | 2 +- test/spec/modules/appnexusBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index bb80b6a8588..551bf5401e2 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -1030,7 +1030,7 @@ function getContextFromPlcmt(ortbPlcmt, ortbStartDelay) { } if (ortbPlcmt === 2) { - if (!ortbStartDelay) { + if (typeof ortbStartDelay === 'undefined') { return; } if (ortbStartDelay === 0) { diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 2a277cf1ba7..c2da2f36223 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -411,7 +411,7 @@ describe('AppNexusAdapter', function () { playerSize: [640, 480], context: 'outstream', plcmt: 2, - startdelay: -1, + startdelay: 0, mimes: ['video/mp4'], skip: 1, minduration: 5, @@ -427,7 +427,7 @@ describe('AppNexusAdapter', function () { minduration: 5, playback_method: 2, skippable: true, - context: 9 + context: 8 }); expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4]) }); From 7b77515a69b61bee1019f47ebdb93b4164d0a36c Mon Sep 17 00:00:00 2001 From: samuel-palmer-relevant-digital <77437973+samuel-palmer-relevant-digital@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:52:20 +0200 Subject: [PATCH 066/147] Remove 'transformBidParams' from relevantdigitalBidAdapter (#11412) --- modules/relevantdigitalBidAdapter.js | 18 ----- .../modules/relevantdigitalBidAdapter_spec.js | 78 +------------------ 2 files changed, 1 insertion(+), 95 deletions(-) diff --git a/modules/relevantdigitalBidAdapter.js b/modules/relevantdigitalBidAdapter.js index 8d1265075f9..c776022749d 100644 --- a/modules/relevantdigitalBidAdapter.js +++ b/modules/relevantdigitalBidAdapter.js @@ -200,24 +200,6 @@ export const spec = { }); return syncs; }, - - /** If server side, transform bid params if needed */ - transformBidParams(params, isOrtb, adUnit, bidRequests) { - if (!params.placementId) { - return; - } - const bid = bidRequests.flatMap(req => req.adUnitsS2SCopy || []).flatMap((adUnit) => adUnit.bids).find((bid) => bid.params?.placementId === params.placementId); - if (!bid) { - return; - } - const cfg = getBidderConfig([bid]); - FIELDS.forEach(({ name }) => { - if (cfg[name] && !params[name]) { - params[name] = cfg[name]; - } - }); - return params; - }, }; registerBidder(spec); diff --git a/test/spec/modules/relevantdigitalBidAdapter_spec.js b/test/spec/modules/relevantdigitalBidAdapter_spec.js index 1575c5c6b94..45a84d5991d 100644 --- a/test/spec/modules/relevantdigitalBidAdapter_spec.js +++ b/test/spec/modules/relevantdigitalBidAdapter_spec.js @@ -1,10 +1,5 @@ import {spec, resetBidderConfigs} from 'modules/relevantdigitalBidAdapter.js'; -import { parseUrl, deepClone } from 'src/utils.js'; -import { config } from 'src/config.js'; -import { S2S } from 'src/constants.js'; - -import adapterManager, { -} from 'src/adapterManager.js'; +import { parseUrl } from 'src/utils.js'; const expect = require('chai').expect; @@ -13,17 +8,6 @@ const PLACEMENT_ID = 'example_placement_id'; const ACCOUNT_ID = 'example_account_id'; const TEST_DOMAIN = 'example.com'; const TEST_PAGE = `https://${TEST_DOMAIN}/page.html`; - -const CONFIG = { - enabled: true, - endpoint: S2S.DEFAULT_ENDPOINT, - timeout: 1000, - maxBids: 1, - adapter: 'prebidServer', - bidders: ['relevantdigital'], - accountId: 'abc' -}; - const ADUNIT_CODE = '/19968336/header-bid-tag-0'; const BID_PARAMS = { @@ -312,64 +296,4 @@ describe('Relevant Digital Bid Adaper', function () { expect(allSyncs).to.deep.equal(expectedResult) }); }); - describe('transformBidParams', function () { - beforeEach(() => { - config.setConfig({ - s2sConfig: CONFIG, - }); - }); - afterEach(() => { - config.resetConfig(); - }); - - const adUnit = (params) => ({ - code: ADUNIT_CODE, - bids: [ - { - bidder: 'relevantdigital', - adUnitCode: ADUNIT_CODE, - params, - } - ] - }); - - const request = (params) => adapterManager.makeBidRequests([adUnit(params)], 123, 'auction-id', 123, [], {})[0]; - - it('transforms adunit bid params and config params correctly', function () { - config.setConfig({ - relevantdigital: { - pbsHost: PBS_HOST, - accountId: ACCOUNT_ID, - }, - }); - const adUnitParams = { placementId: PLACEMENT_ID }; - const expextedTransformedBidParams = { - ...BID_PARAMS.params, pbsHost: `https://${BID_PARAMS.params.pbsHost}`, 'pbsBufferMs': 250 - }; - expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams); - }); - it('transforms adunit bid params correctly', function () { - const adUnitParams = { ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 }; - const expextedTransformedBidParams = { - ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 - }; - expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams); - }); - it('transforms adunit bid params correctly', function () { - const adUnitParams = { ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 }; - const expextedTransformedBidParams = { - ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 - }; - expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams); - }); - it('does not transform bid params if placementId is missing', function () { - const adUnitParams = { ...BID_PARAMS.params, placementId: null }; - expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.equal(undefined); - }); - it('does not transform bid params s2s config is missing', function () { - config.resetConfig(); - const adUnitParams = BID_PARAMS.params; - expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.equal(undefined); - }); - }) }); From 428ae3bc61044ab23f1553d02ec35351d2914553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Mon, 29 Apr 2024 20:35:49 +0200 Subject: [PATCH 067/147] Criteo Bid Adapter: fix issue where bidder conf pubid param is not sent in the proper field (#11416) --- modules/criteoBidAdapter.js | 9 ++++++--- test/spec/modules/criteoBidAdapter_spec.js | 13 +++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index defe2c081e3..faaa7883b42 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -621,9 +621,6 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (networkId) { request.publisher.networkid = networkId; } - if (pubid) { - request.publisher.id = pubid; - } request.source = { tid: bidderRequest.ortb2?.source?.tid @@ -637,6 +634,12 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { request.user = bidderRequest.ortb2?.user || {}; request.site = bidderRequest.ortb2?.site || {}; request.app = bidderRequest.ortb2?.app || {}; + + if (pubid) { + request.site.publisher = {...request.site.publisher, ...{ id: pubid }}; + request.app.publisher = {...request.app.publisher, ...{ id: pubid }}; + } + request.device = bidderRequest.ortb2?.device || {}; if (bidderRequest && bidderRequest.ceh) { request.user.ceh = bidderRequest.ceh; diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index c460b451193..f0fc9dadda8 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -2009,7 +2009,15 @@ describe('The Criteo bidding adapter', function () { }); it('should properly transmit the pubid and slot uid if available', function () { - const bidderRequest = {}; + const bidderRequest = { + ortb2: { + site: { + publisher: { + id: 'pub-777' + } + } + } + }; const bidRequests = [ { bidder: 'criteo', @@ -2050,7 +2058,8 @@ describe('The Criteo bidding adapter', function () { ]; const request = spec.buildRequests(bidRequests, bidderRequest); const ortbRequest = request.data; - expect(ortbRequest.publisher.id).to.equal('pub-888'); + expect(ortbRequest.publisher.id).to.be.undefined; + expect(ortbRequest.site.publisher.id).to.equal('pub-888'); expect(request.data.slots[0].ext.bidder).to.be.undefined; expect(request.data.slots[1].ext.bidder.uid).to.equal(888); }); From ee509d362a3adda6fd3d5e040eb549bd4b6d9c95 Mon Sep 17 00:00:00 2001 From: pm-azhar-mulla <75726247+pm-azhar-mulla@users.noreply.github.com> Date: Tue, 30 Apr 2024 01:29:03 +0530 Subject: [PATCH 068/147] Using origbidid instead of piid (#11415) Co-authored-by: pm-azhar-mulla --- modules/pubmaticAnalyticsAdapter.js | 4 +- .../modules/pubmaticAnalyticsAdapter_spec.js | 66 ++++++++++++++++--- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js index 753b706e363..9e1fa49fef2 100755 --- a/modules/pubmaticAnalyticsAdapter.js +++ b/modules/pubmaticAnalyticsAdapter.js @@ -294,6 +294,7 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { 'pn': adapterName, 'bc': bid.bidderCode || bid.bidder, 'bidid': bid.bidId || bidId, + 'origbidid': bid?.bidResponse?.partnerImpId || bid?.bidResponse?.prebidBidId || bid.bidId || bidId, 'db': bid.bidResponse ? 0 : 1, 'kgpv': getValueForKgpv(bid, adUnitId), 'kgpsv': bid.params && bid.params.kgpv ? bid.params.kgpv : adUnitId, @@ -313,7 +314,6 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { 'af': bid.bidResponse ? (bid.bidResponse.mediaType || undefined) : undefined, 'ocpm': bid.bidResponse ? (bid.bidResponse.originalCpm || 0) : 0, 'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD, - 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING, 'frv': bid.bidResponse ? bid.bidResponse.floorData?.floorRuleValue : undefined, 'md': bid.bidResponse ? getMetadata(bid.bidResponse.meta) : undefined, 'pb': pg || undefined @@ -487,7 +487,7 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD); pixelURL += '&eg=' + enc(winningBid.bidResponse.bidGrossCpmUSD); pixelURL += '&kgpv=' + enc(getValueForKgpv(winningBid, adUnitId)); - pixelURL += '&piid=' + enc(winningBid.bidResponse.partnerImpId || EMPTY_STRING); + pixelURL += '&origbidid=' + enc(winningBid?.bidResponse?.partnerImpId || winningBid?.bidResponse?.prebidBidId || winningBid.bidId); pixelURL += '&di=' + enc(winningBid?.bidResponse?.dealId || OPEN_AUCTION_DEAL_ID); pixelURL += '&pb=' + enc(pg); diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js index cb13a4db234..002b7fb3063 100755 --- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -585,7 +585,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bc).to.equal('pubmatic'); expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); - expect(data.s[0].ps[0].piid).to.equal('partnerImpressionID-1'); + expect(data.s[0].ps[0].origbidid).to.equal('partnerImpressionID-1'); expect(data.s[0].ps[0].db).to.equal(0); expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); expect(data.s[0].ps[0].kgpsv).to.equal('/19968336/header-bid-tag-0'); @@ -618,7 +618,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bc).to.equal('pubmatic'); expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); - expect(data.s[1].ps[0].piid).to.equal('partnerImpressionID-2'); + expect(data.s[1].ps[0].origbidid).to.equal('partnerImpressionID-2'); expect(data.s[1].ps[0].db).to.equal(0); expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); @@ -659,7 +659,7 @@ describe('pubmatic analytics adapter', function () { expect(data.bc).to.equal('pubmatic'); expect(data.eg).to.equal('1.23'); expect(data.en).to.equal('1.23'); - expect(data.piid).to.equal('partnerImpressionID-1'); + expect(data.origbidid).to.equal('partnerImpressionID-1'); expect(data.plt).to.equal('1'); expect(data.psz).to.equal('640x480'); expect(data.tgid).to.equal('15'); @@ -1372,7 +1372,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bc).to.equal('pubmatic'); expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); - expect(data.s[1].ps[0].piid).to.equal('partnerImpressionID-2'); + expect(data.s[1].ps[0].origbidid).to.equal('partnerImpressionID-2'); expect(data.s[1].ps[0].db).to.equal(0); expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); @@ -1453,7 +1453,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bc).to.equal('pubmatic_alias'); expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); - expect(data.s[0].ps[0].piid).to.equal('partnerImpressionID-1'); + expect(data.s[0].ps[0].origbidid).to.equal('partnerImpressionID-1'); expect(data.s[0].ps[0].db).to.equal(0); expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); expect(data.s[0].ps[0].kgpsv).to.equal('/19968336/header-bid-tag-0'); @@ -1487,7 +1487,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].pn).to.equal('pubmatic'); expect(data.s[1].ps[0].bc).to.equal('pubmatic'); expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); - expect(data.s[1].ps[0].piid).to.equal('partnerImpressionID-2'); + expect(data.s[1].ps[0].origbidid).to.equal('partnerImpressionID-2'); expect(data.s[1].ps[0].db).to.equal(0); expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); @@ -1528,7 +1528,7 @@ describe('pubmatic analytics adapter', function () { expect(data.bc).to.equal('pubmatic_alias'); expect(data.eg).to.equal('1.23'); expect(data.en).to.equal('1.23'); - expect(data.piid).to.equal('partnerImpressionID-1'); + expect(data.origbidid).to.equal('partnerImpressionID-1'); }); it('Logger: best case + win tracker in case of GroupM as alternate bidder', function() { @@ -1585,7 +1585,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bc).to.equal('groupm'); expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); - expect(data.s[0].ps[0].piid).to.equal('partnerImpressionID-1'); + expect(data.s[0].ps[0].origbidid).to.equal('partnerImpressionID-1'); expect(data.s[0].ps[0].db).to.equal(0); expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); expect(data.s[0].ps[0].kgpsv).to.equal('/19968336/header-bid-tag-0'); @@ -1615,7 +1615,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].pn).to.equal('pubmatic'); expect(data.s[1].ps[0].bc).to.equal('pubmatic'); expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); - expect(data.s[1].ps[0].piid).to.equal('partnerImpressionID-2'); + expect(data.s[1].ps[0].origbidid).to.equal('partnerImpressionID-2'); expect(data.s[1].ps[0].db).to.equal(0); expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); @@ -1654,7 +1654,53 @@ describe('pubmatic analytics adapter', function () { expect(data.bc).to.equal('groupm'); expect(data.eg).to.equal('1.23'); expect(data.en).to.equal('1.23'); - expect(data.piid).to.equal('partnerImpressionID-1'); + expect(data.origbidid).to.equal('partnerImpressionID-1'); + }); + + it('Logger: best case + win tracker. Log bidId when partnerimpressionid is missing', function() { + delete MOCK.BID_RESPONSE[1]['partnerImpId']; + MOCK.BID_RESPONSE[1]['prebidBidId'] = 'Prebid-bid-id-1'; + sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => { + return [MOCK.BID_RESPONSE[0], MOCK.BID_RESPONSE[1]] + }); + + config.setConfig({ + testGroupId: 15 + }); + + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON[0]); + events.emit(BID_WON, MOCK.BID_WON[1]); + + clock.tick(2000 + 1000); + expect(requests.length).to.equal(3); // 1 logger and 2 win-tracker + let request = requests[2]; // logger is executed late, trackers execute first + expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); + let data = getLoggerJsonFromRequest(request.requestBody); + expect(data.s).to.be.an('array'); + expect(data.s.length).to.equal(2); + + // slot 1 + expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); + expect(data.s[0].ps[0].origbidid).to.equal('partnerImpressionID-1'); + + // slot 2 + expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); + expect(data.s[1].ps[0].origbidid).to.equal('3bd4ebb1c900e2'); + + // tracker slot1 + let firstTracker = requests[0].url; + expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); + data = {}; + firstTracker.split('?')[1].split('&').map(e => e.split('=')).forEach(e => data[e[0]] = e[1]); + expect(data.bidid).to.equal('2ecff0db240757'); + expect(data.origbidid).to.equal('partnerImpressionID-1'); }); }); From b38c0a6b8b54ba02f8d724c1f59acfa8770303ea Mon Sep 17 00:00:00 2001 From: redaguermas Date: Tue, 30 Apr 2024 05:05:26 -0700 Subject: [PATCH 069/147] NoBid Bid Adapter : update version 1.3.4 (#11420) * Enable supplyChain support * Added support for COPPA * rebuilt * Added support for Extended User IDs. * Added support for the "meta" attribute in bid response. * Delete nobidBidAdapter.js.orig * Delete a * Delete .jsdtscope * Delete org.eclipse.wst.jsdt.ui.superType.container * Delete org.eclipse.wst.jsdt.ui.superType.name * Delete .project * Renamed the Analytics Adapter to "nobid" otherwise it wouldn't work with the wrapper builder on the Prebid.js website and added Prebid version "pbver" to the bidding and analytics requests. --------- Co-authored-by: Reda Guermas --- modules/nobidAnalyticsAdapter.js | 6 +++--- modules/nobidBidAdapter.js | 6 ++++-- test/spec/modules/nobidAnalyticsAdapter_spec.js | 1 + test/spec/modules/nobidBidAdapter_spec.js | 3 +-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/nobidAnalyticsAdapter.js b/modules/nobidAnalyticsAdapter.js index 5ae77f0cdc8..a0aa5ee4989 100644 --- a/modules/nobidAnalyticsAdapter.js +++ b/modules/nobidAnalyticsAdapter.js @@ -6,7 +6,7 @@ import { EVENTS } from '../src/constants.js'; import adapterManager from '../src/adapterManager.js'; import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js'; -const VERSION = '2.0.1'; +const VERSION = '2.0.2'; const MODULE_NAME = 'nobidAnalyticsAdapter'; const ANALYTICS_OPT_FLUSH_TIMEOUT_SECONDS = 5 * 1000; const RETENTION_SECONDS = 1 * 24 * 3600; @@ -53,6 +53,7 @@ function sendEvent (event, eventType) { } try { event.version = VERSION; + event.pbver = '$prebid.version$'; const endpoint = `${resolveEndpoint()}/event/${eventType}?pubid=${nobidAnalytics.initOptions.siteId}`; ajax(endpoint, function (response) { @@ -175,10 +176,9 @@ nobidAnalytics = { ANALYTICS_DATA_NAME: 'analytics.nobid.io', ANALYTICS_OPT_NAME: 'analytics.nobid.io.optData' } - adapterManager.registerAnalyticsAdapter({ adapter: nobidAnalytics, - code: 'nobidAnalytics', + code: 'nobid', gvlid: GVLID }); nobidAnalytics.originalAdUnits = {}; diff --git a/modules/nobidBidAdapter.js b/modules/nobidBidAdapter.js index 28fb38e14e5..77e5a1c6fed 100644 --- a/modules/nobidBidAdapter.js +++ b/modules/nobidBidAdapter.js @@ -17,7 +17,7 @@ import { hasPurpose1Consent } from '../src/utils/gpdr.js'; const GVLID = 816; const BIDDER_CODE = 'nobid'; const storage = getStorageManager({bidderCode: BIDDER_CODE}); -window.nobidVersion = '1.3.3'; +window.nobidVersion = '1.3.4'; window.nobid = window.nobid || {}; window.nobid.bidResponses = window.nobid.bidResponses || {}; window.nobid.timeoutTotal = 0; @@ -161,6 +161,7 @@ function nobidBuildRequests(bids, bidderRequest) { state['gdpr'] = gdprConsent(bidderRequest); state['usp'] = uspConsent(bidderRequest); state['pjbdr'] = (bidderRequest && bidderRequest.bidderCode) ? bidderRequest.bidderCode : 'nobid'; + state['pbver'] = '$prebid.version$'; const sch = schain(bids); if (sch) state['schain'] = sch; const cop = coppa(); @@ -383,7 +384,8 @@ export const spec = { */ isBidRequestValid: function(bid) { log('isBidRequestValid', bid); - return !!bid.params.siteId; + if (bid?.params?.siteId) return true; + return false; }, /** * Make a server request from the list of BidRequests. diff --git a/test/spec/modules/nobidAnalyticsAdapter_spec.js b/test/spec/modules/nobidAnalyticsAdapter_spec.js index 07823d3536f..81b78dc14d6 100644 --- a/test/spec/modules/nobidAnalyticsAdapter_spec.js +++ b/test/spec/modules/nobidAnalyticsAdapter_spec.js @@ -399,6 +399,7 @@ describe('NoBid Prebid Analytic', function () { expect(server.requests).to.have.length(1); const auctionEndRequest = JSON.parse(server.requests[0].requestBody); expect(auctionEndRequest).to.have.property('version', nobidAnalyticsVersion); + expect(auctionEndRequest).to.have.property('pbver', '$prebid.version$'); expect(auctionEndRequest).to.have.property('auctionId', expectedOutgoingRequest.auctionId); expect(auctionEndRequest.bidderRequests).to.have.length(1); expect(auctionEndRequest.bidderRequests[0].bidderCode).to.equal(expectedOutgoingRequest.bidderRequests[0].bidderCode); diff --git a/test/spec/modules/nobidBidAdapter_spec.js b/test/spec/modules/nobidBidAdapter_spec.js index b1e303bde6e..2f2c97eae51 100644 --- a/test/spec/modules/nobidBidAdapter_spec.js +++ b/test/spec/modules/nobidBidAdapter_spec.js @@ -62,7 +62,6 @@ describe('Nobid Adapter', function () { }); it('should return true when required params found', function () { - let bid = Object.assign({}, bid); delete bid.params; bid.params = { 'siteId': 2 @@ -72,7 +71,6 @@ describe('Nobid Adapter', function () { }); it('should return false when required params are not passed', function () { - let bid = Object.assign({}, bid); delete bid.params; bid.params = { 'siteId': 0 @@ -399,6 +397,7 @@ describe('Nobid Adapter', function () { const payload = JSON.parse(request.data); expect(payload.sid).to.equal(SITE_ID); expect(payload.pjbdr).to.equal('nobid'); + expect(payload.pbver).to.equal('$prebid.version$'); expect(payload.l).to.exist.and.to.equal(encodeURIComponent(REFERER)); expect(payload.a).to.exist; expect(payload.t).to.exist; From 51532c683630642150fd12e6c25a9ffb104af002 Mon Sep 17 00:00:00 2001 From: Ilia Medvedev Date: Tue, 30 Apr 2024 16:16:13 +0400 Subject: [PATCH 070/147] Limelight Digital Bid Adapter: add sua field (#11422) --- modules/limelightDigitalBidAdapter.js | 7 ++++--- .../limelightDigitalBidAdapter_spec.js | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index 5cccf5300b3..acc6876b822 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -62,7 +62,7 @@ export const spec = { } const placements = groupBy(validBidRequests.map(bidRequest => buildPlacement(bidRequest)), 'host') return Object.keys(placements) - .map(host => buildRequest(winTop, host, placements[host].map(placement => placement.adUnit))); + .map(host => buildRequest(winTop, host, placements[host].map(placement => placement.adUnit), bidderRequest)); }, /** @@ -119,7 +119,7 @@ export const spec = { registerBidder(spec); -function buildRequest(winTop, host, adUnits) { +function buildRequest(winTop, host, adUnits, bidderRequest) { return { method: 'POST', url: `https://${host}/hb`, @@ -127,7 +127,8 @@ function buildRequest(winTop, host, adUnits) { secure: (location.protocol === 'https:'), deviceWidth: winTop.screen.width, deviceHeight: winTop.screen.height, - adUnits: adUnits + adUnits: adUnits, + sua: bidderRequest?.ortb2?.device?.sua } } } diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index 6348d6a1ac6..9e8a00959d4 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -208,7 +208,19 @@ describe('limelightDigitalAdapter', function () { } describe('buildRequests', function () { - const serverRequests = spec.buildRequests([bid1, bid2, bid3, bid4]) + const bidderRequest = { + ortb2: { + device: { + sua: { + browsers: [], + platform: [], + mobile: 1, + architecture: 'arm' + } + } + } + } + const serverRequests = spec.buildRequests([bid1, bid2, bid3, bid4], bidderRequest) it('Creates two ServerRequests', function() { expect(serverRequests).to.exist expect(serverRequests).to.have.lengthOf(2) @@ -230,7 +242,8 @@ describe('limelightDigitalAdapter', function () { 'deviceWidth', 'deviceHeight', 'secure', - 'adUnits' + 'adUnits', + 'sua' ); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); @@ -266,6 +279,10 @@ describe('limelightDigitalAdapter', function () { expect(adUnit.custom5).to.be.a('string'); expect(adUnit.page).to.be.a('string'); }) + expect(data.sua.browsers).to.be.a('array'); + expect(data.sua.platform).to.be.a('array'); + expect(data.sua.mobile).to.be.a('number'); + expect(data.sua.architecture).to.be.a('string'); }) }) it('Returns valid URL', function () { From a6aba0ef79c92fdbb08419959d96cbf739d5749a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9onard=20Labat?= Date: Tue, 30 Apr 2024 15:47:33 +0200 Subject: [PATCH 071/147] Criteo Bid Adapter: Add missing tmax along the request send to backend (#11423) --- modules/criteoBidAdapter.js | 1 + test/spec/modules/criteoBidAdapter_spec.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index faaa7883b42..c95cbf7af73 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -674,6 +674,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (bidderRequest && bidderRequest.ortb2?.bapp) { request.bapp = bidderRequest.ortb2.bapp; } + request.tmax = bidderRequest.timeout; return request; } diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index f0fc9dadda8..def35b13955 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -675,6 +675,25 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.source.tid).to.equal('abc'); }); + it('should properly transmit tmax if available', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.tmax).to.equal(bidderRequest.timeout); + }); + it('should properly transmit bidId if available', function () { const bidderRequest = { ortb2: { From 14ef0c15f989049c00d81980a0ada247fe991575 Mon Sep 17 00:00:00 2001 From: "yuu.t" Date: Tue, 30 Apr 2024 17:38:34 +0200 Subject: [PATCH 072/147] yieldlabBidAdapter support topics (#11421) --- modules/yieldlabBidAdapter.js | 27 +++++++- test/spec/modules/yieldlabBidAdapter_spec.js | 70 ++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index 13910d688e8..23ff94f62a1 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -1,4 +1,4 @@ -import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js'; +import { _each, deepAccess, isArray, isEmptyStr, isFn, isPlainObject, timestamp } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { find } from '../src/polyfill.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; @@ -130,6 +130,13 @@ export const spec = { } } } + + const topics = getGoogleTopics(bidderRequest); + if (topics) { + assignIfNotUndefined(query, 'segtax', topics.segtax); + assignIfNotUndefined(query, 'segclass', topics.segclass); + assignIfNotUndefined(query, 'segments', topics.segments); + } } const adslots = adslotIds.join(','); @@ -607,4 +614,22 @@ function assignIfNotUndefined(obj, key, value) { } } +function getGoogleTopics(bid) { + const userData = deepAccess(bid, 'ortb2.user.data') || []; + const validData = userData.filter(dataObj => + dataObj.segment && isArray(dataObj.segment) && dataObj.segment.length > 0 && + dataObj.segment.every(seg => (seg.id && !isEmptyStr(seg.id) && isFinite(seg.id))) + )[0]; + + if (validData) { + return { + segtax: validData.ext?.segtax, + segclass: validData.ext?.segclass, + segments: validData.segment.map(seg => Number(seg.id)).join(','), + }; + } + + return undefined; +} + registerBidder(spec); diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 751dff4fe33..225186dd326 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -585,6 +585,76 @@ describe('yieldlabBidAdapter', () => { expect(request.url).to.not.include('dsaparams'); }); }); + + describe('google topics handling', () => { + afterEach(() => { + config.resetConfig(); + }); + + it('does pass segtax, segclass, segments for google topics data', () => { + const GOOGLE_TOPICS_DATA = { + ortb2: { + user: { + data: [ + { + ext: { + segtax: 600, + segclass: 'v1', + }, + segment: [ + {id: '717'}, {id: '808'}, + ] + } + ] + }, + }, + } + config.setConfig(GOOGLE_TOPICS_DATA); + const request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...GOOGLE_TOPICS_DATA }); + expect(request.url).to.include('segtax=600&segclass=v1&segments=717%2C808'); + }); + + it('does not pass topics params for invalid topics data', () => { + const INVALID_TOPICS_DATA = { + ortb2: { + user: { + data: [ + { + segment: [] + }, + { + segment: [{id: ''}] + }, + { + segment: [{id: null}] + }, + { + segment: [{id: 'dummy'}, {id: '123'}] + }, + { + ext: { + segtax: 600, + segclass: 'v1', + }, + segment: [ + { + name: 'dummy' + } + ] + }, + ] + } + } + }; + + config.setConfig(INVALID_TOPICS_DATA); + let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...INVALID_TOPICS_DATA }); + + expect(request.url).to.not.include('segtax'); + expect(request.url).to.not.include('segclass'); + expect(request.url).to.not.include('segments'); + }); + }); }); describe('interpretResponse', () => { From ecb92186a8b48ad8b57c2d4d869dba55c45504f1 Mon Sep 17 00:00:00 2001 From: Nick Llerandi Date: Tue, 30 Apr 2024 12:13:53 -0400 Subject: [PATCH 073/147] Kargo Bid Adapter: test spec overhaul (#11417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * KRKPD-1083: Refactor and expand testing (#31) * Refactor the Kargo adapter testing to be more comprehensive and include testing of invalid inputs * Fix the window size test to pull data from the browser instead of hardcoded values * Remove a duplicate test * unhook triggerPixel after tests * fixes circleci failure * Update the localStorage non-functional test In FireFox, having localStorage.getItem throw an error isn't working so the test was updated to not have a valid localStorage value to pass on FireFox. * Restore the bidderSettings following testing --------- Co-authored-by: William Klausmeyer Co-authored-by: “Nick <“nick.llerandi”@kargo.com> Co-authored-by: William Klausmeyer --- test/spec/modules/kargoBidAdapter_spec.js | 2659 +++++++++++++-------- 1 file changed, 1725 insertions(+), 934 deletions(-) diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index eb8f310201d..7aa853ad902 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1,461 +1,1485 @@ -import { expect, assert } from 'chai'; +import { expect } from 'chai'; import { spec } from 'modules/kargoBidAdapter.js'; import { config } from 'src/config.js'; const utils = require('src/utils'); -describe('kargo adapter tests', function () { - var sandbox, clock, frozenNow = new Date(); - const testSchain = { - complete: 1, - nodes: [ +describe('kargo adapter tests', function() { + let bid, outstreamBid, testBids, sandbox, clock, frozenNow = new Date(), oldBidderSettings; + + const topUrl = 'https://random.com/this/is/a/url'; + const domain = 'random.com'; + const referer = 'https://random.com/'; + + const defaultBidParams = Object.freeze({ + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + getFloor: () => {}, + ortb2: { + device: { + w: 1720, + h: 1000, + dnt: 0, + language: 'en', + ua: 'Mozilla/5.0' + }, + site: { + domain: domain, + mobile: 0, + page: topUrl, + publisher: { + domain: domain + }, + ref: referer + }, + source: { + tid: 'random-tid' + } + }, + ortb2Imp: { + ext: { + data: { + pbadslot: '/1234/prebid/slot/path' + }, + gpid: '/1234/prebid/slot/path', + } + }, + userId: { + tdid: 'random-tdid' + }, + userIdAsEids: [ + { + source: 'adquery.io', + uids: [ { + id: 'adquery-id', + atype: 1 + } ] + }, + { + source: 'criteo.com', + uids: [ { + id: 'criteo-id', + atype: 1 + } ] + }, { - 'asi': 'test-page.com', - 'hp': 1, - 'rid': '57bdd953-6e57-4d5b-9351-ed67ca238890', - 'sid': '8190248274' + source: 'adserver.org', + uids: [ { + id: 'adserver-id', + atype: 1, + ext: { rtiPartner: 'TDID' } + } ] + }, + ], + floorData: { + floorMin: 1 + }, + schain: { + validation: 'strict', + config: { + ver: '1.0', + complete: 1, + nodes: [ { + asi: 'indirectseller.com', + sid: '00001', + hp: 1, + } ] + } + }, + }); + + const minimumBidParams = Object.freeze({ + params: { + placementId: 'foobar' + }, + mediaTypes: { + banner: { sizes: [ [1, 1] ] } + } + }); + + const validCrbIds = { + 2: '82fa2555-5969-4614-b4ce-4dcf1080e9f9', + 16: 'VoxIk8AoJz0AAEdCeyAAAAC2&502', + 23: 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', + 24: 'VoxIk8AoJz0AAEdCeyAAAAC2&502', + 25: '5ee24138-5e03-4b9d-a953-38e833f2849f', + '2_80': 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', + '2_93': '5ee24138-5e03-4b9d-a953-38e833f2849f' + }; + const validCrbIdsLs = { + 2: '82fa2555-5969-4614-b4ce-4dcf1080e9f9', + 16: 'VoxIk8AoJz0AAEdCeyAAAAC2&502', + 23: 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', + 25: '5ee24138-5e03-4b9d-a953-38e833f2849f', + '2_80': 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', + '2_93': '5ee24138-5e03-4b9d-a953-38e833f2849f' + }; + function buildCrbValue(isCookie, withIds, withTdid, withLexId, withClientId, optOut) { + let value = { + expireTime: Date.now() + 60000, + lastSyncedAt: Date.now() - 60000, + optOut, + }; + const locationString = isCookie ? 'cookie' : 'localstorage'; + + if (withIds) { + if (isCookie) { + value.syncIds = validCrbIds; + } else { + value.syncIds = validCrbIdsLs; } - ] + } + if (withTdid) { + value.tdID = `test-tdid-cerberus-${locationString}`; + } + if (withLexId) { + value.lexId = `test-lexid-cerberus-${locationString}`; + } + if (withClientId) { + value.clientId = `test-clientid-cerberus-${locationString}`; + } + + const b64Value = btoa(JSON.stringify(value)); + if (isCookie) { + return JSON.stringify({ v: b64Value }); + } + return b64Value; } - beforeEach(function () { + beforeEach(function() { + oldBidderSettings = $$PREBID_GLOBAL$$.bidderSettings; + $$PREBID_GLOBAL$$.bidderSettings = { + kargo: { storageAllowed: true } + }; + + bid = { + ...defaultBidParams, + bidder: 'kargo', + params: { + placementId: 'displayPlacement' + }, + mediaTypes: { + banner: { + sizes: [ [970, 250], [1, 1] ] + } + }, + adUnitCode: 'displayAdunitCode', + sizes: [ [300, 250], [300, 600] ], + bidId: 'randomBidId', + bidderRequestId: 'randomBidderRequestId', + auctionId: 'randomAuctionId' + }; + + outstreamBid = { + ...defaultBidParams, + bidder: 'kargo', + params: { + placementId: 'instreamPlacement' + }, + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + api: [ 1, 2 ], + linearity: 1, + maxduration: 60, + mimes: [ 'video/mp4', 'video/webm', 'application/javascript' ], + minduration: 0, + placement: 1, + playbackmethod: [ 1, 2, 3 ], + plcmt: 1, + protocols: [ 2, 3, 5 ], + skip: 1 + } + }, + adUnitCode: 'instreamAdunitCode', + sizes: [ [300, 250], [300, 600] ], + bidId: 'randomBidId2', + bidderRequestId: 'randomBidderRequestId2', + auctionId: 'randomAuctionId2' + }; + + testBids = [{ ...minimumBidParams }]; + sandbox = sinon.sandbox.create(); clock = sinon.useFakeTimers(frozenNow.getTime()); }); - afterEach(function () { + afterEach(function() { sandbox.restore(); clock.restore(); + $$PREBID_GLOBAL$$.bidderSettings = oldBidderSettings; }); - describe('bid request validity', function () { - it('passes when the bid includes a placement ID', function () { - assert(spec.isBidRequestValid({ params: { placementId: 'foo' } }) === true); + describe('gvlid', function() { + it('exposes the gvlid (global vendor list ID) of 972', function() { + expect(spec.gvlid).to.exist.and.equal(972); + }); + }); + + describe('code', function() { + it('exposes the code kargo', function() { + expect(spec.code).to.exist.and.equal('kargo'); + }); + }); + + describe('isBidRequestValid', function() { + it('fails when the bid object is undefined', function() { + expect(spec.isBidRequestValid()).to.equal(false); }); - it('fails when the bid does not include a placement ID', function () { - assert(spec.isBidRequestValid({ params: {} }) === false); + it('fails when the bid object has no keys at all', function() { + expect(spec.isBidRequestValid({})).to.equal(false); }); - it('fails when bid is falsey', function () { - assert(spec.isBidRequestValid() === false); + it('fails when the bid includes params but not a placement ID', function() { + expect(spec.isBidRequestValid({ params: {} })).to.equal(false); }); - it('fails when the bid has no params at all', function () { - assert(spec.isBidRequestValid({}) === false); + it('passes when the bid includes a placement ID', function () { + expect(spec.isBidRequestValid({ params: { placementId: 'foo' } })).to.equal(true); + }); + + it('passes when the bid includes a placement ID and other keys', function() { + expect(spec.isBidRequestValid({ params: { placementId: 'foo', other: 'value' } })).to.equal(true); + }); + + it('passes when the full bid information is provided', function() { + expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(outstreamBid)).to.equal(true); }); }); - describe('build request', function () { - var bids, undefinedCurrency, noAdServerCurrency, nonUSDAdServerCurrency, cookies = [], localStorageItems = [], sessionIds = [], requestCount = 0; + describe('buildRequests', function() { + let bids, + bidderRequest, + undefinedCurrency, + noAdServerCurrency, + nonUSDAdServerCurrency, + cookies = [], + localStorageItems = [], + session_id = null; + + before(function() { + sinon.spy(spec, 'buildRequests'); + }); - beforeEach(function () { - $$PREBID_GLOBAL$$.bidderSettings = { - kargo: { - storageAllowed: true - } - }; + beforeEach(function() { undefinedCurrency = false; noAdServerCurrency = false; nonUSDAdServerCurrency = false; sandbox.stub(config, 'getConfig').callsFake(function (key) { if (key === 'currency') { - if (undefinedCurrency) { - return undefined; - } - if (noAdServerCurrency) { - return {}; - } - if (nonUSDAdServerCurrency) { - return { adServerCurrency: 'EUR' }; - } + if (undefinedCurrency) return undefined; + + if (noAdServerCurrency) return {}; + + if (nonUSDAdServerCurrency) return { adServerCurrency: 'EUR' }; + return { adServerCurrency: 'USD' }; } + if (key === 'debug') return true; if (key === 'deviceAccess') return true; - throw new Error(`Config stub incomplete! Missing key "${key}"`) + throw new Error(`Config stub incomplete, missing key "${key}"`); }); bids = [ - { - params: { - placementId: 'foo', - socialCanvas: { - segments: ['segment_1', 'segment_2', 'segment_3'], - url: 'https://socan.url' - } - }, - auctionId: '1234098', - bidId: '1', - adUnitCode: '101', - sizes: [[320, 50], [300, 250], [300, 600]], - mediaTypes: { - banner: { - sizes: [[320, 50], [300, 50]] - } - }, - bidRequestsCount: 1, - bidderRequestsCount: 2, - bidderWinsCount: 3, - schain: testSchain, - userId: { - tdid: 'ed1562d5-e52b-406f-8e65-e5ab3ed5583c' + bid, + outstreamBid + ]; + + bidderRequest = { + bidderCode: 'kargo', + auctionId: 'test-auction-id', + bidderRequestId: 'test-request-id', + bids, + ortb2: defaultBidParams.ortb2, + refererInfo: { + canonicalUrl: topUrl, + domain, + isAmp: false, + location: topUrl, + numIframs: 0, + page: topUrl, + reachedTop: true, + ref: referer, + stack: [ topUrl ], + topmostLocation: topUrl, + }, + start: Date.now(), + timeout: 2500, + }; + }); + afterEach(function() { + cookies.forEach(key => document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/`); + cookies = []; + + localStorageItems.forEach(key => localStorage.removeItem(key)); + localStorageItems = []; + }); + + function getPayloadFromTestBids(testBids) { + const request = spec.buildRequests(testBids, { ...bidderRequest, bids: testBids }); + const payload = request.data; + if (session_id === null) session_id = spec._getSessionId(); + + expect(payload).to.exist; + expect(payload.imp).to.have.length(testBids.length); + expect(payload.requestCount).to.equal(spec.buildRequests.callCount - 1); + expect(payload.sid).to.equal(session_id); + + return payload; + } + + function setCookieValue(name, value) { + cookies.push(name); + document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; max-age-in-seconds=1000; path=/`; + } + + function setLocalStorageValue(name, value) { + localStorageItems.push(name); + localStorage.setItem(name, value); + } + + const crbValues = { + valid: buildCrbValue(true, true, true, true, true, false), + validLs: buildCrbValue(false, true, true, true, true, false), + invalidB64: 'crbValue', + invalidB64Ls: 'crbValueLs', + invalidJson: 'eyJ0ZXN0OiJ2YWx1ZSJ9', + invalidJsonLs: 'eyJ0ZXN0OiJ2YWx1ZSJ9', + }; + function setCrb( + setCookie = 'valid', + setLocalStorage = 'valid' + ) { + if (crbValues.hasOwnProperty(setCookie)) { + setCookieValue('krg_crb', crbValues[setCookie]); + } + if (crbValues.hasOwnProperty(`${setLocalStorage}Ls`)) { + setLocalStorageValue('krg_crb', crbValues[`${setLocalStorage}Ls`]); + } + } + + it('exists and produces an object', function() { + const request = spec.buildRequests(bids, bidderRequest); + expect(request).to.exist.and.to.be.an('object'); + }); + + it('produces a POST request with a payload', function() { + const request = spec.buildRequests(bids, bidderRequest); + expect(request.method).to.exist.and.equal('POST'); + expect(request.url).to.exist.and.equal('https://krk2.kargo.com/api/v1/prebid'); + + const payload = request.data; + expect(payload).to.exist; + expect(payload.imp).to.have.length(2); + + // Display bid + const bidImp = payload.imp[0]; + expect(bidImp.id).to.equal('randomBidId'); + expect(bidImp.banner).to.deep.equal({ sizes: [ [970, 250], [1, 1] ] }); + expect(bidImp.video).to.be.undefined; + expect(bidImp.bidRequestCount).to.equal(1); + expect(bidImp.bidderRequestCount).to.equal(1); + expect(bidImp.code).to.equal('displayAdunitCode'); + expect(bidImp.ext.ortb2Imp).to.deep.equal(defaultBidParams.ortb2Imp); + expect(bidImp.fpd).to.deep.equal({ gpid: '/1234/prebid/slot/path' }); + expect(bidImp.pid).to.equal('displayPlacement'); + + // Video bid + const videoBidImp = payload.imp[1]; + expect(videoBidImp.id).to.equal('randomBidId2'); + expect(videoBidImp.banner).to.be.undefined; + expect(videoBidImp.video).to.deep.equal(outstreamBid.mediaTypes.video); + expect(videoBidImp.bidRequestCount).to.equal(1); + expect(videoBidImp.bidderRequestCount).to.equal(1); + expect(videoBidImp.code).to.equal('instreamAdunitCode'); + expect(videoBidImp.ext.ortb2Imp).to.deep.equal(defaultBidParams.ortb2Imp); + expect(videoBidImp.fpd).to.deep.equal({ gpid: '/1234/prebid/slot/path' }); + expect(videoBidImp.pid).to.equal('instreamPlacement'); + + // User + expect(payload.user).to.be.an('object'); + expect(payload.user.crbIDs).to.deep.equal({}); + expect(payload.user.data).to.deep.equal([]); + expect(payload.user.sharedIDEids).to.deep.equal(defaultBidParams.userIdAsEids); + + // General keys + expect(payload.aid).to.equal('randomAuctionId'); + expect(payload.device).to.deep.equal({ size: [ window.screen.width, window.screen.height ] }); + expect(payload.ext.ortb2).to.deep.equal(defaultBidParams.ortb2); + expect(payload.pbv).to.equal('$prebid.version$'); + expect(payload.requestCount).to.equal(spec.buildRequests.callCount - 1); + expect(payload.sid).to.be.a('string').with.length(36); + expect(payload.timeout).to.equal(2500); + expect(payload.url).to.equal(topUrl); + expect(payload.ts).to.be.a('number'); + }); + + it('copies the ortb2 object from the first bid request if present', function() { + let payload; + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { + user: { + key: 'value' + } + } + }]); + expect(payload.ext).to.deep.equal({ ortb2: { + user: { key: 'value' } + }}); + + payload = getPayloadFromTestBids(testBids); + expect(payload.ext).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { + user: { + key: 'value' + } + } + }, { + ...minimumBidParams, + ortb2: { + site: { + key2: 'value2' + } + } + }]); + expect(payload.ext).to.deep.equal({ortb2: { + user: { key: 'value' } + }}); + }); + + it('pulls the site category from the first bids ortb2 object', function() { + let payload; + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { site: { cat: 'test-cat' } } + }]); + expect(payload.site).to.deep.equal({ cat: 'test-cat' }); + + payload = getPayloadFromTestBids(testBids); + expect(payload.site).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { site: { cat: 'test-cat' } } + }, { + ...minimumBidParams, + ortb2: { site: { cat: 'test-cat-2' } } + }]); + expect(payload.site).to.deep.equal({ cat: 'test-cat' }); + }); + + it('pulls the schain from the first bid if it is populated', function() { + let payload; + payload = getPayloadFromTestBids(testBids); + expect(payload.schain).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + schain: {} + }, { + ...minimumBidParams, + schain: { + complete: 1, + nodes: [{ + asi: 'test-page.com', + hp: 1, + rid: '57bdd953-6e57-4d5b-9351-ed67ca238890', + sid: '8190248274' + }] + } + }]); + expect(payload.schain).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + schain: { + complete: 1, + nodes: [{ + asi: 'test-page.com', + hp: 1, + rid: '57bdd953-6e57-4d5b-9351-ed67ca238890', + sid: '8190248274' + }] + } + }, { + ...minimumBidParams, + schain: { + complete: 1, + nodes: [{ + asi: 'test-page-2.com', + hp: 1, + rid: 'other-rid', + sid: 'other-sid' + }] + } + }]); + expect(payload.schain).to.deep.equal({ + complete: 1, + nodes: [{ + asi: 'test-page.com', + hp: 1, + rid: '57bdd953-6e57-4d5b-9351-ed67ca238890', + sid: '8190248274' + }] + }); + }); + + it('does not send currency if it is not defined', function() { + undefinedCurrency = true; + let payload = getPayloadFromTestBids(testBids); + expect(payload.cur).to.be.undefined; + }); + + it('does not send currency if it is missing', function() { + noAdServerCurrency = true; + let payload = getPayloadFromTestBids(testBids); + expect(payload.cur).to.be.undefined; + }); + + it('does not send currency if it is USD', function() { + let payload = getPayloadFromTestBids(testBids); + expect(payload.cur).to.be.undefined; + }); + + it('provides the currency if it is not USD', function() { + nonUSDAdServerCurrency = true; + let payload = getPayloadFromTestBids(testBids); + expect(payload.cur).to.equal('EUR'); + }); + + it('provides the social canvas segments and URL if provided', function() { + let payload; + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + }, { + ...minimumBidParams, + params: { + ...minimumBidParams.params, + socialCanvas: { + segments: ['segment_1', 'segment_2', 'segment_3'], + url: 'https://socan.url' + } + } + }]); + expect(payload.socan).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + params: { + ...minimumBidParams.params, + socialCanvas: null + } + }, { + ...minimumBidParams, + params: { + ...minimumBidParams.params, + socialCanvas: { + segments: ['segment_1', 'segment_2', 'segment_3'], + url: 'https://socan.url' + } + } + }]); + expect(payload.socan).to.be.undefined; + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + params: { + ...minimumBidParams.params, + socialCanvas: { + segments: ['segment_1', 'segment_2', 'segment_3'], + url: 'https://socan.url' + } + } + }, { + ...minimumBidParams, + params: { + ...minimumBidParams.params, + socialCanvas: { + segments: ['segment_4', 'segment_5', 'segment_6'], + url: 'https://socan.url/new' + } + } + }]); + expect(payload.socan).to.deep.equal({ + segments: ['segment_1', 'segment_2', 'segment_3'], + url: 'https://socan.url' + }); + }); + + describe('imp', function() { + it('handles slots with different combinations of formats', function() { + const testBids = [ + // Banner and Outstream + { + ...bid, + params: { + inventoryCode: 'banner_outstream_test', + floor: 1.0, + video: { + mimes: [ 'video/mp4' ], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 + } + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 380] + }, + banner: { + sizes: [ [970, 250], [1, 1] ] + } + }, + adUnitCode: 'adunit-code-banner-outstream', + sizes: [ [300, 250], [300, 600], [1, 1, 1], ['flex'] ], + bidId: 'banner-outstream-bid-id', + bidderRequestId: 'kargo-request-id', + auctionId: 'kargo-auction-id', }, - userIdAsEids: [ - { - 'source': 'adserver.org', - 'uids': [ - { - 'id': 'ed1562d5-e52b-406f-8e65-e5ab3ed5583c', - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - } - ] + // Banner and Native + { + ...bid, + params: { + inventoryCode: 'banner_outstream_test', + floor: 1.0, + video: { + mimes: [ 'video/mp4' ], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 + } }, - { - 'source': 'adquery.io', - 'uids': [ - { - 'id': 'adqueryId-123', - 'atype': 1 - } - ] + mediaTypes: { + banner: { + sizes: [ [970, 250], [1, 1] ] + }, + native: {} }, - { - 'source': 'criteo.com', - 'uids': [ - { - 'id': 'criteoId-456', - 'atype': 1 - } - ] - } - ], - floorData: { - floorMin: 1 + adUnitCode: 'adunit-code-banner-outstream', + sizes: [ [300, 250], [300, 600], [1, 1, 1], ['flex'] ], + bidId: 'banner-outstream-bid-id', + bidderRequestId: 'kargo-request-id', + auctionId: 'kargo-auction-id', }, - ortb2: { - device: { - sua: { - platform: { - brand: 'macOS', - version: ['12', '6', '0'] - }, - browsers: [ - { - brand: 'Chromium', - version: ['106', '0', '5249', '119'] - }, - { - brand: 'Google Chrome', - version: ['106', '0', '5249', '119'] - }, - { - brand: 'Not;A=Brand', - version: ['99', '0', '0', '0'] - } - ], - mobile: 1, - model: 'model', - source: 1, + // Native and Outstream + { + ...bid, + params: { + inventoryCode: 'banner_outstream_test', + floor: 1.0, + video: { + mimes: [ 'video/mp4' ], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 } }, - site: { - id: '1234', - name: 'SiteName', - cat: ['IAB1', 'IAB2', 'IAB3'] + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 380] + }, + native: {}, }, - user: { - data: [ - { - name: 'prebid.org', - ext: { - segtax: 600, - segclass: 'v1', - }, - segment: [ - { - id: '133' - }, - ] - }, - ] - } + adUnitCode: 'adunit-code-banner-outstream', + sizes: [ [300, 250], [300, 600], [1, 1, 1], ['flex'] ], + bidId: 'banner-outstream-bid-id', + bidderRequestId: 'kargo-request-id', + auctionId: 'kargo-auction-id', }, - ortb2Imp: { - ext: { - tid: '10101', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' - }, - pbadslot: '/22558409563,18834096/dfy_mobile_adhesion' + // Banner and Native and Outstream + { + ...bid, + params: { + inventoryCode: 'banner_outstream_test', + floor: 1.0, + video: { + mimes: [ 'video/mp4' ], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 + } + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 380] }, - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - } - } - }, - { - params: { - placementId: 'bar' + banner: { + sizes: [ [970, 250], [1, 1] ] + }, + native: {}, + }, + adUnitCode: 'adunit-code-banner-outstream', + sizes: [ [300, 250], [300, 600], [1, 1, 1], ['flex'] ], + bidId: 'banner-outstream-bid-id', + bidderRequestId: 'kargo-request-id', + auctionId: 'kargo-auction-id', }, - bidId: '2', - adUnitCode: '202', - sizes: [[320, 50], [300, 250], [300, 600]], - mediaTypes: { - video: { - sizes: [[320, 50], [300, 50]] + ]; + + const payload = getPayloadFromTestBids(testBids); + + const bannerImp = { + sizes: [ [970, 250], [1, 1] ] + }; + const videoImp = { + context: 'outstream', + playerSize: [640, 380] + }; + const nativeImp = {}; + + // Banner and Outstream + expect(payload.imp[0].banner).to.deep.equal(bannerImp); + expect(payload.imp[0].video).to.deep.equal(videoImp); + expect(payload.imp[0].native).to.be.undefined; + // Banner and Native + expect(payload.imp[1].banner).to.deep.equal(bannerImp); + expect(payload.imp[1].video).to.be.undefined; + expect(payload.imp[1].native).to.deep.equal(nativeImp); + // Native and Outstream + expect(payload.imp[2].banner).to.be.undefined; + expect(payload.imp[2].video).to.deep.equal(videoImp); + expect(payload.imp[2].native).to.deep.equal(nativeImp); + // Banner and Native and Outstream + expect(payload.imp[3].banner).to.deep.equal(bannerImp); + expect(payload.imp[3].video).to.deep.equal(videoImp); + expect(payload.imp[3].native).to.deep.equal(nativeImp); + }); + + it('pulls gpid from ortb2Imp.ext.gpid then ortb2Imp.ext.data.pbadslot', function () { + const gpidGpid = 'ortb2Imp.ext.gpid-gpid'; + const gpidPbadslot = 'ortb2Imp.ext.data.pbadslot-gpid' + const testBids = [ + { + ...minimumBidParams, + ortb2Imp: { + ext: { + gpid: gpidGpid, + data: { + pbadslot: gpidPbadslot + } + } } }, - bidRequestsCount: 0, - bidderRequestsCount: 0, - bidderWinsCount: 0, - ortb2Imp: { - ext: { - tid: '20202', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' - }, - pbadslot: '/22558409563,18834096/dfy_mobile_adhesion' + { + ...minimumBidParams, + ortb2Imp: { + ext: { + gpid: gpidGpid, + data: {}, } } - } - }, - { - params: { - placementId: 'bar' }, - bidId: '3', - adUnitCode: '303', - sizes: [[320, 50], [300, 250], [300, 600]], - mediaTypes: { - native: { - sizes: [[320, 50], [300, 50]] + { + ...minimumBidParams, + ortb2Imp: { + ext: { + data: { + pbadslot: gpidPbadslot + } + } } }, - ortb2Imp: { - ext: { - tid: '30303', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' + { + ...minimumBidParams, + ortb2Imp: { + ext: { + gpid: null, + data: { + pbadslot: null } - }, - gpid: '/22558409563,18834096/dfy_mobile_adhesion' + } } - } + }, + { ...minimumBidParams } + ]; + + const payload = getPayloadFromTestBids(testBids); + + // Both present + expect(payload.imp[0].fpd).to.deep.equal({ gpid: gpidGpid }); + // Only ext.gpid + expect(payload.imp[1].fpd).to.deep.equal({ gpid: gpidGpid }); + // Only ext.data.pbadslot + expect(payload.imp[2].fpd).to.deep.equal({ gpid: gpidPbadslot }); + // Neither present + expect(payload.imp[3].fpd).to.be.undefined; + expect(payload.imp[4].fpd).to.be.undefined; + }); + + it('includes bidRequestCount, bidderRequestCount, and bidderWinsCount if they are greater than 0', function() { + const testBids = [ + { + ...minimumBidParams, + bidRequestsCount: 1, + bidderRequestsCount: 0, + bidderWinsCount: 0, + }, + { + ...minimumBidParams, + bidRequestsCount: 0, + bidderRequestsCount: 2, + bidderWinsCount: 0, + }, + { + ...minimumBidParams, + bidRequestsCount: 0, + bidderRequestsCount: 0, + bidderWinsCount: 3, + }, + { + ...minimumBidParams, + bidRequestsCount: 4, + bidderRequestsCount: 1, + bidderWinsCount: 3, + }, + ]; + + [ 0, null, false, 'foobar' ].forEach(value => testBids.push({ + ...minimumBidParams, + bidRequestsCount: value, + bidderRequestsCount: value, + bidderWinsCount: value + })); + + const payload = getPayloadFromTestBids(testBids); + + // bidRequestCount + expect(payload.imp[0].bidRequestCount).to.equal(1); + expect(payload.imp[0].bidderRequestCount).to.be.undefined; + expect(payload.imp[0].bidderWinCount).to.be.undefined; + // bidderRequestCount + expect(payload.imp[1].bidRequestCount).to.be.undefined; + expect(payload.imp[1].bidderRequestCount).to.equal(2); + expect(payload.imp[1].bidderWinCount).to.be.undefined; + // bidderWinCount + expect(payload.imp[2].bidRequestCount).to.be.undefined; + expect(payload.imp[2].bidderRequestCount).to.be.undefined; + expect(payload.imp[2].bidderWinCount).to.equal(3); + // all + expect(payload.imp[3].bidRequestCount).to.equal(4); + expect(payload.imp[3].bidderRequestCount).to.equal(1); + expect(payload.imp[3].bidderWinCount).to.equal(3); + // none + for (let i = 4; i < payload.imp.length; i++) { + expect(payload.imp[i].bidRequestCount).to.be.undefined; + expect(payload.imp[i].bidderRequestCount).to.be.undefined; + expect(payload.imp[i].bidderWinCount).to.be.undefined; } - ]; - }); + }); - afterEach(function () { - for (let key in cookies) { - let cookie = cookies[key]; - removeCookie(cookie); - } + it('queries the getFloor function to retrieve the floor and validates it', function() { + const testBids = []; + + [ + { currency: 'USD', floor: 1.99 }, + { currency: 'USD', floor: '1.99' }, + { currency: 'EUR', floor: 1.99 }, + { currency: 'USD', floor: 'foo' }, + { currency: 'USD', floor: null }, + { currency: 'USD', floor: true }, + { currency: 'USD', floor: false }, + { currency: 'USD', floor: {} }, + { currency: 'USD', floor: [] }, + ].forEach(floorValue => testBids.push({ + ...minimumBidParams, + getFloor: () => floorValue + })); + + const payload = getPayloadFromTestBids(testBids); + + // Valid floor + expect(payload.imp[0].floor).to.equal(1.99); + // Valid floor but string + expect(payload.imp[1].floor).to.equal('1.99'); // @TODO - convert this to a number? + // Non-USD valid floor + expect(payload.imp[2].floor).to.be.undefined; + // Invalid floor + for (let i = 3; i < payload.imp.length; i++) { + expect(payload.imp[i].floor).to.be.undefined; + } + }); - for (let key in localStorageItems) { - let localStorageItem = localStorageItems[key]; - localStorage.removeItem(localStorageItem); - } + it('calls getFloor with the right values', function() { + const testBids = [ + { + ...minimumBidParams, + getFloor: () => ({ currency: 'USD', value: 0.5 }) + } + ]; + sinon.spy(testBids[0], 'getFloor'); - cookies.length = 0; - localStorageItems.length = 0; - $$PREBID_GLOBAL$$.bidderSettings = {}; + getPayloadFromTestBids(testBids); + + expect(testBids[0].getFloor.calledWith({ + currency: 'USD', + mediaType: '*', + size: '*' + })).to.be.true; + }); }); - function setCookie(cname, cvalue, exdays = 1) { - _setCookie(cname, cvalue, exdays); - cookies.push(cname); - } + describe('cerberus', function() { + it('retrieves CRB from localStorage and cookies', function() { + setCrb('valid', 'valid'); - function removeCookie(cname) { - _setCookie(cname, '', -1); - } + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function _setCookie(cname, cvalue, exdays = 1) { - var d = new Date(), - expires; + expect(payload.rawCRB).to.equal(crbValues.valid); + expect(payload.rawCRBLocalStorage).to.equal(crbValues.validLs); + expect(payload.user.crbIDs).to.deep.equal(validCrbIdsLs); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-localstorage'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-localstorage'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-localstorage'); + expect(payload.user.optOut).to.equal(false); + }); - d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); - expires = `expires=${d.toUTCString()}`; - document.cookie = `${cname}=${cvalue};${expires};path=/`; - } + it('retrieves CRB from localStorage if cookie is missing', function() { + setCrb(false, 'valid'); - function setLocalStorageItem(name, val) { - localStorage.setItem(name, val); - localStorageItems.push(name); - } + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function simulateNoLocalStorage() { - return sandbox.stub(localStorage, 'getItem').throws(); - } + expect(payload.rawCRB).to.be.undefined; + expect(payload.rawCRBLocalStorage).to.equal(crbValues.validLs); + expect(payload.user.crbIDs).to.deep.equal(validCrbIdsLs); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-localstorage'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-localstorage'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-localstorage'); + expect(payload.user.optOut).to.equal(false); + }); - function simulateNoCurrencyObject() { - undefinedCurrency = true; - noAdServerCurrency = false; - nonUSDAdServerCurrency = false; - } + it('retrieves CRB from cookies if localstorage is missing', function() { + setCrb('valid', false); - function simulateNoAdServerCurrency() { - undefinedCurrency = false; - noAdServerCurrency = true; - nonUSDAdServerCurrency = false; - } + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function simulateNonUSDAdServerCurrency() { - undefinedCurrency = false; - noAdServerCurrency = false; - nonUSDAdServerCurrency = true; - } + expect(payload.rawCRB).to.equal(crbValues.valid); + expect(payload.rawCRBLocalStorage).to.be.undefined; + expect(payload.user.crbIDs).to.deep.equal(validCrbIds); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-cookie'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-cookie'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-cookie'); + expect(payload.user.optOut).to.equal(false); + }); - function generateGDPR(applies, haveConsent) { - var data = { - consentString: 'gdprconsentstring', - gdprApplies: applies, - }; - return data; - } + it('retrieves CRB from cookies if localstorage is not functional', function() { + // Note: this does not cause localStorage to throw an error in Firefox so in that browser this + // test is not 100% true to its name + sandbox.stub(localStorage, 'getItem').throws(); + setCrb('valid', 'invalid'); + + const payload = getPayloadFromTestBids(testBids, bidderRequest); + + expect(payload.rawCRB).to.equal(crbValues.valid); + expect(payload.rawCRBLocalStorage).to.be.undefined; + expect(payload.user.crbIDs).to.deep.equal(validCrbIds); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-cookie'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-cookie'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-cookie'); + expect(payload.user.optOut).to.equal(false); + }); - function generateGDPRExpect(applies, haveConsent) { - return { - consent: 'gdprconsentstring', - applies: applies, - }; - } + it('does not fail if CRB is missing', function() { + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function generatePageView() { - return { - id: '112233', - timestamp: frozenNow.getTime(), - url: 'http://pageview.url' - } - } + expect(payload.rawCRB).to.be.undefined; + expect(payload.rawCRBLocalStorage).to.be.undefined; + expect(payload.user.crbIDs).to.deep.equal({}); + expect(payload.user.tdID).to.be.undefined; + expect(payload.user.kargoID).to.be.undefined; + expect(payload.user.clientID).to.be.undefined; + expect(payload.user.optOut).to.be.undefined; + }); - function generateRawCRB(rawCRB, rawCRBLocalStorage) { - if (rawCRB == null && rawCRBLocalStorage == null) { - return null - } + it('fails gracefully if the CRB is invalid base 64 cookie', function() { + setCrb('invalidB64', false); - let result = {} + const payload = getPayloadFromTestBids(testBids, bidderRequest); - if (rawCRB != null) { - result.rawCRB = rawCRB - } + expect(payload.rawCRB).to.equal(crbValues.invalidB64); + expect(payload.rawCRBLocalStorage).to.be.undefined; + expect(payload.user.crbIDs).to.deep.equal({}); + expect(payload.user.tdID).to.be.undefined; + expect(payload.user.kargoID).to.be.undefined; + expect(payload.user.clientID).to.be.undefined; + expect(payload.user.optOut).to.be.undefined; + }); - if (rawCRBLocalStorage != null) { - result.rawCRBLocalStorage = rawCRBLocalStorage - } + it('fails gracefully if the CRB is invalid base 64 localStorage', function() { + setCrb(false, 'invalidB64'); - return result - } + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function getKrgCrb() { - return 'eyJzeW5jSWRzIjp7IjIiOiI4MmZhMjU1NS01OTY5LTQ2MTQtYjRjZS00ZGNmMTA4MGU5ZjkiLCIxNiI6IlZveElrOEFvSnowQUFFZENleUFBQUFDMiY1MDIiLCIyMyI6ImQyYTg1NWE1LTFiMWMtNDMwMC05NDBlLWE3MDhmYTFmMWJkZSIsIjI0IjoiVm94SWs4QW9KejBBQUVkQ2V5QUFBQUMyJjUwMiIsIjI1IjoiNWVlMjQxMzgtNWUwMy00YjlkLWE5NTMtMzhlODMzZjI4NDlmIiwiMl84MCI6ImQyYTg1NWE1LTFiMWMtNDMwMC05NDBlLWE3MDhmYTFmMWJkZSIsIjJfOTMiOiI1ZWUyNDEzOC01ZTAzLTRiOWQtYTk1My0zOGU4MzNmMjg0OWYifSwibGV4SWQiOiI1ZjEwODgzMS0zMDJkLTExZTctYmY2Yi00NTk1YWNkM2JmNmMiLCJjbGllbnRJZCI6IjI0MTBkOGYyLWMxMTEtNDgxMS04OGE1LTdiNWUxOTBlNDc1ZiIsIm9wdE91dCI6ZmFsc2UsImV4cGlyZVRpbWUiOjE0OTc0NDkzODI2NjgsImxhc3RTeW5jZWRBdCI6MTQ5NzM2Mjk3OTAxMn0='; - } + expect(payload.rawCRB).to.be.undefined; + expect(payload.rawCRBLocalStorage).to.equal(crbValues.invalidB64Ls); + expect(payload.user.crbIDs).to.deep.equal({}); + expect(payload.user.tdID).to.be.undefined; + expect(payload.user.kargoID).to.be.undefined; + expect(payload.user.clientID).to.be.undefined; + expect(payload.user.optOut).to.be.undefined; + }); - function getKrgCrbOldStyle() { - return '{"v":"eyJzeW5jSWRzIjp7IjIiOiI4MmZhMjU1NS01OTY5LTQ2MTQtYjRjZS00ZGNmMTA4MGU5ZjkiLCIxNiI6IlZveElrOEFvSnowQUFFZENleUFBQUFDMiY1MDIiLCIyMyI6ImQyYTg1NWE1LTFiMWMtNDMwMC05NDBlLWE3MDhmYTFmMWJkZSIsIjI0IjoiVm94SWs4QW9KejBBQUVkQ2V5QUFBQUMyJjUwMiIsIjI1IjoiNWVlMjQxMzgtNWUwMy00YjlkLWE5NTMtMzhlODMzZjI4NDlmIiwiMl84MCI6ImQyYTg1NWE1LTFiMWMtNDMwMC05NDBlLWE3MDhmYTFmMWJkZSIsIjJfOTMiOiI1ZWUyNDEzOC01ZTAzLTRiOWQtYTk1My0zOGU4MzNmMjg0OWYifSwibGV4SWQiOiI1ZjEwODgzMS0zMDJkLTExZTctYmY2Yi00NTk1YWNkM2JmNmMiLCJjbGllbnRJZCI6IjI0MTBkOGYyLWMxMTEtNDgxMS04OGE1LTdiNWUxOTBlNDc1ZiIsIm9wdE91dCI6ZmFsc2UsImV4cGlyZVRpbWUiOjE0OTc0NDkzODI2NjgsImxhc3RTeW5jZWRBdCI6MTQ5NzM2Mjk3OTAxMn0="}'; - } + [ + [ 'valid', 'invalidB64', 'cookie' ], + [ 'valid', 'invalidJson', 'cookie' ], + [ 'invalidB64', 'invalidJson', 'none' ], + [ 'invalidB64', 'invalidB64', 'none' ], + [ 'invalidB64', 'valid', 'localStorage' ], + [ 'invalidJson', 'invalidJson', 'none' ], + [ 'invalidJson', 'invalidB64', 'none' ], + [ 'invalidJson', 'valid', 'localStorage' ], + ].forEach(config => { + it(`uses ${config[2]} if the cookie is ${config[0]} and localStorage is ${config[1]}`, function() { + setCrb(config[0], config[1]); + const payload = getPayloadFromTestBids(testBids, bidderRequest); + + expect(payload.rawCRB).to.equal(crbValues[config[0]]); + expect(payload.rawCRBLocalStorage).to.equal(crbValues[`${config[1]}Ls`]); + if (config[2] === 'cookie') { + expect(payload.user.crbIDs).to.deep.equal(validCrbIds); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-cookie'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-cookie'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-cookie'); + expect(payload.user.optOut).to.equal(false); + } else if (config[2] === 'localStorage') { + expect(payload.user.crbIDs).to.deep.equal(validCrbIdsLs); + expect(payload.user.tdID).to.equal('test-tdid-cerberus-localstorage'); + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-localstorage'); + expect(payload.user.clientID).to.equal('test-clientid-cerberus-localstorage'); + expect(payload.user.optOut).to.equal(false); + } else { + expect(payload.user.crbIDs).to.deep.equal({}); + expect(payload.user.tdID).to.be.undefined; + expect(payload.user.kargoID).to.be.undefined; + expect(payload.user.clientID).to.be.undefined; + expect(payload.user.optOut).to.be.undefined; + } + }); + }); - function initializeKrgCrb(cookieOnly) { - if (!cookieOnly) { - setLocalStorageItem('krg_crb', getKrgCrb()); - } - setCookie('krg_crb', getKrgCrbOldStyle()); - } + it('uses the tdID from cerberus to populate the tdID field', function() { + setCrb('valid', 'valid'); + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function getInvalidKrgCrbType1() { - return 'invalid-krg-crb'; - } + expect(payload.user.tdID).to.equal('test-tdid-cerberus-localstorage'); + }); - function initializeInvalidKrgCrbType1() { - setLocalStorageItem('krg_crb', getInvalidKrgCrbType1()); - } + it('uses the lexId from cerberus to populate the kargoID field', function() { + setCrb('valid', 'valid'); + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function initializeInvalidKrgCrbType1Cookie() { - setCookie('krg_crb', getInvalidKrgCrbType1()); - } + expect(payload.user.kargoID).to.equal('test-lexid-cerberus-localstorage'); + }); - function getInvalidKrgCrbType2() { - return 'Ly8v'; - } + it('uses the clientId from cerberus to populate the clientID field', function() { + setCrb('valid', 'valid'); + const payload = getPayloadFromTestBids(testBids, bidderRequest); - function getInvalidKrgCrbType2OldStyle() { - return '{"v":"&&&&&&"}'; - } + expect(payload.user.clientID).to.equal('test-clientid-cerberus-localstorage'); + }); - function initializeInvalidKrgCrbType2() { - setLocalStorageItem('krg_crb', getInvalidKrgCrbType2()); - } + it('uses the optOut from cerberus to populate the clientID field', function() { + setCrb('valid', 'valid'); + let payload; + payload = getPayloadFromTestBids(testBids, bidderRequest); - function initializeInvalidKrgCrbType2Cookie() { - setCookie('krg_crb', getInvalidKrgCrbType2OldStyle()); - } + expect(payload.user.optOut).to.equal(false); - function getInvalidKrgCrbType3OldStyle() { - return '{"v":"Ly8v"}'; - } + setLocalStorageValue('krg_crb', buildCrbValue(false, true, true, true, true, true)); + payload = getPayloadFromTestBids(testBids, bidderRequest); - function initializeInvalidKrgCrbType3Cookie() { - setCookie('krg_crb', getInvalidKrgCrbType3OldStyle()); - } + expect(payload.user.optOut).to.equal(true); + }); + }); - function getInvalidKrgCrbType4OldStyle() { - return '{"v":"bnVsbA=="}'; - } + describe('user', function() { + it('fetches the trade desk id from the adapter if present', function() { + const payload = getPayloadFromTestBids([{ + ...minimumBidParams, + userId: { + tdid: 'test-tdid-module' + } + }]); - function initializeInvalidKrgCrbType4Cookie() { - setCookie('krg_crb', getInvalidKrgCrbType4OldStyle()); - } + expect(payload.user.tdID).to.equal('test-tdid-module'); + }); - function getEmptyKrgCrb() { - return 'eyJleHBpcmVUaW1lIjoxNDk3NDQ5MzgyNjY4LCJsYXN0U3luY2VkQXQiOjE0OTczNjI5NzkwMTJ9'; - } + it('fetches the trade desk id from cerberus if present', function() { + setLocalStorageValue('krg_crb', btoa(JSON.stringify({ tdID: 'test-tdid-crb' }))); - function getEmptyKrgCrbOldStyle() { - return '{"v":"eyJleHBpcmVUaW1lIjoxNDk3NDQ5MzgyNjY4LCJsYXN0U3luY2VkQXQiOjE0OTczNjI5NzkwMTJ9"}'; - } + const payload = getPayloadFromTestBids([{ + ...minimumBidParams, + }]); - function initializeEmptyKrgCrb() { - setLocalStorageItem('krg_crb', getEmptyKrgCrb()); - } + expect(payload.user.tdID).to.equal('test-tdid-crb'); + }); - function initializePageView() { - setLocalStorageItem('pageViewId', 112233); - setLocalStorageItem('pageViewTimestamp', frozenNow.getTime()); - setLocalStorageItem('pageViewUrl', 'http://pageview.url'); - } + it('fetches the trade desk id from the adapter if adapter and cerberus are present', function() { + setLocalStorageValue('krg_crb', buildCrbValue(false, true, true, true, true, false)); - function initializeEmptyKrgCrbCookie() { - setCookie('krg_crb', getEmptyKrgCrbOldStyle()); - } + const payload = getPayloadFromTestBids([{ + ...minimumBidParams, + userId: { + tdid: 'test-tdid-module' + } + }]); + + expect(payload.user.tdID).to.equal('test-tdid-module'); + }); + + it('does not set kargoId if it is not present', function() { + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.lexId).to.be.undefined; + }); + + it('does not populate usp, gdpr, or gpp if they are not present', function() { + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.usp).to.be.undefined; + expect(payload.user.gdpr).to.be.undefined; + expect(payload.user.gpp).to.be.undefined; + }); + + it('fetches usp from the bidder request if present', function() { + bidderRequest.uspConsent = '1---'; + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.usp).to.equal('1---'); + }); + + it('fetches gpp from the bidder request if present', function() { + bidderRequest.gppConsent = { + consentString: 'gppString', + applicableSections: [-1] + }; + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.gpp).to.deep.equal({ + gppString: 'gppString', + applicableSections: [-1] + }); + }); + + it('does not send empty gpp values', function() { + bidderRequest.gppConsent = { + consentString: '', + applicableSections: '' + }; + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.gpp).to.be.undefined; + }); + + it('fetches gdpr consent from the bidder request if present', function() { + bidderRequest.gdprConsent = { + consentString: 'gdpr-consent-string', + gdprApplies: true + }; + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + + expect(payload.user.gdpr).to.deep.equal({ + consent: 'gdpr-consent-string', + applies: true + }); + }); + + it('handles malformed gdpr applies from the bidder request', function() { + [ + ['true', true], + ['false', true], + ['1', true], + [1, true], + [0, false], + ['0', true], + ['y', true], + ['yes', true], + ['n', true], + ['no', true], + [null, false], + [{}, true], + ].forEach(testValue => { + bidderRequest.gdprConsent = { gdprApplies: testValue[0] }; + const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); + expect(payload.user.gdpr, `Value - ${JSON.stringify(testValue[0])}`).to.deep.equal({ + consent: '', + applies: testValue[1] + }); + }); + }); + + it('passes the user.data from the first bid request if availabale', function() { + let payload; + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + }, { + ...minimumBidParams, + ortb2: { user: { data: { test: 'value' } } } + }]); + expect(payload.user.data).to.deep.equal([]); + + payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { user: { data: { test: 'value' } } } + }, { + ...minimumBidParams, + ortb2: { user: { data: { test2: 'value2' } } } + }]); + expect(payload.user.data).to.deep.equal({ + test: 'value' + }); + }); + + it('fails gracefully if there is no localStorage', function() { + sandbox.stub(localStorage, 'getItem').throws(); + let payload = getPayloadFromTestBids(testBids); + expect(payload.user).to.deep.equal({ + crbIDs: {}, + data: [] + }); + }); + }); + + describe('sua', function() { + it('is not provided if not present in the first valid bid', function() { + let payload = getPayloadFromTestBids([ + ...testBids, + { + ...minimumBidParams, + ortb2: { device: { sua: { + platform: { + brand: 'macOS', + version: ['12', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + } } } + } + ]); + expect(payload.device.sua).to.be.undefined; + }); + + it('is provided if present in the first valid bid', function() { + let payload = getPayloadFromTestBids([ + { + ...minimumBidParams, + ortb2: { device: { sua: { + platform: { + brand: 'macOS', + version: ['12', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + } } } + }, + { + ...minimumBidParams, + ortb2: { device: { sua: { + platform: { + brand: 'macOS2', + version: ['122', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium2', + version: ['1062', '0', '5249', '119'] + }, + { + brand: 'Google Chrome2', + version: ['102', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand2', + version: ['992', '0', '0', '0'] + } + ], + mobile: 2, + model: 'model2', + source: 2, + } } } + } + ]); + expect(payload.device.sua).to.deep.equal({ + platform: { + brand: 'macOS', + version: ['12', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + }); + }); + + it('does not send non-mapped attributes', function() { + let payload = getPayloadFromTestBids([{...minimumBidParams, + ortb2: { device: { sua: { + other: 'value', + objectMissing: { + key: 'value' + }, + platform: { + brand: 'macOS', + version: ['12', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + } } } + }]); + expect(payload.device.sua).to.deep.equal({ + platform: { + brand: 'macOS', + version: ['12', '6', '0'] + }, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + }); + }); - function getSessionId() { - return spec._getSessionId(); - } + it('does not send non-truthy values or empty strings', function() { + [ + false, + 0, + null, + '', + ' ', + ' ', + ].forEach(value => { + let payload = getPayloadFromTestBids([{...minimumBidParams, + ortb2: { device: { sua: { + platform: value, + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + } } } + }]); + expect(payload.device.sua, `Value - ${JSON.stringify(value)}`).to.deep.equal({ + browsers: [ + { + brand: 'Chromium', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] + }, + { + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] + } + ], + mobile: 1, + model: 'model', + source: 1, + }); + }); + }); - function getExpectedKrakenParams(expectedCRB, expectedPage, excludeUserIds, expectedGDPR, currency) { - var base = { - pbv: '$prebid.version$', - aid: '1234098', - requestCount: 0, - sid: getSessionId(), - url: 'https://www.prebid.org', - timeout: 200, - ts: frozenNow.getTime(), - schain: testSchain, - device: { - size: [ - screen.width, - screen.height - ], - sua: { + it('does not send 0 for mobile or source', function() { + let payload = getPayloadFromTestBids([{ + ...minimumBidParams, + ortb2: { device: { sua: { platform: { brand: 'macOS', version: ['12', '6', '0'] @@ -474,506 +1498,217 @@ describe('kargo adapter tests', function () { version: ['99', '0', '0', '0'] } ], - mobile: 1, + mobile: 0, model: 'model', - source: 1 - }, - }, - site: { - cat: ['IAB1', 'IAB2', 'IAB3'] - }, - imp: [ - { - code: '101', - id: '1', - pid: 'foo', - tid: '10101', - banner: { - sizes: [[320, 50], [300, 50]] - }, - bidRequestCount: 1, - bidderRequestCount: 2, - bidderWinCount: 3, - floor: 1, - fpd: { - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - }, - ext: { - ortb2Imp: { - ext: { - tid: '10101', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' - }, - pbadslot: '/22558409563,18834096/dfy_mobile_adhesion' - }, - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - } - } - } - }, - { - code: '202', - id: '2', - pid: 'bar', - tid: '20202', - video: { - sizes: [[320, 50], [300, 50]] - }, - fpd: { - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - }, - floor: 2, - ext: { - ortb2Imp: { - ext: { - tid: '20202', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' - }, - pbadslot: '/22558409563,18834096/dfy_mobile_adhesion' - } - } - } - } - }, - { - code: '303', - id: '3', - pid: 'bar', - tid: '30303', - native: { - sizes: [[320, 50], [300, 50]] - }, - fpd: { - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - }, - floor: 3, - ext: { - ortb2Imp: { - ext: { - tid: '30303', - data: { - adServer: { - name: 'gam', - adslot: '/22558409563,18834096/dfy_mobile_adhesion' - } - }, - gpid: '/22558409563,18834096/dfy_mobile_adhesion' - } - } - } - } - ], - socan: { - segments: ['segment_1', 'segment_2', 'segment_3'], - url: 'https://socan.url' - }, - user: { - kargoID: '5f108831-302d-11e7-bf6b-4595acd3bf6c', - clientID: '2410d8f2-c111-4811-88a5-7b5e190e475f', - tdID: 'ed1562d5-e52b-406f-8e65-e5ab3ed5583c', - crbIDs: { - 2: '82fa2555-5969-4614-b4ce-4dcf1080e9f9', - 16: 'VoxIk8AoJz0AAEdCeyAAAAC2&502', - 23: 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', - 24: 'VoxIk8AoJz0AAEdCeyAAAAC2&502', - 25: '5ee24138-5e03-4b9d-a953-38e833f2849f', - '2_80': 'd2a855a5-1b1c-4300-940e-a708fa1f1bde', - '2_93': '5ee24138-5e03-4b9d-a953-38e833f2849f' + source: 0, + } } } + }]); + expect(payload.device.sua).to.deep.equal({ + platform: { + brand: 'macOS', + version: ['12', '6', '0'] }, - optOut: false, - usp: '1---', - sharedIDEids: [ + browsers: [ { - source: 'adserver.org', - uids: [ - { - id: 'ed1562d5-e52b-406f-8e65-e5ab3ed5583c', - atype: 1, - ext: { - rtiPartner: 'TDID' - } - } - ] + brand: 'Chromium', + version: ['106', '0', '5249', '119'] }, { - source: 'adquery.io', - uids: [ - { - id: 'adqueryId-123', - atype: 1 - } - ] + brand: 'Google Chrome', + version: ['106', '0', '5249', '119'] }, { - source: 'criteo.com', - uids: [ - { - id: 'criteoId-456', - atype: 1 - } - ] + brand: 'Not;A=Brand', + version: ['99', '0', '0', '0'] } ], - data: [ - { - name: 'prebid.org', - ext: { - segtax: 600, - segclass: 'v1', - }, - segment: [ - { - id: '133' - } - ] - } - ] - }, - ext: { - ortb2: { - device: { - sua: { - platform: { - brand: 'macOS', - version: ['12', '6', '0'] - }, - browsers: [ - { - brand: 'Chromium', - version: ['106', '0', '5249', '119'] - }, - { - brand: 'Google Chrome', - version: ['106', '0', '5249', '119'] - }, - { - brand: 'Not;A=Brand', - version: ['99', '0', '0', '0'] - } - ], - mobile: 1, - model: 'model', - source: 1, - } - }, - site: { - id: '1234', - name: 'SiteName', - cat: ['IAB1', 'IAB2', 'IAB3'] - }, - user: { - data: [ - { - name: 'prebid.org', - ext: { - segtax: 600, - segclass: 'v1', - }, - segment: [ - { - id: '133' - }, - ] - }, - ] - } - } - } - }; - - if (excludeUserIds) { - base.user.crbIDs = {}; - delete base.user.clientID; - delete base.user.kargoID; - delete base.user.optOut; - } - - if (expectedGDPR) { - base.user.gdpr = expectedGDPR; - } - - if (expectedPage) { - base.page = expectedPage; - } + model: 'model', + }); + }); + }); - if (currency) { - base.cur = currency; - } + describe('page', function() { + it('pulls the page ID from localStorage', function() { + setLocalStorageValue('pageViewId', 'test-page-id'); + let payload = getPayloadFromTestBids(testBids); + expect(payload.page).to.deep.equal({ + id: 'test-page-id' + }); + }); - const reqCount = requestCount++; - base.requestCount = reqCount + it('pulls the page timestamp from localStorage', function() { + setLocalStorageValue('pageViewTimestamp', '123456789'); + let payload = getPayloadFromTestBids(testBids); + expect(payload.page).to.deep.equal({ + timestamp: 123456789 + }); + }); - if (expectedCRB != null) { - if (expectedCRB.rawCRB != null) { - base.rawCRB = expectedCRB.rawCRB - } - if (expectedCRB.rawCRBLocalStorage != null) { - base.rawCRBLocalStorage = expectedCRB.rawCRBLocalStorage - } - } + it('pulls the page ID from localStorage', function() { + setLocalStorageValue('pageViewUrl', 'https://test-url.com'); + let payload = getPayloadFromTestBids(testBids); + expect(payload.page).to.deep.equal({ + url: 'https://test-url.com' + }); + }); - return base; - } + it('pulls all 3 together', function() { + setLocalStorageValue('pageViewId', 'test-page-id'); + setLocalStorageValue('pageViewTimestamp', '123456789'); + setLocalStorageValue('pageViewUrl', 'https://test-url.com'); + let payload = getPayloadFromTestBids(testBids); + expect(payload.page).to.deep.equal({ + id: 'test-page-id', + timestamp: 123456789, + url: 'https://test-url.com' + }); + }); - function testBuildRequests(expected, gdpr) { - var clonedBids = JSON.parse(JSON.stringify(bids)); + it('fails gracefully without localStorage', function() { + sandbox.stub(localStorage, 'getItem').throws(); + let payload = getPayloadFromTestBids(testBids); + expect(payload.page).to.be.undefined; + }); + }); + }); - var payload = { - timeout: 200, - uspConsent: '1---', - refererInfo: { - page: 'https://www.prebid.org', + describe('interpretResponse', function() { + const response = Object.freeze({ body: { + 1: { + id: 'foo', + cpm: 3, + adm: '
', + width: 320, + height: 50, + metadata: {}, + creativeID: 'bar' + }, + 2: { + id: 'bar', + cpm: 2.5, + adm: '
', + width: 300, + height: 250, + targetingCustom: 'dmpmptest1234', + metadata: { + landingPageDomain: ['https://foobar.com'] }, - }; - - if (gdpr) { - payload['gdprConsent'] = gdpr + creativeID: 'foo' + }, + 3: { + id: 'bar', + cpm: 2.5, + adm: '
', + width: 300, + height: 250, + creativeID: 'foo' + }, + 4: { + id: 'bar', + cpm: 2.5, + adm: '
', + width: 300, + height: 250, + mediaType: 'banner', + metadata: {}, + creativeID: 'foo', + currency: 'EUR' + }, + 5: { + id: 'bar', + cpm: 2.5, + adm: '', + width: 300, + height: 250, + mediaType: 'video', + metadata: {}, + creativeID: 'foo', + currency: 'EUR' + }, + 6: { + id: 'bar', + cpm: 2.5, + adm: '', + admUrl: 'https://foobar.com/vast_adm', + width: 300, + height: 250, + mediaType: 'video', + metadata: {}, + creativeID: 'foo', + currency: 'EUR' } - - clonedBids.forEach(bid => { - if (bid.mediaTypes.banner) { - bid.getFloor = () => ({ currency: 'USD', floor: 1 }); - } else if (bid.mediaTypes.video) { - bid.getFloor = () => ({ currency: 'USD', floor: 2 }); - } else if (bid.mediaTypes.native) { - bid.getFloor = () => ({ currency: 'USD', floor: 3 }); + }}); + const bidderRequest = Object.freeze({ + currency: 'USD', + bids: [{ + bidId: 1, + params: { + placementId: 'foo' } - }); - - var request = spec.buildRequests(clonedBids, payload); - var krakenParams = request.data; - - expect(request.url).to.equal('https://krk2.kargo.com/api/v1/prebid'); - expect(request.method).to.equal('POST'); - expect(request.timeout).to.equal(200); - expect(krakenParams).to.deep.equal(expected); - - // Make sure session ID stays the same across requests simulating multiple auctions on one page load - for (let i in sessionIds) { - if (i == 0) { - continue; + }, { + bidId: 2, + params: { + placementId: 'bar' } - let sessionId = sessionIds[i]; - expect(sessionIds[0]).to.equal(sessionId); - } - } - - it('works when all params and localstorage and cookies are correctly set', function () { - initializeKrgCrb(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), generatePageView())); - }); - - it('works when all params and cookies are correctly set but no localstorage', function () { - initializeKrgCrb(true); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle()))); - }); - - it('gracefully handles nothing being set', function () { - testBuildRequests(getExpectedKrakenParams(undefined, undefined, true)); - }); - - it('gracefully handles browsers without localStorage', function () { - simulateNoLocalStorage(); - testBuildRequests(getExpectedKrakenParams(undefined, undefined, true)); - }); - - it('handles empty yet valid Kargo CRB', function () { - initializeEmptyKrgCrb(); - initializeEmptyKrgCrbCookie(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getEmptyKrgCrbOldStyle(), getEmptyKrgCrb()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where base64 encoding is invalid', function () { - initializeInvalidKrgCrbType1(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(undefined, getInvalidKrgCrbType1()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where top level JSON is invalid on cookie', function () { - initializeInvalidKrgCrbType1Cookie(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getInvalidKrgCrbType1()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where decoded JSON is invalid', function () { - initializeInvalidKrgCrbType2(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(undefined, getInvalidKrgCrbType2()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where inner base 64 is invalid on cookie', function () { - initializeInvalidKrgCrbType2Cookie(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getInvalidKrgCrbType2OldStyle()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where inner JSON is invalid on cookie', function () { - initializeInvalidKrgCrbType3Cookie(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getInvalidKrgCrbType3OldStyle()), generatePageView(), true)); - }); - - it('handles broken Kargo CRBs where inner JSON is falsey', function () { - initializeInvalidKrgCrbType4Cookie(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getInvalidKrgCrbType4OldStyle()), generatePageView(), true)); - }); - - it('handles a non-existant currency object on the config', function () { - simulateNoCurrencyObject(); - initializeKrgCrb(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), generatePageView())); - }); - - it('handles no ad server currency being set on the currency object in the config', function () { - simulateNoAdServerCurrency(); - initializeKrgCrb(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), generatePageView())); - }); - - it('handles non-USD ad server currency being set on the currency object in the config', function () { - simulateNonUSDAdServerCurrency(); - initializeKrgCrb(); - initializePageView(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), generatePageView(), undefined, undefined, 'EUR')); + }, { + bidId: 3, + params: { + placementId: 'bar' + } + }, { + bidId: 4, + params: { + placementId: 'bar' + } + }, { + bidId: 5, + params: { + placementId: 'bar' + } + }, { + bidId: 6, + params: { + placementId: 'bar' + } + }] }); - it('sends gdpr consent', function () { - initializeKrgCrb(); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), undefined, false, generateGDPRExpect(true, true)), generateGDPR(true, true)); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), undefined, false, generateGDPRExpect(false, true)), generateGDPR(false, true)); - testBuildRequests(getExpectedKrakenParams(generateRawCRB(getKrgCrbOldStyle(), getKrgCrb()), undefined, false, generateGDPRExpect(false, false)), generateGDPR(false, false)); + it('returns an empty array if the response body is empty or not an object', function() { + [ + '', + undefined, + false, + true, + null, + [], + {}, + 1234, + ].forEach(value => { + let bids = spec.interpretResponse({ body: value }, bidderRequest); + expect(bids, `Value - ${JSON.stringify(value)}`).to.deep.equal([]); + }); }); - }); - describe('response handler', function () { - it('handles bid responses', function () { - var resp = spec.interpretResponse({ - body: { - 1: { - id: 'foo', - cpm: 3, - adm: '
', - width: 320, - height: 50, - metadata: {}, - creativeID: 'bar' - }, - 2: { - id: 'bar', - cpm: 2.5, - adm: '
', - width: 300, - height: 250, - targetingCustom: 'dmpmptest1234', - metadata: { - landingPageDomain: ['https://foobar.com'] - }, - creativeID: 'foo' - }, - 3: { - id: 'bar', - cpm: 2.5, - adm: '
', - width: 300, - height: 250, - creativeID: 'foo' - }, - 4: { - id: 'bar', - cpm: 2.5, - adm: '
', - width: 300, - height: 250, - mediaType: 'banner', - metadata: {}, - creativeID: 'foo', - currency: 'EUR' - }, - 5: { - id: 'bar', - cpm: 2.5, - adm: '', - width: 300, - height: 250, - mediaType: 'video', - metadata: {}, - creativeID: 'foo', - currency: 'EUR' - }, - 6: { - id: 'bar', - cpm: 2.5, - adm: '', - admUrl: 'https://foobar.com/vast_adm', - width: 300, - height: 250, - mediaType: 'video', - metadata: {}, - creativeID: 'foo', - currency: 'EUR' - } - } - }, { - currency: 'USD', - bids: [{ - bidId: 1, - params: { - placementId: 'foo' - } - }, { - bidId: 2, - params: { - placementId: 'bar' - } - }, { - bidId: 3, - params: { - placementId: 'bar' - } - }, { - bidId: 4, - params: { - placementId: 'bar' - } - }, { - bidId: 5, - params: { - placementId: 'bar' - } - }, { - bidId: 6, - params: { - placementId: 'bar' - } - }] - }); - var expectation = [{ + it('returns bid response for various objects', function() { + let bids = spec.interpretResponse(response, bidderRequest); + expect(bids).to.have.length(Object.keys(response.body).length); + expect(bids[0]).to.deep.equal({ ad: '
', - requestId: '1', cpm: 3, - width: 320, - height: 50, - ttl: 300, creativeId: 'bar', - dealId: undefined, - netRevenue: true, currency: 'USD', + dealId: undefined, + height: 50, mediaType: 'banner', meta: { mediaType: 'banner' - } - }, { + }, + netRevenue: true, + requestId: '1', + ttl: 300, + width: 320, + }); + expect(bids[1]).to.deep.equal({ requestId: '2', ad: '
', cpm: 2.5, @@ -990,7 +1725,8 @@ describe('kargo adapter tests', function () { clickUrl: 'https://foobar.com', advertiserDomains: ['https://foobar.com'] } - }, { + }); + expect(bids[2]).to.deep.equal({ requestId: '3', ad: '
', cpm: 2.5, @@ -1005,7 +1741,8 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'banner' } - }, { + }); + expect(bids[3]).to.deep.equal({ requestId: '4', ad: '
', cpm: 2.5, @@ -1020,7 +1757,8 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'banner' } - }, { + }); + expect(bids[4]).to.deep.equal({ requestId: '5', cpm: 2.5, width: 300, @@ -1035,7 +1773,8 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'video' } - }, { + }); + expect(bids[5]).to.deep.equal({ requestId: '6', cpm: 2.5, width: 300, @@ -1050,148 +1789,200 @@ describe('kargo adapter tests', function () { meta: { mediaType: 'video' } - }]; - expect(resp).to.deep.equal(expectation); + }); }); - }); - - describe('user sync handler', function () { - const clientId = '74c81cbb-7d07-46d9-be9b-68ccb291c949'; - var shouldSimulateOutdatedBrowser, crb, isActuallyOutdatedBrowser; - beforeEach(() => { - $$PREBID_GLOBAL$$.bidderSettings = { - kargo: { - storageAllowed: true + it('adds landingPageDomain data', function() { + let response = spec.interpretResponse({ body: { 0: { + metadata: { + landingPageDomain: [ + 'https://foo.com', + 'https://bar.com' + ] } - }; - crb = {}; - shouldSimulateOutdatedBrowser = false; - isActuallyOutdatedBrowser = false; - - // IE11 fails these tests in the Prebid test suite. Since this - // browser won't support any of this stuff we expect all user - // syncing to fail gracefully. Kargo is mobile only, so this - // doesn't really matter. - if (!window.crypto) { - isActuallyOutdatedBrowser = true; - } else { - sandbox.stub(crypto, 'getRandomValues').callsFake(function (buf) { - if (shouldSimulateOutdatedBrowser) { - throw new Error('Could not generate random values'); - } - var bytes = [50, 5, 232, 133, 141, 55, 49, 57, 244, 126, 248, 44, 255, 38, 128, 0]; - for (var i = 0; i < bytes.length; i++) { - buf[i] = bytes[i]; - } - return buf; - }); - } - - sandbox.stub(spec, '_getCrb').callsFake(function () { - return crb; + } } }, {}); + expect(response[0].meta).to.deep.equal({ + mediaType: 'banner', + clickUrl: 'https://foo.com', + advertiserDomains: [ 'https://foo.com', 'https://bar.com' ] }); }); + }); - function getUserSyncsWhenAllowed(gdprConsent, usPrivacy, gppConsent) { - return spec.getUserSyncs({ iframeEnabled: true }, null, gdprConsent, usPrivacy, gppConsent); - } + describe('getUserSyncs', function() { + let crb = {}; + const clientId = 'random-client-id-string'; + const baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid='; + + function buildSyncUrls(baseUrl = 'https://crb.kargo.com/api/v1/initsyncrnd/random-client-id-string?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=0&gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=') { + let syncs = []; + for (let i = 0; i < 5; i++) { + syncs.push({ + type: 'iframe', + url: baseUrl.replace(/idx=\d+&/, `idx=${i}&`), + }); + } - function getUserSyncsWhenForbidden() { - return spec.getUserSyncs({}); + return syncs; } - function turnOnClientId() { - crb.clientId = clientId; + function getUserSyncs(gdpr, usp, gpp) { + return spec.getUserSyncs( + { iframeEnabled: true }, + null, + gdpr, + usp, + gpp + ); } - function simulateOutdatedBrowser() { - shouldSimulateOutdatedBrowser = true; - } + beforeEach(function() { + crb = { clientId }; + sandbox.stub(spec, '_getCrb').callsFake(function() { return crb; }); - function getSyncUrl(index, gdprApplies, gdprConsentString, usPrivacy, gpp, gppSid) { - return { - type: 'iframe', - url: `https://crb.kargo.com/api/v1/initsyncrnd/${clientId}?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=${index}&gdpr=${gdprApplies}&gdpr_consent=${gdprConsentString}&us_privacy=${usPrivacy}&gpp=${gpp}&gpp_sid=${gppSid}` - }; - } + // Makes the seed in the URLs predictable + sandbox.stub(crypto, 'getRandomValues').callsFake(function (buf) { + var bytes = [50, 5, 232, 133, 141, 55, 49, 57, 244, 126, 248, 44, 255, 38, 128, 0]; + for (var i = 0; i < bytes.length; i++) { + buf[i] = bytes[i]; + } + return buf; + }); + }); - function getSyncUrls(gdprApplies, gdprConsentString, usPrivacy, gpp, gppSid) { - var syncs = []; - for (var i = 0; i < 5; i++) { - syncs[i] = getSyncUrl(i, gdprApplies || 0, gdprConsentString || '', usPrivacy || '', gpp || '', gppSid || ''); - } - return syncs; - } + it('returns user syncs when an ID is present', function() { + expect(getUserSyncs()).to.deep.equal(buildSyncUrls()); + }); - function safelyRun(runExpectation) { - if (isActuallyOutdatedBrowser) { - expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty; - } else { - runExpectation(); - } - } + it('returns no syncs if there is no user ID', function() { + delete crb.clientId; + expect(getUserSyncs()).to.deep.equal([]); + }); - it('handles user syncs when there is a client id', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenAllowed()).to.deep.equal(getSyncUrls())); + it('returns no syncs if there is no usp consent', function() { + expect(getUserSyncs(undefined, '1YYY')).to.deep.equal([]); }); - it('no user syncs when there is no client id', function () { - safelyRun(() => expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty); + it('returns no syncs if iframe syncing is not allowed', function() { + expect(spec.getUserSyncs({ iframeEnabled: false }, null, undefined, undefined, undefined)) + .to.deep.equal([]); + expect(spec.getUserSyncs({}, null, undefined, undefined, undefined)) + .to.deep.equal([]); }); - it('no user syncs when there is no us privacy consent', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenAllowed(null, '1YYY')).to.be.an('array').that.is.empty); + it('includes the US privacy string in the sync URL if present', function() { + [ + '0---', + '1---', + '1NNN', + 'invalid', + 1234, + ].forEach(value => expect(getUserSyncs(undefined, value), `Value - ${value}`) + .to.deep.equal(buildSyncUrls(baseUrl.replace(/us_privacy=/, `us_privacy=${value}`)))); }); - it('pass through us privacy consent', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenAllowed(null, '1YNY')).to.deep.equal(getSyncUrls(0, '', '1YNY'))); + it('includes gdpr information if provided', function() { + [ + { gdprApplies: true, consentString: 'test-consent-string', ga: '1', cs: 'test-consent-string' }, + { gdprApplies: false, consentString: 'test-consent-string', ga: '0', cs: 'test-consent-string' }, + { gdprApplies: true, ga: '1', cs: '' }, + { gdprApplies: false, ga: '0', cs: '' }, + { ga: '0', cs: '' }, + ].forEach(value => expect(getUserSyncs(value), `Value - ${value}`) + .to.deep.equal(buildSyncUrls(baseUrl + .replace(/gdpr=\d/, `gdpr=${value.ga}`) + .replace(/gdpr_consent=/, `gdpr_consent=${value.cs}`)))); }); - it('pass through gdpr consent', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenAllowed({ gdprApplies: true, consentString: 'consentstring' })).to.deep.equal(getSyncUrls(1, 'consentstring', ''))); + it('handles malformed gdpr information', function() { + [ + null, + false, + true, + 1, + '1', + 'test-applies', + [], + {} + ].forEach(value => expect(getUserSyncs(value), `Value - ${JSON.stringify(value)}`) + .to.deep.equal(buildSyncUrls(baseUrl))); }); - it('pass through gpp consent', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenAllowed(null, null, { consentString: 'gppString', applicableSections: [-1] })).to.deep.equal(getSyncUrls('', '', '', 'gppString', '-1'))); + it('includes gpp information if provided', function() { + [ + { applicableSections: [-1], consentString: 'test-consent-string', as: '-1', cs: 'test-consent-string' }, + { applicableSections: [1, 2, 3], consentString: 'test-consent-string', as: '1,2,3', cs: 'test-consent-string' }, + { applicableSections: [-1], as: '-1', cs: '' }, + { applicableSections: false, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: null, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: {}, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: [], consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { as: '', cs: '' }, + ].forEach(value => expect(getUserSyncs(undefined, undefined, value), `Value - ${value}`) + .to.deep.equal(buildSyncUrls(baseUrl + .replace(/gpp=/, `gpp=${value.cs}`) + .replace(/gpp_sid=/, `gpp_sid=${value.as}`)))); }); - it('no user syncs when there is outdated browser', function () { - turnOnClientId(); - simulateOutdatedBrowser(); - safelyRun(() => expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty); + it('handles malformed gpp information', function() { + [ + null, + false, + true, + 1, + '1', + 'test-applies', + [], + {} + ].forEach(value => expect(getUserSyncs(undefined, undefined, value), `Value - ${JSON.stringify(value)}`) + .to.deep.equal(buildSyncUrls(baseUrl))); }); - it('no user syncs when no iframe syncing allowed', function () { - turnOnClientId(); - safelyRun(() => expect(getUserSyncsWhenForbidden()).to.be.an('array').that.is.empty); + it('includes all 3 if provided', function() { + expect(getUserSyncs( + { gdprApplies: true, consentString: 'test-gdpr-consent' }, + '1---', + { applicableSections: [1, 2, 3], consentString: 'test-gpp-consent' } + )).to.deep.equal(buildSyncUrls(baseUrl + .replace(/gdpr=\d/, 'gdpr=1') + .replace(/gdpr_consent=/, 'gdpr_consent=test-gdpr-consent') + .replace(/us_privacy=/, 'us_privacy=1---') + .replace(/gpp=/, 'gpp=test-gpp-consent') + .replace(/gpp_sid=/, 'gpp_sid=1,2,3'))); }); }); - describe('timeout pixel trigger', function () { - let triggerPixelStub; + describe('supportedMediaTypes', function() { + it('exposes video and banner', function() { + expect(spec.supportedMediaTypes).to.deep.equal([ 'banner', 'video' ]); + }); + }); + describe('onTimeout', function() { beforeEach(function () { - triggerPixelStub = sinon.stub(utils, 'triggerPixel'); + sinon.stub(utils, 'triggerPixel'); }); afterEach(function () { utils.triggerPixel.restore(); }); - it('should call triggerPixel utils function when timed out is filled', function () { - spec.onTimeout(); - expect(triggerPixelStub.getCall(0)).to.be.null; - spec.onTimeout([{ auctionId: '1234', timeout: 2000 }]); - expect(triggerPixelStub.getCall(0)).to.not.be.null; - expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('https://krk2.kargo.com/api/v1/event/timeout'); - expect(triggerPixelStub.getCall(0).args[0]).to.include('aid=1234'); - expect(triggerPixelStub.getCall(0).args[0]).to.include('ato=2000'); + it('does not call triggerPixel if timeout data is not provided', function() { + spec.onTimeout(null); + expect(utils.triggerPixel.callCount).to.equal(0); + }); + + it('calls triggerPixel if any timeout data is provided', function() { + spec.onTimeout([ + {auctionId: 'test-auction-id', timeout: 400}, + {auctionId: 'test-auction-id-2', timeout: 100}, + {auctionId: 'test-auction-id-3', timeout: 450}, + {auctionId: 'test-auction-id-4', timeout: 500}, + ]); + expect(utils.triggerPixel.calledWith('https://krk2.kargo.com/api/v1/event/timeout?aid=test-auction-id&ato=400')).to.be.true; + expect(utils.triggerPixel.calledWith('https://krk2.kargo.com/api/v1/event/timeout?aid=test-auction-id-2&ato=100')).to.be.true; + expect(utils.triggerPixel.calledWith('https://krk2.kargo.com/api/v1/event/timeout?aid=test-auction-id-3&ato=450')).to.be.true; + expect(utils.triggerPixel.calledWith('https://krk2.kargo.com/api/v1/event/timeout?aid=test-auction-id-4&ato=500')).to.be.true; }); }); }); From bf6de067a4a333c906ef5908b30e7fa455746c1a Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 30 Apr 2024 10:59:19 -0700 Subject: [PATCH 074/147] Build system: fix standalone debugging & inclusion of node dependencies (#11375) --- gulpfile.js | 87 ++++++++++++++++++++++++-------------------- webpack.conf.js | 10 ----- webpack.debugging.js | 30 +++++++++++++++ 3 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 webpack.debugging.js diff --git a/gulpfile.js b/gulpfile.js index 4dbd92587fe..86c1b7fe509 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -11,6 +11,7 @@ var webpackStream = require('webpack-stream'); var gulpClean = require('gulp-clean'); var opens = require('opn'); var webpackConfig = require('./webpack.conf.js'); +const standaloneDebuggingConfig = require('./webpack.debugging.js'); var helpers = require('./gulpHelpers.js'); var concat = require('gulp-concat'); var replace = require('gulp-replace'); @@ -127,35 +128,56 @@ function viewReview(done) { viewReview.displayName = 'view-review'; -function makeDevpackPkg() { - var cloned = _.cloneDeep(webpackConfig); - Object.assign(cloned, { - devtool: 'source-map', - mode: 'development' - }) +function makeVerbose(config = webpackConfig) { + return _.merge({}, config, { + optimization: { + minimizer: [ + new TerserPlugin({ + parallel: true, + terserOptions: { + mangle: false, + format: { + comments: 'all' + } + }, + extractComments: false, + }), + ], + } + }); +} - const babelConfig = require('./babelConfig.js')({disableFeatures: helpers.getDisabledFeatures(), prebidDistUrlBase: argv.distUrlBase || '/build/dev/'}); +function makeDevpackPkg(config = webpackConfig) { + return function() { + var cloned = _.cloneDeep(config); + Object.assign(cloned, { + devtool: 'source-map', + mode: 'development' + }) + + const babelConfig = require('./babelConfig.js')({disableFeatures: helpers.getDisabledFeatures(), prebidDistUrlBase: argv.distUrlBase || '/build/dev/'}); - // update babel config to set local dist url - cloned.module.rules - .flatMap((rule) => rule.use) - .filter((use) => use.loader === 'babel-loader') - .forEach((use) => use.options = Object.assign({}, use.options, babelConfig)); + // update babel config to set local dist url + cloned.module.rules + .flatMap((rule) => rule.use) + .filter((use) => use.loader === 'babel-loader') + .forEach((use) => use.options = Object.assign({}, use.options, babelConfig)); - var externalModules = helpers.getArgModules(); + var externalModules = helpers.getArgModules(); - const analyticsSources = helpers.getAnalyticsSources(); - const moduleSources = helpers.getModulePaths(externalModules); + const analyticsSources = helpers.getAnalyticsSources(); + const moduleSources = helpers.getModulePaths(externalModules); - return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js')) - .pipe(helpers.nameModules(externalModules)) - .pipe(webpackStream(cloned, webpack)) - .pipe(gulp.dest('build/dev')) - .pipe(connect.reload()); + return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js')) + .pipe(helpers.nameModules(externalModules)) + .pipe(webpackStream(cloned, webpack)) + .pipe(gulp.dest('build/dev')) + .pipe(connect.reload()); + } } -function makeWebpackPkg(extraConfig = {}) { - var cloned = _.merge(_.cloneDeep(webpackConfig), extraConfig); +function makeWebpackPkg(config = webpackConfig) { + var cloned = _.cloneDeep(config) if (!argv.sourceMaps) { delete cloned.devtool; } @@ -495,26 +517,11 @@ gulp.task(escapePostbidConfig); gulp.task('build-creative-dev', gulp.series(buildCreative(argv.creativeDev ? 'development' : 'production'), updateCreativeRenderers)); gulp.task('build-creative-prod', gulp.series(buildCreative(), updateCreativeRenderers)); -gulp.task('build-bundle-dev', gulp.series('build-creative-dev', makeDevpackPkg, gulpBundle.bind(null, true))); -gulp.task('build-bundle-prod', gulp.series('build-creative-prod', makeWebpackPkg(), gulpBundle.bind(null, false))); +gulp.task('build-bundle-dev', gulp.series('build-creative-dev', makeDevpackPkg(standaloneDebuggingConfig), makeDevpackPkg(), gulpBundle.bind(null, true))); +gulp.task('build-bundle-prod', gulp.series('build-creative-prod', makeWebpackPkg(standaloneDebuggingConfig), makeWebpackPkg(), gulpBundle.bind(null, false))); // build-bundle-verbose - prod bundle except names and comments are preserved. Use this to see the effects // of dead code elimination. -gulp.task('build-bundle-verbose', gulp.series(makeWebpackPkg({ - optimization: { - minimizer: [ - new TerserPlugin({ - parallel: true, - terserOptions: { - mangle: false, - format: { - comments: 'all' - } - }, - extractComments: false, - }), - ], - } -}), gulpBundle.bind(null, false))); +gulp.task('build-bundle-verbose', gulp.series('build-creative-dev', makeWebpackPkg(makeVerbose(standaloneDebuggingConfig)), makeWebpackPkg(makeVerbose()), gulpBundle.bind(null, true))); // public tasks (dependencies are needed for each task since they can be ran on their own) gulp.task('test-only', test); diff --git a/webpack.conf.js b/webpack.conf.js index c934b09d439..1035e985b22 100644 --- a/webpack.conf.js +++ b/webpack.conf.js @@ -51,9 +51,6 @@ module.exports = { 'prebid-core': { import: './src/prebid.js' }, - 'debugging-standalone': { - import: './modules/debugging/standalone.js' - } }; const selectedModules = new Set(helpers.getArgModules()); @@ -130,15 +127,8 @@ module.exports = { ); const core = path.resolve('./src'); const paapiMod = path.resolve('./modules/paapi.js'); - const nodeModules = path.resolve('./node_modules'); return Object.assign(libraries, { - common_deps: { - name: 'common_deps', - test(module) { - return module.resource && module.resource.startsWith(nodeModules); - } - }, core: { name: 'chunk-core', test: (module) => { diff --git a/webpack.debugging.js b/webpack.debugging.js new file mode 100644 index 00000000000..3952649c557 --- /dev/null +++ b/webpack.debugging.js @@ -0,0 +1,30 @@ +var path = require('path'); + +module.exports = { + mode: 'production', + devtool: 'source-map', + resolve: { + modules: [ + path.resolve('.'), + 'node_modules' + ], + }, + entry: { + 'debugging-standalone': { + import: './modules/debugging/standalone.js', + } + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: path.resolve('./node_modules'), // required to prevent loader from choking non-Prebid.js node_modules + use: [ + { + loader: 'babel-loader' + } + ] + }, + ] + } +}; From 51c63b633e007968d9ddcb117aef5cfab169dc88 Mon Sep 17 00:00:00 2001 From: Pruthvi Muga <143863123+pruthvimuga@users.noreply.github.com> Date: Wed, 1 May 2024 12:47:55 +0530 Subject: [PATCH 075/147] Pubx.ai RTD Provider - Initial Release (#11300) * Add pubx RTD module * Add pubx RTD module documentation * Add basic tests for pubx RTD module * Fix the failing tests * Added logic to fetch floors and set to auction * Updated setDataToConfig to attach floors data to bidder requests object * pubx rtd module: * fetch floor rules * timeout defaults * floors config customizations * pubx on/off from floors response * move fetch floors to init and also wait for it before auction * TESTS: update * replace createFloorsDataForAuction to avoid circular dep - WIP * reset default floors when no floor response is received * TESTS: add test * tag integration - fetch floors api events * * Remove coonsole.log * move __pubxFloorRulesPromise__ to window * Remove unused var error * TESTS: add getBidRequestData, refactor stubs * TESTS: setFloorsApiStatus * TESTS: add fetchFloorRules * remove useRtd * make endpoint potional and take pubxId form provider config * TESTS: use xhr to fakeServer instead of sinon * make default data optional * update README * TEST: update tests * add integration example * remove floorProvider from default config * fix linting * update readme.md --------- Co-authored-by: Phaneendra Hegde Co-authored-by: Phaneendra Hegde --- .../gpt/pubxaiRtdProvider_example.html | 113 +++++ modules/.submodules.json | 1 + modules/pubxaiRtdProvider.js | 146 +++++++ modules/pubxaiRtdProvider.md | 68 +++ test/spec/modules/pubxaiRtdProvider_spec.js | 397 ++++++++++++++++++ 5 files changed, 725 insertions(+) create mode 100644 integrationExamples/gpt/pubxaiRtdProvider_example.html create mode 100644 modules/pubxaiRtdProvider.js create mode 100644 modules/pubxaiRtdProvider.md create mode 100644 test/spec/modules/pubxaiRtdProvider_spec.js diff --git a/integrationExamples/gpt/pubxaiRtdProvider_example.html b/integrationExamples/gpt/pubxaiRtdProvider_example.html new file mode 100644 index 00000000000..566cfe0c928 --- /dev/null +++ b/integrationExamples/gpt/pubxaiRtdProvider_example.html @@ -0,0 +1,113 @@ + + + Individual Ad Unit Refresh Example + + + + + + + + +

Individual Ad Unit Refresh Example

+
Div-1
+

+
+ +
+ + diff --git a/modules/.submodules.json b/modules/.submodules.json index 3913f3f5734..3b7f84af245 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -90,6 +90,7 @@ "optimeraRtdProvider", "oxxionRtdProvider", "permutiveRtdProvider", + "pubxaiRtdProvider", "qortexRtdProvider", "reconciliationRtdProvider", "relevadRtdProvider", diff --git a/modules/pubxaiRtdProvider.js b/modules/pubxaiRtdProvider.js new file mode 100644 index 00000000000..b958856df00 --- /dev/null +++ b/modules/pubxaiRtdProvider.js @@ -0,0 +1,146 @@ +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import { submodule } from '../src/hook.js'; +import { deepAccess } from '../src/utils.js'; +/** + * This RTD module has a dependency on the priceFloors module. + * We utilize the createFloorsDataForAuction function from the priceFloors module to incorporate price floors data into the current auction. + */ +import { createFloorsDataForAuction } from './priceFloors.js'; // eslint-disable-line prebid/validate-imports + +const MODULE_NAME = 'realTimeData'; +const SUBMODULE_NAME = 'pubxai'; +window.__pubxFloorRulesPromise__ = null; +export const FloorsApiStatus = Object.freeze({ + IN_PROGRESS: 'IN_PROGRESS', + SUCCESS: 'SUCCESS', + ERROR: 'ERROR', +}); +export const FLOORS_EVENT_HANDLE = 'floorsApi'; +export const FLOORS_END_POINT = 'https://floor.pbxai.com/'; +export const FLOOR_PROVIDER = 'PubxFloorProvider'; + +export const getFloorsConfig = (provider, floorsResponse) => { + const floorsConfig = { + floors: { + enforcement: { floorDeals: true }, + data: floorsResponse, + }, + }; + const { floorMin, enforcement } = deepAccess(provider, 'params'); + if (floorMin) { + floorsConfig.floors.floorMin = floorMin; + } + if (enforcement) { + floorsConfig.floors.enforcement = enforcement; + } + return floorsConfig; +}; + +export const setFloorsConfig = (provider, data) => { + if (data) { + const floorsConfig = getFloorsConfig(provider, data); + config.setConfig(floorsConfig); + window.__pubxLoaded__ = true; + window.__pubxFloorsConfig__ = floorsConfig; + } else { + config.setConfig({ floors: window.__pubxPrevFloorsConfig__ }); + window.__pubxLoaded__ = false; + window.__pubxFloorsConfig__ = null; + } +}; + +export const setDefaultPriceFloors = (provider) => { + const { data } = deepAccess(provider, 'params'); + if (data !== undefined) { + data.floorProvider = FLOOR_PROVIDER; + setFloorsConfig(provider, data); + } +}; + +export const setPriceFloors = async (provider) => { + window.__pubxPrevFloorsConfig__ = config.getConfig('floors'); + setDefaultPriceFloors(provider); + return fetchFloorRules(provider) + .then((floorsResponse) => { + setFloorsConfig(provider, floorsResponse); + setFloorsApiStatus(FloorsApiStatus.SUCCESS); + }) + .catch((_) => { + setFloorsApiStatus(FloorsApiStatus.ERROR); + }); +}; + +export const setFloorsApiStatus = (status) => { + window.__pubxFloorsApiStatus__ = status; + window.dispatchEvent( + new CustomEvent(FLOORS_EVENT_HANDLE, { detail: { status } }) + ); +}; + +export const getUrl = (provider) => { + const { pubxId, endpoint } = deepAccess(provider, 'params'); + return `${endpoint || FLOORS_END_POINT}?pubxId=${pubxId}&page=${ + window.location.href + }`; +}; + +export const fetchFloorRules = async (provider) => { + return new Promise((resolve, reject) => { + setFloorsApiStatus(FloorsApiStatus.IN_PROGRESS); + ajax(getUrl(provider), { + success: (responseText, response) => { + try { + if (response && response.response) { + const floorsResponse = JSON.parse(response.response); + resolve(floorsResponse); + } else { + resolve(null); + } + } catch (error) { + reject(error); + } + }, + error: (responseText, response) => { + reject(response); + }, + }); + }); +}; + +const init = (provider) => { + window.__pubxFloorRulesPromise__ = setPriceFloors(provider); + return true; +}; + +const getBidRequestData = (() => { + let floorsAttached = false; + return (reqBidsConfigObj, onDone) => { + if (!floorsAttached) { + createFloorsDataForAuction( + reqBidsConfigObj.adUnits, + reqBidsConfigObj.auctionId + ); + window.__pubxFloorRulesPromise__.then(() => { + createFloorsDataForAuction( + reqBidsConfigObj.adUnits, + reqBidsConfigObj.auctionId + ); + onDone(); + }); + floorsAttached = true; + } + }; +})(); + +export const pubxaiSubmodule = { + name: SUBMODULE_NAME, + init, + getBidRequestData, +}; + +export const beforeInit = () => { + submodule(MODULE_NAME, pubxaiSubmodule); +}; + +beforeInit(); diff --git a/modules/pubxaiRtdProvider.md b/modules/pubxaiRtdProvider.md new file mode 100644 index 00000000000..d7d89857c62 --- /dev/null +++ b/modules/pubxaiRtdProvider.md @@ -0,0 +1,68 @@ +## Overview + +- Module Name: pubX.ai RTD Provider +- Module Type: RTD Adapter +- Maintainer: phaneendra@pubx.ai + +## Description + +This RTD module, provided by pubx.ai, is used to set dynamic floors within Prebid. + +## Usage + +Ensure that the following modules are listed when building Prebid: `priceFloors`. +For example: + +```shell +gulp build --modules=priceFloors +``` + +To compile the RTD module into your Prebid build: + +```shell +gulp build --modules=rtdModule,pubxaiRtdProvider +``` + +To utilize the pubX.ai RTD module, add `realTimeData` with the parameters mentioned below to the Prebid config. + +```js +const AUCTION_DELAY = 100; +pbjs.setConfig({ + // rest of the config + ..., + realTimeData: { + auctionDelay: AUCTION_DELAY, + dataProviders: { + name: "pubxai", + waitForIt: true, + params: { + pubxId: ``, + endpoint: ``, // (optional) + floorMin: ``, // (optional) + enforcement: ``, // (optional) + data: `` // (optional) + } + } + } + // rest of the config + ..., +}); +``` + +## Parameters + +| Name | Type | Description | Default | +| :----------------- | :------ | :------------------------------------------------------------- | :------------------------- | +| name | String | Name of the real-time data module | Always `pubxai` | +| waitForIt | Boolean | Should be `true` if an `auctionDelay` is defined (optional) | `false` | +| params | Object | | | +| params.pubxId | String | Publisher ID | | +| params.endpoint | String | URL to retrieve floor data (optional) | `https://floor.pbxai.com/` | +| params.floorMin | Number | Minimum CPM floor (optional) | `None` | +| params.enforcement | Object | Enforcement behavior within the Price Floors Module (optional) | `None` | +| params.data | Object | Default floor data provided by pubX.ai (optional) | `None` | + +## What Should Change in the Bid Request? + +There are no direct changes in the bid request due to our RTD module, but floor configuration will be set using the price floors module. These changes will be reflected in adunit bids or bidder requests as floor data. + diff --git a/test/spec/modules/pubxaiRtdProvider_spec.js b/test/spec/modules/pubxaiRtdProvider_spec.js new file mode 100644 index 00000000000..b645b830246 --- /dev/null +++ b/test/spec/modules/pubxaiRtdProvider_spec.js @@ -0,0 +1,397 @@ +import * as priceFloors from '../../../modules/priceFloors'; +import { + FLOORS_END_POINT, + FLOORS_EVENT_HANDLE, + FloorsApiStatus, + beforeInit, + fetchFloorRules, + getFloorsConfig, + getUrl, + pubxaiSubmodule, + setDefaultPriceFloors, + setFloorsApiStatus, + setFloorsConfig, + setPriceFloors, +} from '../../../modules/pubxaiRtdProvider'; +import { config } from '../../../src/config'; +import * as hook from '../../../src/hook.js'; +import { server } from '../../mocks/xhr.js'; + +const getConfig = () => ({ + params: { + useRtd: true, + endpoint: 'http://pubxai.com:3001/floors', + data: { + currency: 'EUR', + floorProvider: 'PubxFloorProvider', + modelVersion: 'gpt-mvm_AB_0.50_dt_0.75_dwt_0.95_dnt_0.25_fm_0.50', + schema: { fields: ['gptSlot', 'mediaType'] }, + values: { '*|banner': 0.02 }, + }, + }, +}); + +const getFloorsResponse = () => ({ + currency: 'USD', + floorProvider: 'PubxFloorProvider', + modelVersion: 'gpt-mvm_AB_0.50_dt_0.75_dwt_0.95_dnt_0.25_fm_0.50', + schema: { fields: ['gptSlot', 'mediaType'] }, + values: { '*|banner': 0.02 }, +}); + +const resetGlobals = () => { + window.__pubxLoaded__ = undefined; + window.__pubxPrevFloorsConfig__ = undefined; + window.__pubxFloorsConfig__ = undefined; + window.__pubxFloorsApiStatus__ = undefined; + window.__pubxFloorRulesPromise__ = null; +}; + +const fakeServer = ( + fakeResponse = '', + providerConfig = undefined, + statusCode = 200 +) => { + const fakeResponseHeaders = { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }; + const request = server.requests[0]; + request.respond( + statusCode, + fakeResponseHeaders, + fakeResponse ? JSON.stringify(fakeResponse) : '' + ); + return request; +}; + +const stubConfig = () => { + const stub = sinon.stub(config, 'setConfig'); + return stub; +}; + +describe('pubxaiRtdProvider', () => { + describe('beforeInit', () => { + it('should register RTD submodule provider', function () { + let submoduleStub = sinon.stub(hook, 'submodule'); + beforeInit(); + assert(submoduleStub.calledOnceWith('realTimeData', pubxaiSubmodule)); + submoduleStub.restore(); + }); + }); + describe('submodule', () => { + describe('name', function () { + it('should be pubxai', function () { + expect(pubxaiSubmodule.name).to.equal('pubxai'); + }); + }); + }); + describe('init', () => { + let stub; + beforeEach(() => { + resetGlobals(); + stub = stubConfig(); + }); + afterEach(() => { + stub.restore(); + }); + it('standard case - returns true', () => { + const initResult = pubxaiSubmodule.init({ params: { useRtd: true } }); + expect(initResult).to.be.true; + }); + it('setPriceFloors called when `useRtd` is true in the provider config', () => { + pubxaiSubmodule.init(getConfig()); + expect(window.__pubxLoaded__).to.equal(true); + }); + }); + describe('getBidRequestData', () => { + const reqBidsConfigObj = { + adUnits: [{ code: 'ad-slot-code-0' }], + auctionId: 'auction-id-0', + }; + let stub; + beforeEach(() => { + window.__pubxFloorRulesPromise__ = Promise.resolve(); + stub = sinon.stub(priceFloors, 'createFloorsDataForAuction'); + }); + afterEach(() => { + resetGlobals(); + stub.restore(); + }); + it('createFloorsDataForAuction called once before and once after __pubxFloorRulesPromise__. Also getBidRequestData executed only once', async () => { + pubxaiSubmodule.getBidRequestData(reqBidsConfigObj, () => {}); + assert(priceFloors.createFloorsDataForAuction.calledOnce); + await window.__pubxFloorRulesPromise__; + assert(priceFloors.createFloorsDataForAuction.calledTwice); + assert( + priceFloors.createFloorsDataForAuction.alwaysCalledWith( + reqBidsConfigObj.adUnits, + reqBidsConfigObj.auctionId + ) + ); + pubxaiSubmodule.getBidRequestData(reqBidsConfigObj, () => {}); + await window.__pubxFloorRulesPromise__; + assert(priceFloors.createFloorsDataForAuction.calledTwice); + }); + }); + describe('fetchFloorRules', () => { + const providerConfig = getConfig(); + const floorsResponse = getFloorsResponse(); + it('success with floors response', (done) => { + const promise = fetchFloorRules(providerConfig); + fakeServer(floorsResponse); + promise.then((res) => { + expect(res).to.deep.equal(floorsResponse); + done(); + }); + }); + it('success with no floors response', (done) => { + const promise = fetchFloorRules(providerConfig); + fakeServer(undefined); + promise.then((res) => { + expect(res).to.deep.equal(null); + done(); + }); + }); + it('API call error', (done) => { + const promise = fetchFloorRules(providerConfig); + fakeServer(undefined, undefined, 404); + promise + .then((res) => { + expect(true).to.be.false; + }) + .catch((e) => { + expect(e).to.not.be.undefined; + }) + .finally(() => { + done(); + }); + }); + it('Wrong API response', (done) => { + const promise = fetchFloorRules(providerConfig); + fakeServer('floorsResponse'); + promise + .then((res) => { + expect(true).to.be.false; + }) + .catch((e) => { + expect(e).to.not.be.undefined; + }) + .finally(() => { + done(); + }); + }); + }); + describe('setPriceFloors', () => { + const providerConfig = getConfig(); + const floorsResponse = getFloorsResponse(); + let stub; + beforeEach(() => { + resetGlobals(); + stub = stubConfig(); + }); + afterEach(() => { + stub.restore(); + }); + it('with floors response', (done) => { + const floorsPromise = setPriceFloors(providerConfig); + fakeServer(floorsResponse); + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal( + getFloorsConfig(providerConfig, providerConfig.params.data) + ); + floorsPromise.then(() => { + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal( + getFloorsConfig(providerConfig, floorsResponse) + ); + done(); + }); + }); + it('without floors response', (done) => { + const floorsPromise = setPriceFloors(providerConfig); + fakeServer(undefined); + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal( + getFloorsConfig(providerConfig, providerConfig.params.data) + ); + floorsPromise.then(() => { + expect(window.__pubxLoaded__).to.be.false; + expect(window.__pubxFloorsConfig__).to.deep.equal(null); + done(); + }); + }); + it('default floors', (done) => { + const floorsPromise = setPriceFloors(providerConfig); + fakeServer(undefined, undefined, 404); + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal( + getFloorsConfig(providerConfig, providerConfig.params.data) + ); + floorsPromise + .then(() => { + expect(true).to.be.false; + }) + .catch((e) => { + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal( + getFloorsConfig(providerConfig, providerConfig.params.data) + ); + }) + .finally(() => { + done(); + }); + }); + }); + describe('setFloorsConfig', () => { + const providerConfig = getConfig(); + let stub; + beforeEach(() => { + resetGlobals(); + stub = stubConfig(); + }); + afterEach(function () { + stub.restore(); + }); + it('non-empty floorResponse', () => { + const floorsResponse = getFloorsResponse(); + setFloorsConfig(providerConfig, floorsResponse); + const floorsConfig = getFloorsConfig(providerConfig, floorsResponse); + assert(config.setConfig.calledOnceWith(floorsConfig)); + expect(window.__pubxLoaded__).to.be.true; + expect(window.__pubxFloorsConfig__).to.deep.equal(floorsConfig); + }); + it('empty floorResponse', () => { + const floorsResponse = null; + setFloorsConfig(providerConfig, floorsResponse); + assert(config.setConfig.calledOnceWith({ floors: undefined })); + expect(window.__pubxLoaded__).to.be.false; + expect(window.__pubxFloorsConfig__).to.be.null; + }); + }); + describe('getFloorsConfig', () => { + let providerConfig; + const floorsResponse = getFloorsResponse(); + beforeEach(() => { + providerConfig = getConfig(); + }); + it('no customizations in the provider config', () => { + const result = getFloorsConfig(providerConfig, floorsResponse); + expect(result).to.deep.equal({ + floors: { + enforcement: { floorDeals: true }, + data: floorsResponse, + }, + }); + }); + it('only floormin in the provider config', () => { + providerConfig.params.floorMin = 2; + expect(getFloorsConfig(providerConfig, floorsResponse)).to.deep.equal({ + floors: { + enforcement: { floorDeals: true }, + floorMin: 2, + data: floorsResponse, + }, + }); + }); + it('only enforcement in the provider config', () => { + providerConfig.params.enforcement = { + bidAdjustment: true, + enforceJS: false, + }; + expect(getFloorsConfig(providerConfig, floorsResponse)).to.deep.equal({ + floors: { + enforcement: { + bidAdjustment: true, + enforceJS: false, + }, + data: floorsResponse, + }, + }); + }); + it('both floorMin and enforcement in the provider config', () => { + providerConfig.params.floorMin = 2; + providerConfig.params.enforcement = { + bidAdjustment: true, + enforceJS: false, + }; + expect(getFloorsConfig(providerConfig, floorsResponse)).to.deep.equal({ + floors: { + enforcement: { + bidAdjustment: true, + enforceJS: false, + }, + floorMin: 2, + data: floorsResponse, + }, + }); + }); + }); + describe('setDefaultPriceFloors', () => { + let stub; + beforeEach(() => { + resetGlobals(); + stub = stubConfig(); + }); + afterEach(function () { + stub.restore(); + }); + it('should set default floors config', () => { + const providerConfig = getConfig(); + setDefaultPriceFloors(providerConfig); + assert( + config.setConfig.calledOnceWith( + getFloorsConfig(providerConfig, providerConfig.params.data) + ) + ); + expect(window.__pubxLoaded__).to.be.true; + }); + }); + describe('setFloorsApiStatus', () => { + let stub; + beforeEach(() => { + resetGlobals(); + stub = sinon.stub(window, 'dispatchEvent'); + }); + afterEach(function () { + stub.restore(); + }); + it('set status', () => { + setFloorsApiStatus(FloorsApiStatus.SUCCESS); + expect(window.__pubxFloorsApiStatus__).to.equal(FloorsApiStatus.SUCCESS); + }); + it('dispatch event', () => { + setFloorsApiStatus(FloorsApiStatus.SUCCESS); + assert( + window.dispatchEvent.calledOnceWith( + new CustomEvent(FLOORS_EVENT_HANDLE, { + detail: { status: FloorsApiStatus.SUCCESS }, + }) + ) + ); + }); + }); + describe('getUrl', () => { + const provider = { + name: 'pubxai', + waitForIt: true, + params: { + pubxId: '12345', + }, + }; + it('floors end point', () => { + expect(FLOORS_END_POINT).to.equal('https://floor.pbxai.com/'); + }); + it('standard case', () => { + expect(getUrl(provider)).to.equal( + `https://floor.pbxai.com/?pubxId=12345&page=${window.location.href}` + ); + }); + it('custom url provided', () => { + provider.params.endpoint = 'https://custom.floor.com/'; + expect(getUrl(provider)).to.equal( + `https://custom.floor.com/?pubxId=12345&page=${window.location.href}` + ); + }); + }); +}); From 0e58601ab5e4e4c60120c2a780bc7b0156ffefa9 Mon Sep 17 00:00:00 2001 From: Keith Petri <74626343+KEPlockr@users.noreply.github.com> Date: Wed, 1 May 2024 04:24:47 -0400 Subject: [PATCH 076/147] lockr AIM user module: initial release (#11159) * Adding Lockr AIM module and tests * formatting * Fix formatting * format * fix formatting * add paapi back * added markdown file * 20240324 Fixed Storage Manager | lockrAIMIdSystem.js * Updated to use Prebid Storage Manager | lockrAIMIdSystem_shared.js * added the fix for the comments * removed the unnecessary console --------- Co-authored-by: chris-lockr Co-authored-by: avin-lockr --- modules/.submodules.json | 13 +- modules/lockrAIMIdSystem.js | 165 +++++++++++++++++++++ modules/lockrAIMIdSystem.md | 165 +++++++++++++++++++++ test/spec/modules/lockrAIMIdSystem_spec.js | 72 +++++++++ 4 files changed, 409 insertions(+), 6 deletions(-) create mode 100644 modules/lockrAIMIdSystem.js create mode 100644 modules/lockrAIMIdSystem.md create mode 100644 test/spec/modules/lockrAIMIdSystem_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index 3b7f84af245..8409ea9918d 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -4,6 +4,7 @@ "33acrossIdSystem", "admixerIdSystem", "adtelligentIdSystem", + "adqueryIdSystem", "amxIdSystem", "britepoolIdSystem", "connectIdSystem", @@ -13,9 +14,11 @@ "deepintentDpesIdSystem", "dmdIdSystem", "fabrickIdSystem", + "freepassIdSystem", "hadronIdSystem", "id5IdSystem", "ftrackIdSystem", + "gravitoIdSystem", "identityLinkIdSystem", "idxIdSystem", "imuIdSystem", @@ -23,13 +26,16 @@ "justIdSystem", "kinessoIdSystem", "liveIntentIdSystem", + "lockrAIMIdSystem", "lotamePanoramaIdSystem", "merkleIdSystem", "mwOpenLinkIdSystem", + "mygaruIdSystem", "naveggIdSystem", "netIdSystem", "novatiqIdSystem", "oneKeyIdSystem", + "operaadsIdSystem", "parrableIdSystem", "pubProvidedIdSystem", "publinkIdSystem", @@ -44,12 +50,7 @@ "euidIdSystem", "unifiedIdSystem", "verizonMediaIdSystem", - "zeotapIdPlusIdSystem", - "adqueryIdSystem", - "gravitoIdSystem", - "freepassIdSystem", - "operaadsIdSystem", - "mygaruIdSystem" + "zeotapIdPlusIdSystem" ], "adpod": [ "freeWheelAdserverVideo", diff --git a/modules/lockrAIMIdSystem.js b/modules/lockrAIMIdSystem.js new file mode 100644 index 00000000000..de0435a2255 --- /dev/null +++ b/modules/lockrAIMIdSystem.js @@ -0,0 +1,165 @@ +/** + * This module adds lockr AIM ID support to the User ID module + * The {@link module:modules/userId} module is required. + * @module modules/lockrAIMIdSystem + * @requires module:modules/userId + */ + +import { submodule } from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { logInfo, logWarn } from '../src/utils.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; +import { gppDataHandler } from '../src/adapterManager.js'; + +/** + * @typedef {import('../modules/userId/index.js').Submodule} Submodule + * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig + * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData + * @typedef {import('../modules/userId/index.js').lockrAIMId} lockrAIMId + */ + +const MODULE_NAME = 'lockrAIMId' +const LOG_PRE_FIX = 'lockr-AIM: '; + +const AIM_PROD_URL = 'https://identity.loc.kr'; + +export const lockrAIMCodeVersion = '1.0'; + +export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }) + +function createLogger(logger, prefix) { + return function (...strings) { + logger(prefix + ' ', ...strings); + } +} + +const _logInfo = createLogger(logInfo, LOG_PRE_FIX); +const _logWarn = createLogger(logWarn, LOG_PRE_FIX); + +/** @type {Submodule} */ +export const lockrAIMSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + + init() { + _logInfo('lockrAIM Initialization complete'); + }, + + /** + * performs action to obtain id and return a value. + * @function + * @param {SubmoduleConfig} [config] + * @param {ConsentData|undefined} consentData + * @returns {lockrAIMId} + */ + getId(config, consentData) { + if (consentData?.gdprApplies === true) { + _logWarn('lockrAIM is not intended for use where GDPR applies. The lockrAIM module will not run'); + return undefined; + } + + const gppConsent = gppDataHandler.getConsentData(); + let gppString = ''; + if (gppConsent) { + gppString = gppConsent.gppString; + } + const mappedConfig = { + appID: config?.params?.appID, + email: config?.params?.email, + baseUrl: AIM_PROD_URL, + }; + + _logInfo('lockr AIM configurations loaded and mapped.', mappedConfig); + if (!mappedConfig.appID || !mappedConfig.email) { + return undefined; + } + const tokenGenerator = new LockrAIMApiClient(mappedConfig, _logInfo, _logWarn, storage, gppString); + const result = tokenGenerator.generateToken(); + _logInfo('lockr AIM results generated'); + return result; + } +} + +class LockrAIMApiClient { + static expiryDateKeys = []; + static canRefreshToken = false; + + constructor(opts, logInfo, logWarn, prebidStorageManager, gppString) { + this._baseUrl = opts.baseUrl; + this._appID = opts.appID; + this._email = opts.email; + this._logInfo = logInfo; + this._logWarn = logWarn; + this._gppString = gppString; + this.prebidStorageManager = prebidStorageManager; + LockrAIMApiClient.expiryDateKeys = this.prebidStorageManager.getDataFromLocalStorage('lockr_expiry_keys') ? JSON.parse(this.prebidStorageManager.getDataFromLocalStorage('lockr_expiry_keys')) : [] + this.initializeRefresher(); + } + + async generateToken(type = 'email', value) { + const url = this._baseUrl + '/publisher/app/v1/identityLockr/generate-tokens'; + let rejectPromise; + const promise = new Promise((resolve, reject) => { + rejectPromise = reject; + }); + const requestBody = { + appID: this._appID, + data: { + type: type, + value: value ?? this._email, + gppString: this._gppString, + } + } + this._logInfo('Sending the token generation request') + ajax(url, { + success: (responseText) => { + try { + const response = JSON.parse(responseText); + LockrAIMApiClient.canRefreshToken = false; + const token = response.lockrMappingToken; + this.prebidStorageManager.setDataInLocalStorage('ilui', token); + response.data.forEach(cookieitem => { + const settings = cookieitem?.settings; + this.prebidStorageManager.setDataInLocalStorage(`${cookieitem.key_name}_expiry`, cookieitem.identity_expires); + if (!LockrAIMApiClient.expiryDateKeys.includes(`${cookieitem.key_name}_expiry`)) { + LockrAIMApiClient.expiryDateKeys.push(`${cookieitem.key_name}_expiry`); + } + this.prebidStorageManager.setDataInLocalStorage('lockr_expiry_keys', JSON.stringify(LockrAIMApiClient.expiryDateKeys)); + if (!settings?.dropLocalStorage) { + this.prebidStorageManager.setDataInLocalStorage(cookieitem.key_name, cookieitem.advertising_token); + } + if (!settings?.dropCookie) { + this.prebidStorageManager.setCookie(cookieitem.key_name, cookieitem.advertising_token); + } + }); + LockrAIMApiClient.canRefreshToken = true; + return; + } catch (_err) { + this._logWarn(_err); + rejectPromise(responseText); + LockrAIMApiClient.canRefreshToken = true; + } + } + }, JSON.stringify(requestBody), { method: 'POST', contentType: 'application/json;charset=UTF-8' }); + return promise; + } + + async initializeRefresher() { + setInterval(() => { + LockrAIMApiClient.expiryDateKeys.forEach(expiryItem => { + const currentMillis = new Date().getTime(); + const dateMillis = this.prebidStorageManager.getDataFromLocalStorage(expiryItem); + if (currentMillis > dateMillis && dateMillis !== null && this.prebidStorageManager.getDataFromLocalStorage('ilui') && LockrAIMApiClient.canRefreshToken) { + this.generateToken('refresh', this.prebidStorageManager.getDataFromLocalStorage('ilui')); + } + }) + }, 1000); + } +} + +// Register submodule for userId +submodule('userId', lockrAIMSubmodule); diff --git a/modules/lockrAIMIdSystem.md b/modules/lockrAIMIdSystem.md new file mode 100644 index 00000000000..95eee5bc5e3 --- /dev/null +++ b/modules/lockrAIMIdSystem.md @@ -0,0 +1,165 @@ +## **lockr AIM** + +Alternative Identity Manager (AIM) is a unified container for identity and data management. +With AIM’s self-service platform, publishers seamlessly integrate and activate alternative IDs like LiveRamp’s Authenticated Traffic Solution (ATS), Unified ID 2.0 (UID2), ID5 and more. The burden of due diligence and maintenance, coupled with the benefits of server-side calls result in the adoption of multiple alternative IDs, clean rooms like InfoSum and CDPs like Blueconic based on their specific needs. + +### **Account Creation | AIM** + +Sign up for an [Identity lockr account.](https://sso.loc.kr/console/signup) +Setup your app and activate the AIM library. +Compile Prebid with the appropriate configurations, and deploy. + +### **Configuration | AIM** + +First, make sure to add the lockr’s AIM submodule to your Prebid.js package with: +The following configuration parameters are available: +AIM supports all Single Sign On functions, newsletter registrations, UTM parameters, etc. For the sake of clarity, a few examples are shared below. +**Google oAuth: ** +If you are using Google oAuth (_as an example_), the onSignIn function will subsequently call window.lockr.setAdditionalData function and include a raw email. + +``` +function onSignIn(googleUser) { + pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'lockrAIMId', + params: { + email: 'john@example.com', + appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc' + } + }] + } + }); +} +``` + +**Facebook oAuth:** +If you are using Facebook Login (_as an example_), the statusChangeCallback function will subsequently call window.lockr.setAdditionalData function and include a raw email. + +``` +function statusChangeCallback(response) { + console.log('statusChangeCallback'); + console.log(response); + if(response.status === 'connected'){ + pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'lockrAIMId', + params: { + email: 'john@example.com', + appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc' + } + }] + } + }); + }else{ + document.getElementById('status').innerHTML = 'Please login'; + } +} +``` + +**Note:** The above code can be triggered from anywhere on the domain (i.e. a subscription form). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Param + Scope + Type + Description + Example +
name + Required + String + The name of this module: "lockrAIMId" + "lockrAIMId" +
params + Required + Object + Details for the configuration. + +
params.email + Required + String + Email address for identity tokens. + test@example.com +
params.appID + Required + String + Identity lockr appID + test@example.com +
+ +**lockr AIM Example** + +``` +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'lockrAIMId', + params: { + email: 'test@example.com', + appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc' + } + }] + } +}); +``` + +_Note_: lockr’s AIM self-service interface empowers publishers with the ability to pass the alternative IDs activated back to the client as local storage or as a first party cookie. Each Identity Provider can be individually set to restrict from client-side delivery and instead be retained as an authentication event within Identity lockr. In this case no data is lost, but instead maintained for automated or manual sharing to any Data Endpoint. + +**Troubleshooting and Error handling:** + +1. Navigate to the domain where Prebid.js Library is integrated. +2. Go to the 'Network' tab of your Developer Tools. Search for “prebid.js” +3. In the application tab, you can confirm any activated Identity Provider (if client-side storage is turned on in AIM’s Identity Provider settings). +4. Debugging: + Enable the debug flag to true in the setConfig call: + +``` +pbjs.setConfig({ + debug: true, + userSync: { + userIds: [{ + name: 'lockrAIMId', + params: { + email: 'test@example.com', + appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc' + } + }] + } +}); +``` diff --git a/test/spec/modules/lockrAIMIdSystem_spec.js b/test/spec/modules/lockrAIMIdSystem_spec.js new file mode 100644 index 00000000000..c886fb305c2 --- /dev/null +++ b/test/spec/modules/lockrAIMIdSystem_spec.js @@ -0,0 +1,72 @@ +/* eslint-disable no-console */ +/* eslint-disable quotes */ +import * as lockrAIMSystem from "../../../modules/lockrAIMIdSystem.js"; +import { hook } from "../../../src/hook.js"; +import { expect } from "chai"; +import { coreStorage } from "../../../modules/userId/index.js"; + +const defaultConfig = { + appID: "3b5a0f6c-7e91-11ec-b9c7-e330d98440a7", + email: "example@test.com", +}; + +const LIVE_RAMP_COOKIE = "_lr_env"; +const UID2_COOKIE = "_uid2_advertising_token"; +const ID5_COOKIE = "id5id"; +const dummyTokenValue = 'Success OK'; + +const getDataFromStorage = (dataKey) => { + return coreStorage.getDataFromLocalStorage(dataKey); +}; + +const mockHTTPRequestSuccess = (key, value) => { + coreStorage.setDataInLocalStorage(key, value); +} + +describe("lockr AIM ID System", function () { + before(() => { + hook.ready(); + }); + + describe("Check for invalid publisher config and GDPR", function () { + it("Should fail for invalid config", async function () { + // no Config + const idResult = await lockrAIMSystem.lockrAIMSubmodule.getId(); + expect(idResult).is.eq(undefined); + const idResultNoConfig = await lockrAIMSystem.lockrAIMSubmodule.getId({}); + expect(idResultNoConfig).is.eq(undefined); + }); + + it("Does not generate the token, when GDPR is enabled", async function () { + // Mocking the GDPR + const idResult = await lockrAIMSystem.lockrAIMSubmodule.getId( + defaultConfig, + { gdprApplies: true } + ); + expect(idResult).is.eq(undefined); + }); + }); + + describe("Generates the token successfully", function () { + it("Generates the UID2 token successfully", async function () { + mockHTTPRequestSuccess(UID2_COOKIE, dummyTokenValue); + await lockrAIMSystem.lockrAIMSubmodule.getId(defaultConfig); + const uid2Cookie = getDataFromStorage(UID2_COOKIE); + expect(uid2Cookie).is.eq(dummyTokenValue); + }); + + it("Generates the ID5 token successfully", async function () { + mockHTTPRequestSuccess(ID5_COOKIE, dummyTokenValue); + await lockrAIMSystem.lockrAIMSubmodule.getId(defaultConfig); + const id5Cookie = getDataFromStorage(ID5_COOKIE); + expect(id5Cookie).is.eq(dummyTokenValue); + }); + + it("Generates the liveramp token successfully", async function () { + mockHTTPRequestSuccess(LIVE_RAMP_COOKIE, dummyTokenValue); + await lockrAIMSystem.lockrAIMSubmodule.getId(defaultConfig); + const liveRampCookie = getDataFromStorage(LIVE_RAMP_COOKIE); + expect(liveRampCookie).is.eq(dummyTokenValue); + }); + }); +}); From 670a8594d13b998a68de4064668125b76cfd5917 Mon Sep 17 00:00:00 2001 From: IgorKulemzin <65122039+IgorKulemzin@users.noreply.github.com> Date: Wed, 1 May 2024 16:17:43 +0300 Subject: [PATCH 077/147] OpenWeb Bid Adapter : remove multi currency support (#11430) * removed currency from getFloor * removed currency from generateBidParameters * removed currency from optional params in md * removed currency from test --------- Co-authored-by: Dedi Sidi --- modules/openwebBidAdapter.js | 10 ++++------ modules/openwebBidAdapter.md | 4 +--- test/spec/modules/openwebBidAdapter_spec.js | 10 ---------- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/modules/openwebBidAdapter.js b/modules/openwebBidAdapter.js index 39bd50f61a9..cf0334b7f29 100644 --- a/modules/openwebBidAdapter.js +++ b/modules/openwebBidAdapter.js @@ -141,16 +141,16 @@ registerBidder(spec); * @param bid {bid} * @returns {Number} */ -function getFloor(bid, mediaType, currency) { +function getFloor(bid, mediaType) { if (!isFn(bid.getFloor)) { return 0; } let floorResult = bid.getFloor({ - currency: currency, + currency: DEFAULT_CURRENCY, mediaType: mediaType, size: '*' }); - return floorResult.currency === currency && floorResult.floor ? floorResult.floor : 0; + return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; } /** @@ -286,7 +286,6 @@ function generateBidParameters(bid, bidderRequest) { const {params} = bid; const mediaType = isBanner(bid) ? BANNER : VIDEO; const sizesArray = getSizesArray(bid, mediaType); - const currency = params.currency || config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY; // fix floor price in case of NAN if (isNaN(params.floorPrice)) { @@ -297,8 +296,7 @@ function generateBidParameters(bid, bidderRequest) { mediaType, adUnitCode: getBidIdParameter('adUnitCode', bid), sizes: sizesArray, - currency: currency, - floorPrice: Math.max(getFloor(bid, mediaType, currency), params.floorPrice), + floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), bidId: getBidIdParameter('bidId', bid), loop: getBidIdParameter('bidderRequestsCount', bid), bidderRequestId: getBidIdParameter('bidderRequestId', bid), diff --git a/modules/openwebBidAdapter.md b/modules/openwebBidAdapter.md index 36c1f0ca6c5..5450182265c 100644 --- a/modules/openwebBidAdapter.md +++ b/modules/openwebBidAdapter.md @@ -24,8 +24,6 @@ The adapter supports Video and Display demand. | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false -| `currency` | optional | String | 3 letters currency | "EUR" - # Test Parameters ```javascript @@ -50,4 +48,4 @@ var adUnits = [ }] } ]; -``` \ No newline at end of file +``` diff --git a/test/spec/modules/openwebBidAdapter_spec.js b/test/spec/modules/openwebBidAdapter_spec.js index 5a0264f00b8..4586ce78135 100644 --- a/test/spec/modules/openwebBidAdapter_spec.js +++ b/test/spec/modules/openwebBidAdapter_spec.js @@ -178,16 +178,6 @@ describe('openwebAdapter', function () { expect(request.data.bids[1].mediaType).to.equal(BANNER) }); - it('should send the correct currency in bid request', function () { - const bid = utils.deepClone(bidRequests[0]); - bid.params = { - 'currency': 'EUR' - }; - const expectedCurrency = bid.params.currency; - const request = spec.buildRequests([bid], bidderRequest); - expect(request.data.bids[0].currency).to.equal(expectedCurrency); - }); - it('should respect syncEnabled option', function() { config.setConfig({ userSync: { From 16616c5f08b10ffacb8ff8747440bbc667441617 Mon Sep 17 00:00:00 2001 From: Dedi <32620962+Dedis23@users.noreply.github.com> Date: Wed, 1 May 2024 16:39:05 +0300 Subject: [PATCH 078/147] STN Bid Adapter: remove multi currency support (#11429) * removed currency from getFloor * removed currency from generateBidParameters * removed currency from optional params in md * removed currency from test --- modules/stnBidAdapter.js | 11 ++++------- modules/stnBidAdapter.md | 1 - test/spec/modules/stnBidAdapter_spec.js | 10 ---------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/modules/stnBidAdapter.js b/modules/stnBidAdapter.js index 633e941b3b7..42b69ee7c2b 100644 --- a/modules/stnBidAdapter.js +++ b/modules/stnBidAdapter.js @@ -139,19 +139,18 @@ registerBidder(spec); * Get floor price * @param bid {bid} * @param mediaType {String} - * @param currency {String} * @returns {Number} */ -function getFloor(bid, mediaType, currency) { +function getFloor(bid, mediaType) { if (!isFn(bid.getFloor)) { return 0; } let floorResult = bid.getFloor({ - currency: currency, + currency: DEFAULT_CURRENCY, mediaType: mediaType, size: '*' }); - return floorResult.currency === currency && floorResult.floor ? floorResult.floor : 0; + return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; } /** @@ -289,7 +288,6 @@ function generateBidParameters(bid, bidderRequest) { const {params} = bid; const mediaType = isBanner(bid) ? BANNER : VIDEO; const sizesArray = getSizesArray(bid, mediaType); - const currency = params.currency || config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY; // fix floor price in case of NAN if (isNaN(params.floorPrice)) { @@ -300,8 +298,7 @@ function generateBidParameters(bid, bidderRequest) { mediaType, adUnitCode: getBidIdParameter('adUnitCode', bid), sizes: sizesArray, - currency: currency, - floorPrice: Math.max(getFloor(bid, mediaType, currency), params.floorPrice), + floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), bidId: getBidIdParameter('bidId', bid), loop: getBidIdParameter('bidderRequestsCount', bid), bidderRequestId: getBidIdParameter('bidderRequestId', bid), diff --git a/modules/stnBidAdapter.md b/modules/stnBidAdapter.md index 46374c5a53d..90b0b58e34b 100644 --- a/modules/stnBidAdapter.md +++ b/modules/stnBidAdapter.md @@ -24,7 +24,6 @@ The adapter supports Video(instream) & Banner. | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | true -| `currency` | optional | String | 3 letters currency | "EUR" # Test Parameters ```javascript diff --git a/test/spec/modules/stnBidAdapter_spec.js b/test/spec/modules/stnBidAdapter_spec.js index deba87baac2..95cab32e41d 100644 --- a/test/spec/modules/stnBidAdapter_spec.js +++ b/test/spec/modules/stnBidAdapter_spec.js @@ -178,16 +178,6 @@ describe('stnAdapter', function () { expect(request.data.bids[1].mediaType).to.equal(BANNER) }); - it('should send the correct currency in bid request', function () { - const bid = utils.deepClone(bidRequests[0]); - bid.params = { - 'currency': 'EUR' - }; - const expectedCurrency = bid.params.currency; - const request = spec.buildRequests([bid], bidderRequest); - expect(request.data.bids[0].currency).to.equal(expectedCurrency); - }); - it('should respect syncEnabled option', function() { config.setConfig({ userSync: { From c56184373df725c035751d0727025f83562ac10f Mon Sep 17 00:00:00 2001 From: Dedi <32620962+Dedis23@users.noreply.github.com> Date: Wed, 1 May 2024 16:47:24 +0300 Subject: [PATCH 079/147] MinuteMedia Bid Adapter: remove multi currency support (#11428) * removed currency from getFloor * removed currency from generateBidParameters * removed currency from test * removed currency from optional params in md * removed currency --- modules/minutemediaBidAdapter.js | 10 ++++------ modules/minutemediaBidAdapter.md | 1 - test/spec/modules/minutemediaBidAdapter_spec.js | 10 ---------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/modules/minutemediaBidAdapter.js b/modules/minutemediaBidAdapter.js index 81200f28a6f..d14af07210e 100644 --- a/modules/minutemediaBidAdapter.js +++ b/modules/minutemediaBidAdapter.js @@ -141,16 +141,16 @@ registerBidder(spec); * @param bid {bid} * @returns {Number} */ -function getFloor(bid, mediaType, currency) { +function getFloor(bid, mediaType) { if (!isFn(bid.getFloor)) { return 0; } let floorResult = bid.getFloor({ - currency: currency, + currency: DEFAULT_CURRENCY, mediaType: mediaType, size: '*' }); - return floorResult.currency === currency && floorResult.floor ? floorResult.floor : 0; + return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; } /** @@ -286,7 +286,6 @@ function generateBidParameters(bid, bidderRequest) { const {params} = bid; const mediaType = isBanner(bid) ? BANNER : VIDEO; const sizesArray = getSizesArray(bid, mediaType); - const currency = params.currency || config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY; // fix floor price in case of NAN if (isNaN(params.floorPrice)) { @@ -297,8 +296,7 @@ function generateBidParameters(bid, bidderRequest) { mediaType, adUnitCode: getBidIdParameter('adUnitCode', bid), sizes: sizesArray, - currency: currency, - floorPrice: Math.max(getFloor(bid, mediaType, currency), params.floorPrice), + floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), bidId: getBidIdParameter('bidId', bid), loop: getBidIdParameter('bidderRequestsCount', bid), bidderRequestId: getBidIdParameter('bidderRequestId', bid), diff --git a/modules/minutemediaBidAdapter.md b/modules/minutemediaBidAdapter.md index fdfdf1b32bf..66b54adaf0e 100644 --- a/modules/minutemediaBidAdapter.md +++ b/modules/minutemediaBidAdapter.md @@ -24,7 +24,6 @@ The adapter supports Video(instream) & Banner. | `floorPrice` | optional | Number | Minimum price in USD. Misuse of this parameter can impact revenue | 2.00 | `placementId` | optional | String | A unique placement identifier | "12345678" | `testMode` | optional | Boolean | This activates the test mode | false -| `currency` | optional | String | 3 letters currency | "EUR" # Test Parameters ```javascript diff --git a/test/spec/modules/minutemediaBidAdapter_spec.js b/test/spec/modules/minutemediaBidAdapter_spec.js index d5d6cdc5449..cf50ad2cd0a 100644 --- a/test/spec/modules/minutemediaBidAdapter_spec.js +++ b/test/spec/modules/minutemediaBidAdapter_spec.js @@ -178,16 +178,6 @@ describe('minutemediaAdapter', function () { expect(request.data.bids[1].mediaType).to.equal(BANNER) }); - it('should send the correct currency in bid request', function () { - const bid = utils.deepClone(bidRequests[0]); - bid.params = { - 'currency': 'EUR' - }; - const expectedCurrency = bid.params.currency; - const request = spec.buildRequests([bid], bidderRequest); - expect(request.data.bids[0].currency).to.equal(expectedCurrency); - }); - it('should respect syncEnabled option', function() { config.setConfig({ userSync: { From 0bb0ad3e55e48217719d746ddccc284d9cce3beb Mon Sep 17 00:00:00 2001 From: Dedi <32620962+Dedis23@users.noreply.github.com> Date: Wed, 1 May 2024 16:52:01 +0300 Subject: [PATCH 080/147] Rise Bid Adapter : remove multi currency support (#11427) * removed currency test * removed currency from optional params in md * removed currency from generateBidParameters * removed currency from getFloor --- modules/riseBidAdapter.js | 11 ++++------- modules/riseBidAdapter.md | 2 -- test/spec/modules/riseBidAdapter_spec.js | 10 ---------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/modules/riseBidAdapter.js b/modules/riseBidAdapter.js index 82790805303..b176ab08aaf 100644 --- a/modules/riseBidAdapter.js +++ b/modules/riseBidAdapter.js @@ -146,19 +146,18 @@ registerBidder(spec); * Get floor price * @param bid {bid} * @param mediaType {string} - * @param currency {string} * @returns {Number} */ -function getFloor(bid, mediaType, currency) { +function getFloor(bid, mediaType) { if (!isFn(bid.getFloor)) { return 0; } let floorResult = bid.getFloor({ - currency: currency, + currency: DEFAULT_CURRENCY, mediaType: mediaType, size: '*' }); - return floorResult.currency === currency && floorResult.floor ? floorResult.floor : 0; + return floorResult.currency === DEFAULT_CURRENCY && floorResult.floor ? floorResult.floor : 0; } /** @@ -296,7 +295,6 @@ function generateBidParameters(bid, bidderRequest) { const {params} = bid; const mediaType = isBanner(bid) ? BANNER : VIDEO; const sizesArray = getSizesArray(bid, mediaType); - const currency = params.currency || config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY; // fix floor price in case of NAN if (isNaN(params.floorPrice)) { params.floorPrice = 0; @@ -306,8 +304,7 @@ function generateBidParameters(bid, bidderRequest) { mediaType, adUnitCode: getBidIdParameter('adUnitCode', bid), sizes: sizesArray, - currency: currency, - floorPrice: Math.max(getFloor(bid, mediaType, currency), params.floorPrice), + floorPrice: Math.max(getFloor(bid, mediaType), params.floorPrice), bidId: getBidIdParameter('bidId', bid), bidderRequestId: getBidIdParameter('bidderRequestId', bid), loop: getBidIdParameter('bidderRequestsCount', bid), diff --git a/modules/riseBidAdapter.md b/modules/riseBidAdapter.md index ac0ea559c88..94d36a08510 100644 --- a/modules/riseBidAdapter.md +++ b/modules/riseBidAdapter.md @@ -26,8 +26,6 @@ The adapter supports Video(instream). | `testMode` | optional | Boolean | This activates the test mode | false | `rtbDomain` | optional | String | Sets the seller end point | "www.test.com" | `is_wrapper` | private | Boolean | Please don't use unless your account manager asked you to | false -| `currency` | optional | String | 3 letters currency | "EUR" - # Test Parameters ```javascript diff --git a/test/spec/modules/riseBidAdapter_spec.js b/test/spec/modules/riseBidAdapter_spec.js index ec9309fd4ae..3cb5cb5c154 100644 --- a/test/spec/modules/riseBidAdapter_spec.js +++ b/test/spec/modules/riseBidAdapter_spec.js @@ -201,16 +201,6 @@ describe('riseAdapter', function () { expect(request.data.bids[1].mediaType).to.equal(BANNER) }); - it('should send the correct currency in bid request', function () { - const bid = utils.deepClone(bidRequests[0]); - bid.params = { - 'currency': 'EUR' - }; - const expectedCurrency = bid.params.currency; - const request = spec.buildRequests([bid], bidderRequest); - expect(request.data.bids[0].currency).to.equal(expectedCurrency); - }); - it('should respect syncEnabled option', function() { config.setConfig({ userSync: { From 3cb4c1631abd0f31d359ad24fd6c5656819cf804 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 1 May 2024 14:51:08 +0000 Subject: [PATCH 081/147] Prebid 8.47.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c9bddfaf06..1dffbcec331 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.47.0-pre", + "version": "8.47.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 7236e62b5d4..6e5022bcece 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.47.0-pre", + "version": "8.47.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 54c87ba4ac6c0d1de14e8855e10edf6197e9ce57 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 1 May 2024 14:51:09 +0000 Subject: [PATCH 082/147] Increment version to 8.48.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1dffbcec331..e7621c210f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.47.0", + "version": "8.48.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 6e5022bcece..acac0a99da7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.47.0", + "version": "8.48.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From f4d0ef011491811e5bb426ffc2e92038ea00b233 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 09:44:08 -0600 Subject: [PATCH 083/147] Bump ejs from 3.1.9 to 3.1.10 (#11432) Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](https://github.com/mde/ejs/compare/v3.1.9...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7621c210f1..261cbdb1fb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "8.43.0-pre", + "version": "8.48.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -10979,9 +10979,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "dependencies": { "jake": "^10.8.5" @@ -37620,9 +37620,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, "requires": { "jake": "^10.8.5" From 3350dee8ee32e07941d7871caf66b75bd66dc93b Mon Sep 17 00:00:00 2001 From: ecdrsvc <82906140+ecdrsvc@users.noreply.github.com> Date: Wed, 1 May 2024 17:16:33 -0400 Subject: [PATCH 084/147] Add lmpIdSystem userId submodule (#11431) Co-authored-by: Antoine Niek --- modules/.submodules.json | 1 + modules/lmpIdSystem.js | 61 +++++++++++++ modules/lmpIdSystem.md | 27 ++++++ modules/userId/userId.md | 3 + test/spec/modules/lmpIdSystem_spec.js | 124 ++++++++++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 modules/lmpIdSystem.js create mode 100644 modules/lmpIdSystem.md create mode 100644 test/spec/modules/lmpIdSystem_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index 8409ea9918d..9dfeaf910f8 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -26,6 +26,7 @@ "justIdSystem", "kinessoIdSystem", "liveIntentIdSystem", + "lmpIdSystem", "lockrAIMIdSystem", "lotamePanoramaIdSystem", "merkleIdSystem", diff --git a/modules/lmpIdSystem.js b/modules/lmpIdSystem.js new file mode 100644 index 00000000000..b6dcae3118b --- /dev/null +++ b/modules/lmpIdSystem.js @@ -0,0 +1,61 @@ +/** + * This module adds lmpId support to the User ID module + * The {@link module:modules/userId} module is required. + * @module modules/lmpIdSystem + * @requires module:modules/userId + */ + +import { submodule } from '../src/hook.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const MODULE_NAME = 'lmpid'; +const STORAGE_KEY = '__lmpid'; +export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); + +function readFromLocalStorage() { + return storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage(STORAGE_KEY) : null; +} + +function getLmpid() { + return window[STORAGE_KEY] || readFromLocalStorage(); +} + +/** @type {Submodule} */ +export const lmpIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + + /** + * decode the stored id value for passing to bid requests + * @function + * @param { string | undefined } value + * @return { {lmpid: string} | undefined } + */ + decode(value) { + return value ? { lmpid: value } : undefined; + }, + + /** + * Retrieve the LMPID + * @function + * @param {SubmoduleConfig} config + * @return {{id: string | undefined} | undefined} + */ + getId(config) { + const id = getLmpid(); + return id ? { id } : undefined; + }, + + eids: { + 'lmpid': { + source: 'loblawmedia.ca', + atype: 3 + }, + } +}; + +submodule('userId', lmpIdSubmodule); diff --git a/modules/lmpIdSystem.md b/modules/lmpIdSystem.md new file mode 100644 index 00000000000..a56c9dbb3d6 --- /dev/null +++ b/modules/lmpIdSystem.md @@ -0,0 +1,27 @@ +# LMPID + +The Loblaw Media Private ID (LMPID) is the Loblaw Advance identity solution deployed by its media partners. LMPID leverages encrypted user registration information to provide a privacy-conscious, secure, and reliable identifier to power Loblaw Advance's digital advertising ecosystem. + +## LMPID Registration + +If you're a media company looking to partner with Loblaw Advance, please reach out to us through our [Contact page](https://www.loblawadvance.ca/contact-us) + +## LMPID Configuration + +First, make sure to add the LMPID submodule to your Prebid.js package with: + +``` +gulp build --modules=lmpIdSystem,userId +``` + +The following configuration parameters are available: + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'lmpid' + }] + } +}); +``` diff --git a/modules/userId/userId.md b/modules/userId/userId.md index 7a01e128814..1ec109ff309 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -358,6 +358,9 @@ pbjs.setConfig({ }, { name: 'naveggId', + }, + { + name: 'lmpid', }], syncDelay: 5000 } diff --git a/test/spec/modules/lmpIdSystem_spec.js b/test/spec/modules/lmpIdSystem_spec.js new file mode 100644 index 00000000000..37c7351f143 --- /dev/null +++ b/test/spec/modules/lmpIdSystem_spec.js @@ -0,0 +1,124 @@ +import { expect } from 'chai'; +import { find } from 'src/polyfill.js'; +import { config } from 'src/config.js'; +import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js'; +import { storage, lmpIdSubmodule } from 'modules/lmpIdSystem.js'; +import { mockGdprConsent } from '../../helpers/consentData.js'; + +function getConfigMock() { + return { + userSync: { + syncDelay: 0, + userIds: [{ + name: 'lmpid' + }] + } + } +} + +function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: { banner: {}, native: {} }, + sizes: [ + [300, 200], + [300, 600] + ], + bids: [{ + bidder: 'sampleBidder', + params: { placementId: 'banner-only-bidder' } + }] + }; +} + +describe('LMPID System', () => { + let getDataFromLocalStorageStub, localStorageIsEnabledStub; + let windowLmpidStub; + + beforeEach(() => { + window.__lmpid = undefined; + windowLmpidStub = sinon.stub(window, '__lmpid'); + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + }); + + afterEach(() => { + getDataFromLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); + windowLmpidStub.restore(); + }); + + describe('LMPID: test "getId" method', () => { + it('prefers the window cached LMPID', () => { + localStorageIsEnabledStub.returns(true); + getDataFromLocalStorageStub.withArgs('__lmpid').returns('stored-lmpid'); + + windowLmpidStub.value('lmpid'); + expect(lmpIdSubmodule.getId()).to.deep.equal({ id: 'lmpid' }); + }); + + it('fallbacks on localStorage when window cache is falsy', () => { + localStorageIsEnabledStub.returns(true); + getDataFromLocalStorageStub.withArgs('__lmpid').returns('stored-lmpid'); + + windowLmpidStub.value(''); + expect(lmpIdSubmodule.getId()).to.deep.equal({ id: 'stored-lmpid' }); + + windowLmpidStub.value(false); + expect(lmpIdSubmodule.getId()).to.deep.equal({ id: 'stored-lmpid' }); + }); + + it('fallbacks only if localStorageIsEnabled', () => { + localStorageIsEnabledStub.returns(false); + getDataFromLocalStorageStub.withArgs('__lmpid').returns('stored-lmpid'); + + expect(lmpIdSubmodule.getId()).to.be.undefined; + }); + }); + + describe('LMPID: test "decode" method', () => { + it('provides the lmpid from a stored object', () => { + expect(lmpIdSubmodule.decode('lmpid')).to.deep.equal({ lmpid: 'lmpid' }); + }); + }); + + describe('LMPID: requestBids hook', () => { + let adUnits; + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + mockGdprConsent(sandbox); + adUnits = [getAdUnitMock()]; + init(config); + setSubmoduleRegistry([lmpIdSubmodule]); + getDataFromLocalStorageStub.withArgs('__lmpid').returns('stored-lmpid'); + localStorageIsEnabledStub.returns(true); + config.setConfig(getConfigMock()); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('when a stored LMPID exists it is added to bids', (done) => { + requestBidsHook(() => { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.lmpid'); + expect(bid.userId.lmpid).to.equal('stored-lmpid'); + const lmpidAsEid = find(bid.userIdAsEids, e => e.source == 'loblawmedia.ca'); + expect(lmpidAsEid).to.deep.equal({ + source: 'loblawmedia.ca', + uids: [{ + id: 'stored-lmpid', + atype: 3, + }] + }); + }); + }); + done(); + }, { adUnits }); + }); + }); +}); From 8c72bc2239e3f9adbb14b40ec211b2be8eb8a0fb Mon Sep 17 00:00:00 2001 From: Giuseppe Cera <117671343+giuseppe-exads@users.noreply.github.com> Date: Thu, 2 May 2024 14:31:04 +0100 Subject: [PATCH 085/147] EXADS Bid Adapter: initial release (#11284) * First commit * fix: readme.md * fix: changed exads urls * fix: Tools and suggestions related to the doc * fix: from code review * fix: from code review * fix: from code review * fix: error from code review - native example * fox: from code review * fix: from code review * fix: from code review * fix: native img set as mandatory * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: bidfloor and bidfloorcur set as optional * fix: dsa * fix: mananing multiple responses * fix: unit test after code review * fix: fixing native snippet code * fix: from code review * fix: video events after code review * fix: video module into documentation * fix: impression tracker for native * fix: afeter code review * fix: unit tests * fix: added badv and bcat * fix: video -> mimes and protocols * fix * fix: removed image_output and video_output params, forcing always html for rtb banner * fix: gulp * fix: added site.name * fix: removed EXADS dir * fix: after linting * fix: unit tests * fix: final dsa solution * fix: dsa * fix: fix instream example * fix: doc media type context * fix: documented the endpoint param into native section * fix: related to markdown lint validation (#2) * fix: from CR (#3) --------- Co-authored-by: tfoliveira --- modules/exadsBidAdapter.js | 514 ++++++++++++++++++ modules/exadsBidAdapter.md | 484 +++++++++++++++++ test/spec/modules/exadsBidAdapter_spec.js | 632 ++++++++++++++++++++++ 3 files changed, 1630 insertions(+) create mode 100644 modules/exadsBidAdapter.js create mode 100644 modules/exadsBidAdapter.md create mode 100644 test/spec/modules/exadsBidAdapter_spec.js diff --git a/modules/exadsBidAdapter.js b/modules/exadsBidAdapter.js new file mode 100644 index 00000000000..31d75db470d --- /dev/null +++ b/modules/exadsBidAdapter.js @@ -0,0 +1,514 @@ +import * as utils from '../src/utils.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const BIDDER = 'exadsadserver'; + +const PARTNERS = { + ORTB_2_4: 'ortb_2_4' +}; + +const GVL_ID = 1084; + +const htmlImageOutput = 'html'; +const htmlVideoOutput = 'html'; + +const adPartnerHandlers = { + [PARTNERS.ORTB_2_4]: { + request: handleReqORTB2Dot4, + response: handleResORTB2Dot4, + validation: handleValidORTB2Dot4 + } +}; + +function handleReqORTB2Dot4(validBidRequest, endpointUrl, bidderRequest) { + utils.logInfo(`Calling endpoint for ortb_2_4:`, endpointUrl); + const gdprConsent = getGdprConsentChoice(bidderRequest); + const envParams = getEnvParams(); + + // Make a dynamic bid request to the ad partner's endpoint + let bidRequestData = { + 'id': validBidRequest.bidId, // NOT bid.bidderRequestId or bid.auctionId + 'at': 1, + 'imp': [], + 'bcat': validBidRequest.params.bcat, + 'badv': validBidRequest.params.badv, + 'site': { + 'id': validBidRequest.params.siteId, + 'name': validBidRequest.params.siteName, + 'domain': envParams.domain, + 'page': envParams.page, + 'keywords': validBidRequest.params.keywords + }, + 'device': { + 'ua': envParams.userAgent, + 'ip': validBidRequest.params.userIp, + 'geo': { + 'country': validBidRequest.params.country + }, + 'language': envParams.lang, + 'os': envParams.osName, + 'js': 0, + 'ext': { + 'accept_language': envParams.language + } + }, + 'user': { + 'id': validBidRequest.params.userId, + }, + 'ext': { + 'sub': 0, + 'prebid': { + 'channel': { + 'name': 'pbjs', + 'version': '$prebid.version$' + } + } + } + }; + + if (gdprConsent && gdprConsent.gdprApplies) { + bidRequestData.user['ext'] = { + consent: gdprConsent.consentString + } + } + + if (validBidRequest.params.dsa && ( + hasValue(validBidRequest.params.dsa.dsarequired) || + hasValue(validBidRequest.params.dsa.pubrender) || + hasValue(validBidRequest.params.dsa.datatopub))) { + bidRequestData.regs = { + 'ext': { + 'dsa': { + 'dsarequired': validBidRequest.params.dsa.dsarequired, + 'pubrender': validBidRequest.params.dsa.pubrender, + 'datatopub': validBidRequest.params.dsa.datatopub + } + } + } + } + + const impData = imps.get(validBidRequest.params.impressionId); + + // Banner setup + const bannerMediaType = utils.deepAccess(validBidRequest, 'mediaTypes.banner'); + if (bannerMediaType != null) { + impData.mediaType = BANNER; + bidRequestData.imp = bannerMediaType.sizes.map(size => { + return ({ + 'id': validBidRequest.params.impressionId, + 'bidfloor': validBidRequest.params.bidfloor, + 'bidfloorcur': validBidRequest.params.bidfloorcur, + 'banner': { + 'w': size[0], + 'h': size[1], + 'mimes': validBidRequest.params.mimes ? validBidRequest.params.mimes : undefined, + 'ext': { + image_output: htmlImageOutput, + video_output: htmlVideoOutput, + } + }, + }); + }); + } + + const nativeMediaType = utils.deepAccess(validBidRequest, 'mediaTypes.native'); + + if (nativeMediaType != null) { + impData.mediaType = NATIVE; + const nativeVersion = '1.2'; + + const native = { + 'native': { + 'ver': nativeVersion, + 'plcmttype': 4, + 'plcmtcnt': validBidRequest.params.native.plcmtcnt + } + }; + + native.native.assets = bidRequestData.imp = nativeMediaType.ortb.assets.map(asset => { + const newAsset = asset; + if (newAsset.img != null) { + newAsset.img.wmin = newAsset.img.h; + newAsset.img.hmin = newAsset.img.w; + } + return newAsset; + }); + + const imp = [{ + 'id': validBidRequest.params.impressionId, + 'bidfloor': validBidRequest.params.bidfloor, + 'bidfloorcur': validBidRequest.params.bidfloorcur, + 'native': { + 'request': JSON.stringify(native), + 'ver': nativeVersion + }, + }]; + + bidRequestData.imp = imp; + }; + + const videoMediaType = utils.deepAccess(validBidRequest, 'mediaTypes.video'); + + if (videoMediaType != null) { + impData.mediaType = VIDEO; + const imp = [{ + 'id': validBidRequest.params.impressionId, + 'bidfloor': validBidRequest.params.bidfloor, + 'bidfloorcur': validBidRequest.params.bidfloorcur, + 'video': { + 'mimes': videoMediaType.mimes, + 'protocols': videoMediaType.protocols, + }, + 'ext': validBidRequest.params.imp.ext + }]; + + bidRequestData.imp = imp; + } + + utils.logInfo('PAYLOAD', bidRequestData, JSON.stringify(bidRequestData)); + utils.logInfo('FINAL URL', endpointUrl); + + return makeBidRequest(endpointUrl, bidRequestData); +}; + +function handleResORTB2Dot4(serverResponse, request, adPartner) { + utils.logInfo('on handleResORTB2Dot4 -> request:', request); + utils.logInfo('on handleResORTB2Dot4 -> request json data:', JSON.parse(request.data)); + utils.logInfo('on handleResORTB2Dot4 -> serverResponse:', serverResponse); + + let bidResponses = []; + const bidRq = JSON.parse(request.data); + + if (serverResponse.hasOwnProperty('body') && serverResponse.body.hasOwnProperty('id')) { + utils.logInfo('Ad server response', serverResponse.body.id); + + const requestId = serverResponse.body.id; + const currency = serverResponse.body.cur; + + serverResponse.body.seatbid.forEach((seatbid, seatIndex) => { + seatbid.bid.forEach((bidData, bidIndex) => { + utils.logInfo('serverResponse.body.seatbid[' + seatIndex + '].bid[' + bidIndex + ']', bidData); + + const bidResponseAd = bidData.adm; + const bannerInfo = utils.deepAccess(bidRq.imp[0], 'banner'); + const nativeInfo = utils.deepAccess(bidRq.imp[0], 'native'); + const videoInfo = utils.deepAccess(bidRq.imp[0], 'video'); + + let w; let h = 0; + let mediaType = ''; + const native = {}; + + if (bannerInfo != null) { + w = bidRq.imp[0].banner.w; + h = bidRq.imp[0].banner.h; + mediaType = BANNER; + } else if (nativeInfo != null) { + const responseADM = JSON.parse(bidResponseAd); + responseADM.native.assets.forEach(asset => { + if (asset.img != null) { + const imgAsset = JSON.parse(bidRq.imp[0].native.request) + .native.assets.filter(asset => asset.img != null).map(asset => asset.img); + w = imgAsset[0].w; + h = imgAsset[0].h; + native.image = { + url: asset.img.url, + height: h, + width: w + } + } else if (asset.title != null) { + native.title = asset.title.text; + } else if (asset.data != null) { + native.body = asset.data.value; + } else { + utils.logWarn('bidResponse->', 'wrong asset type or null'); + } + }); + + if (responseADM.native) { + if (responseADM.native.link) { + native.clickUrl = responseADM.native.link.url; + } + if (responseADM.native.eventtrackers) { + native.impressionTrackers = []; + + responseADM.native.eventtrackers.forEach(tracker => { + if (tracker.method == 1) { + native.impressionTrackers.push(tracker.url); + } + }); + } + } + mediaType = NATIVE; + } else if (videoInfo != null) { + mediaType = VIDEO; + } + + const metaData = {}; + + if (hasValue(bidData.ext.dsa)) { + metaData.dsa = bidData.ext.dsa; + } + + const bidResponse = { + requestId: requestId, + currency: currency, + ad: bidData.adm, + cpm: bidData.price, + creativeId: bidData.crid, + cid: bidData.cid, + width: w, + ttl: 360, + height: h, + netRevenue: true, + mediaType: mediaType, + meta: metaData, + nurl: bidData.nurl.replace(/^http:\/\//i, 'https://') + }; + + if (mediaType == 'native') { + bidResponse.native = native; + } + + if (mediaType == 'video') { + bidResponse.vastXml = bidData.adm; + bidResponse.width = bidData.w; + bidResponse.height = bidData.h; + } + + utils.logInfo('bidResponse->', bidResponse); + + bidResponses.push(bidResponse); + }); + }); + } else { + imps.delete(bidRq.imp[0].id); + utils.logInfo('NO Ad server response ->', serverResponse.body.id); + } + + utils.logInfo('interpretResponse -> bidResponses:', bidResponses); + + return bidResponses; +} + +function makeBidRequest(url, data) { + const payloadString = JSON.stringify(data); + + return { + method: 'POST', + url: url, + data: payloadString + } +} + +function getUrl(adPartner, bid) { + let endpointUrlMapping = { + [PARTNERS.ORTB_2_4]: bid.params.endpoint + '?idzone=' + bid.params.zoneId + '&fid=' + bid.params.fid + }; + + return endpointUrlMapping[adPartner] ? endpointUrlMapping[adPartner] : 'defaultEndpoint'; +} + +function getEnvParams() { + const envParams = { + lang: '', + userAgent: '', + osName: '', + page: '', + domain: '', + language: '' + }; + + envParams.domain = window.location.hostname; + envParams.page = window.location.protocol + '//' + window.location.host + window.location.pathname; + envParams.lang = navigator.language.indexOf('-') > -1 + ? navigator.language.split('-')[0] + : navigator.language; + envParams.userAgent = navigator.userAgent; + + if (envParams.userAgent.match(/Windows/i)) { + envParams.osName = 'Windows'; + } else if (envParams.userAgent.match(/Mac OS|Macintosh/i)) { + envParams.osName = 'MacOS'; + } else if (envParams.userAgent.match(/Unix/i)) { + envParams.osName = 'Unix'; + } else if (envParams.userAgent.userAgent.match(/Android/i)) { + envParams.osName = 'Android'; + } else if (envParams.userAgent.userAgent.match(/iPhone|iPad|iPod/i)) { + envParams.osName = 'iOS'; + } else if (envParams.userAgent.userAgent.match(/Linux/i)) { + envParams.osName = 'Linux'; + } else { + envParams.osName = 'Unknown'; + } + + let browserLanguage = navigator.language || navigator.userLanguage; + let acceptLanguage = browserLanguage.replace('_', '-'); + + envParams.language = acceptLanguage; + + utils.logInfo('Domain -> ', envParams.domain); + utils.logInfo('Page -> ', envParams.page); + utils.logInfo('Lang -> ', envParams.lang); + utils.logInfo('OS -> ', envParams.osName); + utils.logInfo('User Agent -> ', envParams.userAgent); + utils.logInfo('Primary Language -> ', envParams.language); + + return envParams; +} + +export const imps = new Map(); + +/* + Common mandatory parameters: + - endpoint + - userIp + - userIp - the minimum constraint is having the propery, empty or not + - zoneId + - partner + - fid + - siteId + - impressionId + - country + - mediaTypes?.banner or mediaTypes?.native or mediaTypes?.video + + for native parameters + - assets - it should contain the img property + + for video parameters + - mimes - it has to contain one mime type at least + - procols - it should contain one protocol at least + +*/ +function handleValidORTB2Dot4(bid) { + const bannerInfo = bid.mediaTypes?.banner; + const nativeInfo = bid.mediaTypes?.native; + const videoInfo = bid.mediaTypes?.video; + const isValid = ( + hasValue(bid.params.endpoint) && + hasValue(bid.params.userIp) && + bid.params.hasOwnProperty('userIp') && + hasValue(bid.params.zoneId) && + hasValue(bid.params.partner) && + hasValue(bid.params.fid) && + hasValue(bid.params.siteId) && + hasValue(bid.params.impressionId) && + hasValue(bid.params.country) && + hasValue(bid.params.country.length > 0) && + ((!hasValue(bid.params.bcat) || + bid.params.bcat.length > 0)) && + ((!hasValue(bid.params.badv) || + bid.params.badv.length > 0)) && + (bannerInfo || nativeInfo || videoInfo) && + (nativeInfo ? bid.params.native && + nativeInfo.ortb.assets && + nativeInfo.ortb.assets.some(asset => !!asset.img) : true) && + (videoInfo ? (videoInfo.mimes && + videoInfo.mimes.length > 0 && + videoInfo.protocols && + videoInfo.protocols.length > 0) : true)); + if (!isValid) { + utils.logError('Validation Error'); + } + + return isValid; +} + +function hasValue(value) { + return ( + value !== undefined && + value !== null + ); +} + +function getGdprConsentChoice(bidderRequest) { + const hasGdprConsent = + hasValue(bidderRequest) && + hasValue(bidderRequest.gdprConsent); + + if (hasGdprConsent) { + return bidderRequest.gdprConsent; + } + + return null; +} + +export const spec = { + aliases: ['exads'], // short code + supportedMediaTypes: [BANNER, NATIVE, VIDEO], + isBidRequestValid: function (bid) { + utils.logInfo('on isBidRequestValid -> bid:', bid); + + if (!bid.params.partner) { + utils.logError('Validation Error', 'bid.params.partner missed'); + return false; + } else if (!Object.values(PARTNERS).includes(bid.params.partner)) { + utils.logError('Validation Error', 'bid.params.partner is not valid'); + return false; + } + + let adPartner = bid.params.partner; + + if (adPartnerHandlers[adPartner] && adPartnerHandlers[adPartner]['validation']) { + return adPartnerHandlers[adPartner]['validation'](bid); + } else { + // Handle unknown or unsupported ad partners + return false; + } + }, + buildRequests: function (validBidRequests, bidderRequest) { + utils.logInfo('on buildRequests -> validBidRequests:', validBidRequests); + utils.logInfo('on buildRequests -> bidderRequest:', bidderRequest); + + return validBidRequests.map(bid => { + let adPartner = bid.params.partner; + + imps.set(bid.params.impressionId, { adPartner: adPartner, mediaType: null }); + + let endpointUrl = getUrl(adPartner, bid); + + // Call the handler for the ad partner, passing relevant parameters + if (adPartnerHandlers[adPartner]['request']) { + return adPartnerHandlers[adPartner]['request'](bid, endpointUrl, bidderRequest); + } else { + // Handle unknown or unsupported ad partners + return null; + } + }); + }, + interpretResponse: function (serverResponse, request) { + const bid = JSON.parse(request.data); + const impData = imps.get(bid.imp[0].id); + const adPartner = impData.adPartner; + + // Call the handler for the ad partner, passing relevant parameters + if (adPartnerHandlers[adPartner]['response']) { + return adPartnerHandlers[adPartner]['response'](serverResponse, request, adPartner); + } else { + // Handle unknown or unsupported ad partners + return null; + } + }, + onTimeout: function (timeoutData) { + utils.logWarn(`onTimeout -> timeoutData:`, timeoutData); + }, + onBidWon: function (bid) { + utils.logInfo(`onBidWon -> bid:`, bid); + if (bid.nurl) { + utils.triggerPixel(bid.nurl); + } + }, + onSetTargeting: function (bid) { + utils.logInfo(`onSetTargeting -> bid:`, bid); + }, + onBidderError: function (bid) { + imps.delete(bid.bidderRequest.bids[0].params.impressionId); + utils.logInfo('onBidderError -> bid:', bid); + }, +}; + +registerBidder({ + code: BIDDER, + gvlid: GVL_ID, + ...spec +}); diff --git a/modules/exadsBidAdapter.md b/modules/exadsBidAdapter.md new file mode 100644 index 00000000000..06b873d8da8 --- /dev/null +++ b/modules/exadsBidAdapter.md @@ -0,0 +1,484 @@ +# Overview + +**Module Name**: Exads Bidder Adapter + +**Module Type**: Bidder Adapter + +**Maintainer**: + +## Description + +Module that connects to EXADS' bidder for bids. + +## Build + +If you don't need to use the prebidJS video module, please remove the videojsVideoProvider module. + +```bash +gulp build --modules=consentManagement,exadsBidAdapter,videojsVideoProvider +``` + +### Configuration + +Use `setConfig` to instruct Prebid.js to initilize the exadsBidAdapter, as specified below. + +* Set "debug" as true if you need to read logs; +* Set "gdprApplies" as true if you need to pass gdpr consent string; +* The tcString is the iabtcf consent string for gdpr; +* Uncomment the cache instruction if you need to configure a cache server (e.g. for instream video) + +```js +pbjs.setConfig({ + debug: false, + //cache: { url: "https://prebid.adnxs.com/pbc/v1/cache" }, + consentManagement: { + gdpr: { + cmpApi: 'static', + timeout: 1000000, + defaultGdprScope: true, + consentData: { + getTCData: { + tcString: consentString, + gdprApplies: false // set to true to pass the gdpr consent string + } + } + } + } +}); +``` + +Add the `video` config if you need to render videos using the video module. +For more info navigate to . + +```js +pbjs.setConfig({ + video: { + providers: [{ + divId: 'player', // the id related to the videojs tag in your body + vendorCode: 2, // videojs, + playerConfig: { + params: { + adPluginConfig: { + numRedirects: 10 + }, + vendorConfig: { + controls: true, + autoplay: true, + preload: "auto", + } + } + } + },] + }, +}); +``` + +### Test Parameters + +Now you will find the different parameters to set, based on publisher website. They are optional unless otherwise specified. + +#### RTB Banner 2.4 + +* **zoneId** (required) - you can get it from the endpoint created after configuring the zones (integer) +* **fid** (required) - you can get it from the endpoint created after configuring the zones (string) +* **partner** (required) - currently we support rtb 2.4 ("ortb_2_4") only (string) +* **siteId** (recommended) - unique Site ID (string) +* **siteName** site name (string) +* **banner.sizes** (required) - one integer array - [width, height] +* **userIp** (required) - IP address of the user, ipv4 or ipv6 (string) +* **userId** (*required) - unique user ID (string).*If you cannot generate a user ID, you can leave it empty (""). The request will get a response as long as "user" object is included in the request +* **country** - country ISO3 +* **impressionId** (required) - unique impression ID within this bid request (string) +* **keywords** - keywords can be used to ensure ad zones get the right type of advertising. Keywords should be a string of comma-separated words +* **bidfloor** - minimum bid for this impression (CPM) / click (CPC) and account currency (float) +* **bidfloorcur** - currency for minimum bid value specified using ISO-4217 alpha codes (string) +* **bcat** - blocked advertiser categories using the IAB content categories (string array) +* **badv** - block list of advertisers by their domains (string array) +* **mimes** - list of supported mime types. We support: image/jpeg, image/jpg, image/png, image/png, image/gif, image/webp, video/mp4 (string array) +* **dsa** - DSA transparency information + * **dsarequired** - flag to indicate if DSA information should be made available (integer) + *0 - Not required + * 1 - Supported, bid responses with or without DSA object will be accepted + *2 - Required, bid responses without DSA object will not be accepted + * 3 - Required, bid responses without DSA object will not be accepted, Publisher is an Online Platform + * **pubrender** - flag to indicate if the publisher will render the DSA Transparency info (integer) + * 0 - Publisher can't render + * 1 - Publisher could render depending on adrender + * 2 - Publisher will render + * **datatopub** - independent of pubrender, the publisher may need the transparency data for audit purposes (integer) + * 0 - do not send transparency data + * 1 - optional to send transparency data + * 2 - send transparency data +* **endpoint** (required) - EXADS endpoint (URL) + +##### RTB Banner 2.4 (Image) + +```js + +adUnits = + [{ code: 'postbid_iframe', // the frame where to render the creative + mediaTypes: { + banner: { + sizes: [300, 250] + } + }, + bids: [{ + bidder: 'exadsadserver', + params: { + zoneId: 12345, + fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', + partner: 'ortb_2_4', + siteId: '123', + siteName: 'test.com', + userIp: '0.0.0.0', + userId: '1234', + country: 'IRL', + impressionId: impression_id.toString(), + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + bcat: ['IAB25', 'IAB7-39','IAB8-18','IAB8-5','IAB9-9'], + badv: ['first.com', 'second.com'], + mimes: ['image/jpg'], + dsa: { + dsarequired: 3, + pubrender: 0, + datatopub: 2 + }, + endpoint: 'https://your-ad-network.com/rtb.php' + } + }] + }]; +``` + +##### RTB Banner 2.4 (Video) + +```js +adUnits = + [{ code: 'postbid_iframe', // the frame where to render the creative + mediaTypes: { + banner: { + sizes: [900, 250] + } + }, + bids: [{ + bidder: 'exadsadserver', + params: { + zoneId: 12345, + fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', + partner: 'ortb_2_4', + siteId: '123', + siteName: 'test.com', + userIp: '0.0.0.0', + userId: '1234', + country: 'IRL', + impressionId: '1234', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + bcat: ['IAB25', 'IAB7-39','IAB8-18','IAB8-5','IAB9-9'], + badv: ['first.com', 'second.com'], + mimes: ['image/jpg'], + dsa: { + dsarequired: 3, + pubrender: 0, + datatopub: 2 + }, + endpoint: 'https://your-ad-network.com/rtb.php' + } + }] + }]; +``` + +#### RTB 2.4 Video (Instream/OutStream/Video Slider) - VAST XML or VAST TAG (url) + +* **zoneId** (required) - you can get it from the endpoint created after configuring the zones (integer) +* **fid** (required) - you can get it from the endpoint created after configuring the zones (string) +* **partner** (required) - currently we support rtb 2.4 ("ortb_2_4") only (string) +* **siteId** (recommended) - unique Site ID (string) +* **siteName** site name (string) +* **userIp** (required) - IP address of the user, ipv4 or ipv6 (string) +* **userId** (required) - unique user ID (string). *If you cannot generate a user ID, you can leave it empty (""). The request will get a response as long as "user" object is included in the request +* **country** - Country ISO3 (string) +* **impressionId** (required) - unique impression ID within this bid request (string) +* **keywords** - keywords can be used to ensure ad zones get the right type of advertising. Keywords should be a string of comma-separated words +* **bidfloor** - minimum bid for this impression (CPM) / click (CPC) and account currency (float) +* **bidfloorcur** - currency for minimum bid value specified using ISO-4217 alpha codes (string) +* **bcat** - blocked advertiser categories using the IAB content categories (string array) +* **badv** - block list of advertisers by their domains (string array) +* **mediaTypes.video** (required) + * **mimes** (required) - list of supported mime types (string array) + * **protocols** (required) - list of supported video bid response protocols (integer array) + * **context** - (recommended) - the video context, either 'instream', 'outstream'. Defaults to ‘instream’ (string) +* **dsa** - DSA transparency information + * **dsarequired** - flag to indicate if DSA information should be made available (integer) + *0 - Not required + * 1 - Supported, bid responses with or without DSA object will be accepted + *2 - Required, bid responses without DSA object will not be accepted + * 3 - Required, bid responses without DSA object will not be accepted, Publisher is an Online Platform + * **pubrender** - flag to indicate if the publisher will render the DSA Transparency info (integer) + * 0 - Publisher can't render + * 1 - Publisher could render depending on adrender + * 2 - Publisher will render + * **datatopub** - independent of pubrender, the publisher may need the transparency data for audit purposes (integer) + * 0 - do not send transparency data + * 1 - optional to send transparency data + * 2 - send transparency data +* **endpoint** (required) - EXADS endpoint (URL) + +```js +adUnits = [{ + code: 'postbid_iframe', + mediaTypes: { + video: { + mimes: ['video/mp4'], + context: 'instream', + protocols: [3, 6] + } + }, + bids: [{ + bidder: 'exadsadserver', + params: { + zoneId: 12345, + fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', + partner: 'ortb_2_4', + siteId: '123', + siteName: 'test.com', + userIp: '0.0.0.0', + userId: '1234', + impressionId: '1234', + imp: { + ext: { + video_cta: 0 + } + }, + dsa: { + dsarequired: 3, + pubrender: 0, + datatopub: 2 + }, + country: 'IRL', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + bcat: ['IAB25', 'IAB7-39','IAB8-18','IAB8-5','IAB9-9'], + badv: ['first.com', 'second.com'], + endpoint: 'https://your-ad-network.com/rtb.php' + } + }] +}]; +``` + +#### RTB 2.4 Native + +* **zoneId** (required) - you can get it from the endpoint created after configuring the zones (integer) +* **fid** (required) - you can get it from the endpoint created after configuring the zones (string) +* **partner** (required) - currently we support rtb 2.4 ("ortb_2_4") only (string) +* **siteId** (recommended) - unique Site ID (string) +* **siteName** site name (string) +* **userIp** (required) - IP address of the user, ipv4 or ipv6 (string) +* **userId** (*required) - unique user ID (string).*If you cannot generate a user ID, you can leave it empty (""). The request will get a response as long as "user" object is included in the request +* **country** - country ISO3 (string) +* **impressionId** (required) - unique impression ID within this bid request (string) +* **keywords** - keywords can be used to ensure ad zones get the right type of advertising. Keywords should be a string of comma-separated words +* **bidfloor** - minimum bid for this impression (CPM) / click (CPC) and account currency (float) +* **bidfloorcur** - currency for minimum bid value specified using ISO-4217 alpha codes (string) +* **bcat** - blocked advertiser categories using the IAB content categories (string array) +* **badv** - block list of advertisers by their domains (string array) +* **dsa** - DSA transparency information + * **dsarequired** - flag to indicate if DSA information should be made available (integer) + *0 - Not required + * 1 - Supported, bid responses with or without DSA object will be accepted + *2 - Required, bid responses without DSA object will not be accepted + * 3 - Required, bid responses without DSA object will not be accepted, Publisher is an Online Platform + * **pubrender** - flag to indicate if the publisher will render the DSA Transparency info (integer) + * 0 - Publisher can't render + * 1 - Publisher could render depending on adrender + * 2 - Publisher will render + * **datatopub** - independent of pubrender, the publisher may need the transparency data for audit purposes (integer) + * 0 - do not send transparency data + * 1 - optional to send transparency data + * 2 - send transparency data +* **native.plcmtcnt** - the number of identical placements in this Layout (integer) +* **assets (title)** + * **id** - unique asset ID, assigned by exchange. Typically a counter for the array (integer): + *1 - image asset ID + * 2 - title asset ID + * 3 - description asset ID + * **required** - set to 1 if asset is required or 0 if asset is optional (integer) + * **title** + * len (required) - maximum length of the text in the title element (integer) +* **assets (data)** + * **id** - unique asset ID, assigned by exchange. Typically a counter for the array (integer): + *1 - image asset ID + * 2 - title asset ID + * 3 - description asset ID + * **data** + * **type** - type ID of the element supported by the publisher (integer). We support: + *1 - sponsored - sponsored By message where response should contain the brand name of the sponsor + * 2 - desc - descriptive text associated with the product or service being advertised + * **len** - maximum length of the text in the element’s response (integer) +* **assets (img)** + * **id** - unique asset ID, assigned by exchange. Typically a counter for the array (integer): + *1 - image asset ID + * 2 - title asset ID + * 3 - description asset ID + * **required** - set to 1 if asset is required or 0 if asset is optional (integer) + * **img** + * **type** - type ID of the image element supported by the publisher. We support: + *1 - icon image (integer) + * 3 - large image preview for the ad (integer) + * **w** - width of the image in pixels, optional (integer) + * **h** - height of the image in pixels, optional (integer) +* **endpoint** (required) - EXADS endpoint (URL) + +```js +adUnits = [{ + code: 'postbid_iframe', + mediaTypes: { + native: { + ortb: { + assets: [{ + id: 2, + required: 1, + title: { + len: 124 + } + }, + { + id: 3, + data: { + type: 1, + len: 50 + } + }, + { + id: 1, + required: 1, + img: { + type: 3, + w: 300, + h: 300 + } + }] + } + } + }, + bids: [{ + bidder: 'exadsadserver', + params: { + zoneId: 12345, + fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', + partner: 'ortb_2_4', + siteId: '123', + siteName: 'test.com', + userIp: '0.0.0.0', + userId: '1234', + impressionId: '1234', + native: { + plcmtcnt: 4 + }, + dsa: { + dsarequired: 3, + pubrender: 0, + datatopub: 2 + }, + country: 'IRL', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + bcat: ['IAB25', 'IAB7-39','IAB8-18','IAB8-5','IAB9-9'], + badv: ['first.com', 'second.com'], + endpoint: 'https://your-ad-network.com/rtb.php' + } + }] +}]; +``` + +## DSA Transparency + +All DSA information, returned by the ad server, can be found into the **meta** tag of the response. As: + +```js +"meta": { + "dsa": { + "behalf": "...", + "paid": "...", + "transparency": [ + { + "params": [ + ... + ] + } + ], + "adrender": ... + } +} +``` + +For more information navigate to . + +## Tools and suggestions + +This section contains some suggestions that allow to set some parameters automatically. + +### User Ip / Country + +In order to detect the current user ip there are different approaches. An example is using public web services as ```https://api.ipify.org```. + +Example of usage (to add to the publisher websites): + +```html + +``` + +The same service gives the possibility to detect the country as well. Check the official web page about possible limitations of the free licence. + +### Impression Id + +Each advertising request has to be identified uniquely by an id. +One possible approach is using a classical hash function. + +```html + +``` + +### User Id + +The approach used for impression id could be used for generating a unique user id. +Also, it is recommended to store the id locally, e.g. by the browser localStorage. + +```html + +``` diff --git a/test/spec/modules/exadsBidAdapter_spec.js b/test/spec/modules/exadsBidAdapter_spec.js new file mode 100644 index 00000000000..9253f21ddf1 --- /dev/null +++ b/test/spec/modules/exadsBidAdapter_spec.js @@ -0,0 +1,632 @@ +import { expect } from 'chai'; +import { spec, imps } from 'modules/exadsBidAdapter.js'; +import { BANNER, NATIVE, VIDEO } from '../../../src/mediaTypes.js'; + +describe('exadsBidAdapterTest', function () { + const bidder = 'exadsadserver'; + + const partners = { + ORTB_2_4: 'ortb_2_4' + }; + + const imageBanner = { + mediaTypes: { + banner: { + sizes: [300, 250] + } + }, + bidder: bidder, + params: { + zoneId: 5147485, + fid: '829a896f011475d505a0d89cfdd1af8d9cdb07ff', + partner: partners.ORTB_2_4, + siteId: '12345', + siteName: 'your-site.com', + catIab: ['IAB25-3'], + userIp: '0.0.0.0', + userId: '', + country: 'IRL', + impressionId: '123456', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + bcat: ['IAB25', 'IAB7-39', 'IAB8-18', 'IAB8-5', 'IAB9-9'], + badv: ['first.com', 'second.com'], + mimes: ['image/jpg'], + endpoint: 'test.com', + dsa: { + dsarequired: 3, + pubrender: 0, + datatopub: 2 + }, + } + }; + + const native = { + mediaTypes: { + native: { + ortb: { + assets: [{ + id: 3, + required: 1, + title: { + len: 124 + } + }, + { + id: 2, + data: { + type: 1, + len: 50 + } + }, + { + id: 1, + required: 1, + img: { + type: 3, + w: 300, + h: 300, + } + }] + } + }, + }, + bidder: bidder, + params: { + zoneId: 5147485, + fid: '829a896f011475d505a0d89cfdd1af8d9cdb07ff', + partner: partners.ORTB_2_4, + siteId: '12345', + siteName: 'your-site.com', + catIab: ['IAB25-3'], + userIp: '0.0.0.0', + userId: '', + country: 'IRL', + impressionId: '123456', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + native: { + plcmtcnt: 4, + }, + dsa: { + pubrender: 0, + datatopub: 2 + }, + endpoint: 'test.com' + } + }; + + const instream = { + mediaTypes: { + video: { + mimes: ['video/mp4'], + protocols: [3, 6], + } + }, + bidder: bidder, + params: { + zoneId: 5147485, + fid: '829a896f011475d505a0d89cfdd1af8d9cdb07ff', + partner: partners.ORTB_2_4, + siteId: '12345', + siteName: 'your-site.com', + catIab: ['IAB25-3'], + userIp: '0.0.0.0', + userId: '', + country: 'IRL', + impressionId: '123456', + keywords: 'lifestyle, humour', + bidfloor: 0.00000011, + bidfloorcur: 'EUR', + imp: { + ext: { + video_cta: 0 + } + }, + dsa: { + datatopub: 2 + }, + endpoint: 'test.com', + } + }; + + describe('while validating bid request', function () { + it('should check the validity of bidRequest with all mandatory params for banner ad-format', function () { + expect(spec.isBidRequestValid(imageBanner)).to.equal(true); + }); + + it('should check the validity of a bidRequest with all mandatory params for native ad-format', function () { + expect(spec.isBidRequestValid(native)); + }); + + it('should check the validity of a bidRequest with all mandatory params for instream ad-format', function () { + expect(spec.isBidRequestValid(instream)).to.equal(true); + }); + + it('should check the validity of a bidRequest with wrong partner', function () { + expect(spec.isBidRequestValid({ + ...imageBanner, + params: { + ...imageBanner.params, + partner: 'not_ortb_2_4' + } + })).to.eql(false); + }); + + it('should check the validity of a bidRequest without params', function () { + expect(spec.isBidRequestValid({ + bidder: bidder, + params: { } + })).to.equal(false); + }); + }); + + describe('while building bid request for banner ad-format', function () { + const bidRequests = [imageBanner]; + + it('should make a bidRequest by HTTP method', function () { + const requests = spec.buildRequests(bidRequests, {}); + requests.forEach(function(requestItem) { + expect(requestItem.method).to.equal('POST'); + }); + }); + }); + + describe('while building bid request for native ad-format', function () { + const bidRequests = [native]; + + it('should make a bidRequest by HTTP method', function () { + const requests = spec.buildRequests(bidRequests, {}); + requests.forEach(function(requestItem) { + expect(requestItem.method).to.equal('POST'); + }); + }); + }); + + describe('while building bid request for instream ad-format', function () { + const bidRequests = [instream]; + + it('should make a bidRequest by HTTP method', function () { + const requests = spec.buildRequests(bidRequests, {}); + requests.forEach(function(requestItem) { + expect(requestItem.method).to.equal('POST'); + }); + }); + }); + + describe('while interpreting bid response', function () { + beforeEach(() => { + imps.set('270544423272657', { adPartner: 'ortb_2_4', mediaType: null }); + }); + + it('should test the banner interpretResponse', function () { + const serverResponse = { + body: { + 'id': '2d2a496527398e', + 'seatbid': [ + { + 'bid': [ + { + 'id': '8f7fa506af97bc193e7bf099d8ed6930bd50aaf1', + 'impid': '270544423272657', + 'price': 0.0045000000000000005, + 'adm': '\n\n', + 'ext': { + 'btype': 1, + 'asset_mime_type': [ + 'image/jpeg', + 'image/jpg' + ] + }, + 'nurl': 'http://your-ad-network.com/', + 'cid': '6260389', + 'crid': '89453173', + 'adomain': [ + 'test.com' + ], + 'w': 300, + 'h': 250, + 'attr': [ + 12 + ] + } + ] + } + ], + 'cur': 'USD' + } + }; + + const bidResponses = spec.interpretResponse(serverResponse, { + data: JSON.stringify({ + 'id': '2d2a496527398e', + 'at': 1, + 'imp': [ + { + 'id': '270544423272657', + 'bidfloor': 1.1e-7, + 'bidfloorcur': 'EUR', + 'banner': { + 'w': 300, + 'h': 250 + } + } + ], + 'site': { + 'id': '12345', + 'domain': 'your-ad-network.com', + 'cat': [ + 'IAB25-3' + ], + 'page': 'https://your-ad-network.com/prebidJS-client-RTB-banner.html', + 'keywords': 'lifestyle, humour' + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', + 'ip': '95.233.216.174', + 'geo': { + 'country': 'ITA' + }, + 'language': 'en', + 'os': 'MacOS', + 'js': 0, + 'ext': { + 'remote_addr': '', + 'x_forwarded_for': '', + 'accept_language': 'en-GB' + } + }, + 'user': { + 'id': '' + }, + 'ext': { + 'sub': 0 + } + }) + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + + const bid = serverResponse.body.seatbid[0].bid[0]; + const bidResponse = bidResponses[0]; + + expect(bidResponse.mediaType).to.equal(BANNER); + expect(bidResponse.width).to.equal(bid.w); + expect(bidResponse.height).to.equal(bid.h); + }); + + it('should test the native interpretResponse', function () { + const serverResponse = { + body: { + 'id': '21dea1fc6c3e1b', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'cedc93987cd4a1e08fdfe97de97482d1ecc503ee', + 'impid': '270544423272657', + 'price': 0.0045000000000000005, + 'adm': '{"native":{"link":{"url":"https:\\/\\/your-ad-network.com"},"eventtrackers":[{"event":1,"method":1,"url":"https:\\/\\/your-ad-network.com"}],"assets":[{"id":1,"title":{"text":"Title"}},{"id":2,"data":{"value":"Description"}},{"id":3,"img":{"url":"https:\\/\\/your-ad-network.com\\/32167\\/f85ee87ea23.jpg"}}]}}', + 'ext': { + 'btype': 1, + 'asset_mime_type': [ + 'image/jpeg', + 'image/jpg' + ] + }, + 'nurl': 'http://your-ad-network.com', + 'cid': '6260393', + 'crid': '89453189', + 'adomain': [ + 'test.com' + ], + 'w': 300, + 'h': 300, + 'attr': [] + } + ] + } + ], + 'cur': 'USD' + } + }; + + const bidResponses = spec.interpretResponse(serverResponse, { + data: JSON.stringify({ + 'id': '21dea1fc6c3e1b', + 'at': 1, + 'imp': [ + { + 'id': '270544423272657', + 'bidfloor': 1.1e-7, + 'bidfloorcur': 'EUR', + 'native': { + 'request': '{"native":{"ver":"1.2","context":1,"contextsubtype":10,"plcmttype":4,"plcmtcnt":4,"assets":[{"id":1,"required":1,"title":{"len":124}},{"id":2,"data":{"type":1,"len":50}},{"id":3,"required":1,"img":{"type":3,"w":300,"h":300,"wmin":300,"hmin":300}}]}}', + 'ver': '1.2' + } + } + ], + 'site': { + 'id': '12345', + 'domain': 'your-ad-network.com', + 'cat': [ + 'IAB25-3' + ], + 'page': 'https://your-ad-network.com/prebidJS-client-RTB-native.html' + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', + 'ip': '95.233.216.174', + 'geo': { + 'country': 'ITA' + }, + 'language': 'en', + 'os': 'MacOS', + 'js': 0, + 'ext': { + 'remote_addr': '', + 'x_forwarded_for': '', + 'accept_language': 'en-GB' + } + }, + 'user': { + 'id': '' + }, + 'ext': { + 'sub': 0 + } + }) + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + + const bidResponse = bidResponses[0]; + + expect(bidResponse.mediaType).to.equal(NATIVE); + }); + + it('should test the InStream Video interpretResponse', function () { + const serverResponse = { + body: { + 'id': '2218abc7ebca97', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'd2d2063517b126252f56e22767c53f936ff40411', + 'impid': '270544423272657', + 'price': 0.12474000000000002, + 'adm': '\n\n \n \n your-ad-network.com\n \n \n \n \n \n \n 00:00:20.32\n \n \n \n \n \n \n \n \n \n \n \n \n test.com\n \n \n \n \n \n \n \n \n\n', + 'ext': { + 'btype': 1, + 'asset_mime_type': [ + 'video/mp4' + ] + }, + 'nurl': 'http://your-ad-network.com', + 'cid': '6260395', + 'crid': '89453191', + 'adomain': [ + 'test.com' + ], + 'w': 0, + 'h': 0, + 'attr': [] + } + ] + } + ], + 'cur': 'USD' + } + }; + + const bidResponses = spec.interpretResponse(serverResponse, { + data: JSON.stringify({ + 'id': '2218abc7ebca97', + 'at': 1, + 'imp': [ + { + 'id': '270544423272657', + 'video': { + 'mimes': [ + 'video/mp4' + ] + }, + 'protocols': [ + 3, + 6 + ], + 'ext': { + 'video_cta': 0 + } + } + ], + 'site': { + 'id': '12345', + 'domain': 'your-ad-network.com', + 'cat': [ + 'IAB25-3' + ], + 'page': 'https://your-ad-network.com/prebidJS-client-RTB-InStreamVideo.html', + 'keywords': 'lifestyle, humour' + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', + 'ip': '95.233.216.174', + 'geo': { + 'country': 'ITA' + }, + 'language': 'en', + 'os': 'MacOS', + 'js': 0, + 'ext': { + 'remote_addr': '', + 'x_forwarded_for': '', + 'accept_language': 'en-GB' + } + }, + 'user': { + 'id': '' + }, + 'ext': { + 'sub': 0 + } + }) + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + + const bidResponse = bidResponses[0]; + + expect(bidResponse.mediaType).to.equal(VIDEO); + }); + }); + + describe('checking dsa information', function() { + it('should add dsa information to the request via bidderRequest.params.dsa', function () { + const bidRequests = [imageBanner]; + + const requests = spec.buildRequests(bidRequests, {}); + + requests.forEach(function(requestItem) { + const payload = JSON.parse(requestItem.data); + + expect(payload.regs.ext.dsa).to.exist; + expect(payload.regs.ext.dsa.dsarequired).to.equal(3); + expect(payload.regs.ext.dsa.pubrender).to.equal(0); + expect(payload.regs.ext.dsa.datatopub).to.equal(2); + }); + }); + + it('should test the dsa interpretResponse', function () { + const dsaResponse = { + 'behalf': '...', + 'paid': '...', + 'transparency': [ + { + 'params': [ + 2 + ] + } + ], + 'adrender': 0 + }; + + const serverResponse = { + body: { + 'id': '2d2a496527398e', + 'seatbid': [ + { + 'bid': [ + { + 'id': '8f7fa506af97bc193e7bf099d8ed6930bd50aaf1', + 'impid': '270544423272657', + 'price': 0.0045000000000000005, + 'adm': '\n\n', + 'ext': { + 'btype': 1, + 'asset_mime_type': [ + 'image/jpeg', + 'image/jpg' + ], + 'dsa': dsaResponse + }, + 'nurl': 'http://your-ad-network.com/', + 'cid': '6260389', + 'crid': '89453173', + 'adomain': [ + 'test.com' + ], + 'w': 300, + 'h': 250, + 'attr': [ + 12 + ] + } + ] + } + ], + 'cur': 'USD' + } + }; + + const bidResponses = spec.interpretResponse(serverResponse, { + data: JSON.stringify({ + 'id': '2d2a496527398e', + 'at': 1, + 'imp': [ + { + 'id': '270544423272657', + 'bidfloor': 1.1e-7, + 'bidfloorcur': 'EUR', + 'banner': { + 'w': 300, + 'h': 250 + } + } + ], + 'site': { + 'id': '12345', + 'domain': 'your-ad-network.com', + 'cat': [ + 'IAB25-3' + ], + 'page': 'https://your-ad-network.com/prebidJS-client-RTB-banner.html', + 'keywords': 'lifestyle, humour' + }, + 'device': { + 'ua': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', + 'ip': '95.233.216.174', + 'geo': { + 'country': 'ITA' + }, + 'language': 'en', + 'os': 'MacOS', + 'js': 0, + 'ext': { + 'remote_addr': '', + 'x_forwarded_for': '', + 'accept_language': 'en-GB' + } + }, + 'user': { + 'id': '' + }, + 'ext': { + 'sub': 0 + }, + 'regs': { + 'ext': { + 'dsa': { + 'dsarequired': 3, + 'pubrender': 0, + 'datatopub': 2 + } + } + } + }) + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + const bidResponse = bidResponses[0]; + expect(bidResponse.meta).to.exist; + expect(bidResponse.meta.dsa).to.exist; + expect(bidResponse.meta.dsa).equal(dsaResponse); + }); + }); + + describe('on getting the win event', function() { + it('should not create nurl request if bid is undefined', function() { + const result = spec.onBidWon({}); + expect(result).to.be.undefined; + }); + }); + + describe('checking timeut', function () { + it('should exists and be a function', () => { + expect(spec.onTimeout).to.exist.and.to.be.a('function'); + }); + }); +}); From 5cfae1b34bd28d41e89c29f005b7abebe26a8c48 Mon Sep 17 00:00:00 2001 From: Hrechko Dmytro Date: Thu, 2 May 2024 17:38:22 +0300 Subject: [PATCH 086/147] Eight Pod Bid / Analytics Adapter : initial release (#11260) * eight pod init * fix mocks * specify eightPodAnalyticAdapter tests * update Event import --- modules/eightPodAnalyticsAdapter.js | 186 ++++++++++++++++ modules/eightPodAnalyticsAdapter.md | 19 ++ modules/eightPodBidAdapter.js | 193 +++++++++++++++++ modules/eightPodBidAdapter.md | 36 ++++ .../modules/eightPodAnalyticsAdapter_spec.js | 178 +++++++++++++++ test/spec/modules/eightPodBidAdapter_spec.js | 203 ++++++++++++++++++ 6 files changed, 815 insertions(+) create mode 100644 modules/eightPodAnalyticsAdapter.js create mode 100644 modules/eightPodAnalyticsAdapter.md create mode 100644 modules/eightPodBidAdapter.js create mode 100644 modules/eightPodBidAdapter.md create mode 100644 test/spec/modules/eightPodAnalyticsAdapter_spec.js create mode 100644 test/spec/modules/eightPodBidAdapter_spec.js diff --git a/modules/eightPodAnalyticsAdapter.js b/modules/eightPodAnalyticsAdapter.js new file mode 100644 index 00000000000..64ff845505d --- /dev/null +++ b/modules/eightPodAnalyticsAdapter.js @@ -0,0 +1,186 @@ +import {logError, logInfo} from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import { EVENTS } from '../src/constants.js'; +import adapterManager from '../src/adapterManager.js'; +import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js' +import {getStorageManager} from '../src/storageManager.js'; + +const analyticsType = 'endpoint'; +const MODULE_NAME = `eightPod`; +const MODULE = `${MODULE_NAME}AnalyticProvider`; + +/** + * Custom tracking server that gets internal events from EightPod's ad unit + */ +const trackerUrl = 'https://demo.8pod.com/tracker/track'; + +export const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_NAME}) + +const { + BID_WON +} = EVENTS; + +export let queue = []; +export let context; + +/** + * Create eightPod Analytic adapter + */ +let eightPodAnalytics = Object.assign(adapter({ analyticsType }), { + /** + * Execute on bid won - setup basic settings, save context about EightPod's bid. We will send it with our events later + */ + track({ eventType, args }) { + switch (eventType) { + case BID_WON: + if (args.bidder === 'eightPod') { + eightPodAnalytics.setupPage(args); + context = makeContext(args); + break; + } + } + }, + + /** + * Execute on bid won - subscribe on events from adUnit + */ + setupPage() { + eightPodAnalytics.eventSubscribe(); + queue = getEventFromLocalStorage(); + }, + /** + * Subscribe on internal ad unit tracking events + */ + eventSubscribe() { + window.addEventListener('message', async (event) => { + const data = event?.data; + + if (!data?.detail?.name) { + return; + } + + trackEvent(data); + }); + + // Send queue of event every 10 seconds + setInterval(sendEvents, 10_000); + }, + resetQueue() { + queue = []; + }, + getContext() { + return context; + } +}); + +/** + * Create context of event, who emits it + */ +function makeContext(args) { + const params = args?.params?.[0]; + return { + bidId: args.seatBidId, + variantId: args.creativeId || 'variantId', + campaignId: 'campaignId', + publisherId: params.publisherId, + placementId: params.placementId, + }; +} + +/** + * Create event, add context and push it to queue + */ +export function trackEvent(event) { + if (!event.detail) { + return; + } + const fullEvent = { + context: eightPodAnalytics.getContext(), + eventType: event.detail.type, + eventClass: 'adunit', + timestamp: new Date().getTime(), + eventName: event.detail.name, + payload: event.detail.payload + }; + + addEvent(fullEvent); +} + +/** + * Push event to queue, save event list in local storage + */ +function addEvent(eventPayload) { + queue.push(eventPayload); + storage.setDataInLocalStorage(`EIGHT_POD_EVENTS`, JSON.stringify(queue), null); +} + +/** + * Gets previously saved event that has not been sent + */ +function getEventFromLocalStorage() { + const storedEvents = storage.localStorageIsEnabled() ? storage.getDataFromLocalStorage('EIGHT_POD_EVENTS') : null; + + if (storedEvents) { + return JSON.parse(storedEvents); + } else { + return []; + } +} + +/** + * Send event to our custom tracking server and reset queue + */ +function sendEvents() { + eightPodAnalytics.eventsStorage = queue; + + if (queue.length) { + try { + sendEventsApi(queue, { + success: () => { + resetLocalStorage(); + eightPodAnalytics.resetQueue(); + }, + error: (e) => { + logError(MODULE, 'Cant send events', e); + } + }) + } catch (e) { + logError(MODULE, 'Cant send events', e); + } + } +} + +/** + * Send event to our custom tracking server + */ +function sendEventsApi(eventList, callbacks) { + ajax(trackerUrl, callbacks, JSON.stringify(eventList)); +} + +/** + * Remove saved events in success scenario + */ +const resetLocalStorage = () => { + storage.setDataInLocalStorage(`EIGHT_POD_EVENTS`, JSON.stringify([]), null); +} + +// save the base class function +eightPodAnalytics.originEnableAnalytics = eightPodAnalytics.enableAnalytics; +eightPodAnalytics.eventsStorage = []; + +// override enableAnalytics so we can get access to the config passed in from the page +eightPodAnalytics.enableAnalytics = function (config) { + eightPodAnalytics.originEnableAnalytics(config); + logInfo(MODULE, 'init', config); +}; + +/** + * Register Analytics Adapter + */ +adapterManager.registerAnalyticsAdapter({ + adapter: eightPodAnalytics, + code: MODULE_NAME +}); + +export default eightPodAnalytics; diff --git a/modules/eightPodAnalyticsAdapter.md b/modules/eightPodAnalyticsAdapter.md new file mode 100644 index 00000000000..fe37bf34459 --- /dev/null +++ b/modules/eightPodAnalyticsAdapter.md @@ -0,0 +1,19 @@ +# Overview +Module Name: 8pod Analytics by 8Pod + +Module Type: Analytics Adapter + +Maintainer: bianca@8pod.com + +# Description + +Analytics adapter for prebid provided by 8pod. It gets events from eightPod's ad unit and send it to our tracking server to improve user experience. +Please, use it ONLY with eightPodBidAdapter. + +# Analytics Adapter configuration example + +``` +{ + provider: 'eightPod' +} +``` diff --git a/modules/eightPodBidAdapter.js b/modules/eightPodBidAdapter.js new file mode 100644 index 00000000000..02f0954af07 --- /dev/null +++ b/modules/eightPodBidAdapter.js @@ -0,0 +1,193 @@ +import { ortbConverter } from '../libraries/ortbConverter/converter.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { BANNER } from '../src/mediaTypes.js' +import * as utils from '../src/utils.js' + +export const BIDDER_CODE = 'eightPod' +const url = 'https://demo.8pod.com/bidder/rtb/eightpod_exchange/bid?trace=true'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + isBannerBid, + isVideoBid, + onBidWon +} + +registerBidder(spec) + +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: 300, + }, + request(buildRequest, imps, bidderRequest, context) { + const req = buildRequest(imps, bidderRequest, context) + return req + }, + response(buildResponse, bidResponses, ortbResponse, context) { + const response = buildResponse(bidResponses, ortbResponse, context) + return response.bids + }, + imp(buildImp, bidRequest, context) { + return buildImp(bidRequest, context) + }, + bidResponse +}) + +function hasRequiredParams(bidRequest) { + return !!bidRequest?.params?.placementId +} + +function isBidRequestValid(bidRequest) { + return hasRequiredParams(bidRequest) +} + +function buildRequests(bids, bidderRequest) { + let bannerBids = bids.filter((bid) => isBannerBid(bid)) + let requests = bannerBids.length + ? [createRequest(bannerBids, bidderRequest, BANNER)] + : [] + return requests +} + +function bidResponse(buildBidResponse, bid, context) { + bid.nurl = replacePriceInUrl(bid.nurl, bid.price); + + const bidResponse = buildBidResponse(bid, context); + + bidResponse.height = context?.imp?.banner?.format?.[0].h; + bidResponse.width = context?.imp?.banner?.format?.[0].w; + + bidResponse.burl = replacePriceInUrl(bid.burl, bidResponse.originalCpm || bidResponse.cpm); + return bidResponse; +} + +function onBidWon(bid) { + if (bid.burl) { + utils.triggerPixel(bid.burl) + } +} +function replacePriceInUrl(url, price) { + return url.replace(/\${AUCTION_PRICE}/, price) +} + +export function parseUserAgent() { + const ua = navigator.userAgent.toLowerCase(); + + // Check if it's iOS + if (/iphone|ipad|ipod/.test(ua)) { + // Extract iOS version and device type + const iosInfo = /(iphone|ipad|ipod) os (\d+[._]\d+)|((iphone|ipad|ipod)(\D+cpu) os (\d+(?:[._\s]\d+)?))/.exec(ua); + return { + platform: 'ios', + version: iosInfo ? iosInfo[1] : '', + device: iosInfo ? iosInfo[2].replace('_', '.') : '' + }; + } else if (/android/.test(ua)) { + // Check if it's Android + // Extract Android version + const androidVersion = /android (\d+([._]\d+)?)/.exec(ua); + return { + platform: 'android', + version: androidVersion ? androidVersion[1].replace('_', '.') : '', + device: '' + }; + } else { + // If neither iOS nor Android, return unknown + return { + platform: 'Unknown', + version: '', + device: '' + }; + } +} + +export function getPageKeywords(win = window) { + let element; + + try { + element = win.top.document.querySelector('meta[name="keywords"]'); + } catch (e) { + element = document.querySelector('meta[name="keywords"]'); + } + + return ((element && element.content) || '').replaceAll(' ', ''); +} + +function createRequest(bidRequests, bidderRequest, mediaType) { + const data = converter.toORTB({ + bidRequests, + bidderRequest, + context: { mediaType }, + }); + + data.adSlotPositionOnScreen = 'ABOVE_THE_FOLD'; + data.at = 1; + + const params = getBidderParams(bidRequests); + + data.device = { + ...data.device, + model: parseUserAgent().device, + os: parseUserAgent().platform, + osv: parseUserAgent().version, + geo: { + country: params.country || 'GRB' + }, + language: params.language || data.device.language, + } + data.site = { + ...data.site, + keywords: getPageKeywords(window), + } + data.imp = [ + { + ...data.imp?.[0], + pmp: params.dealId + ? { + ...data.pmp, + deals: [ + { + bidfloor: 0.5, + at: 2, + id: params.dealId, + }, + ], + private_auction: 1, + } + : data.pmp, + } + ] + data.adSlotPlacementId = params.placementId; + + const req = { + method: 'POST', + url, + data + } + return req +} + +function getBidderParams(bidRequests) { + const bid = bidRequests.find(bid => { + return bid.bidder === BIDDER_CODE + }); + + return bid?.params ? bid.params : undefined; +} + +function isVideoBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.video') +} + +function isBannerBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.banner') +} + +function interpretResponse(resp, req) { + return converter.fromORTB({ request: req.data, response: resp.body }) +} diff --git a/modules/eightPodBidAdapter.md b/modules/eightPodBidAdapter.md new file mode 100644 index 00000000000..afefd5717de --- /dev/null +++ b/modules/eightPodBidAdapter.md @@ -0,0 +1,36 @@ +# Overview +Module Name: 8pod Bidder Adapter + +Module Type: Bidder Adapter + +Maintainer: bianca@8pod.com + +# Description + +Connect to 8pod for bids. + +This adapter requires setup and approval from the 8pod team. + +Please add eightPodAnalytics to collect user behavior and improve user experience as well. + +# Bidder Adapter configuration example + +``` +var adUnits = [{ + code: 'something', + mediaTypes: { + banner: { + sizes: [[350, 550]], + }, + }, + bids: [ + { + bidder: 'eightPod', + params: { + placementId: 13144370, + publisherId: 'publisherID-488864646', + }, + }, + ], + }]; +``` diff --git a/test/spec/modules/eightPodAnalyticsAdapter_spec.js b/test/spec/modules/eightPodAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..930b15bda31 --- /dev/null +++ b/test/spec/modules/eightPodAnalyticsAdapter_spec.js @@ -0,0 +1,178 @@ +import analyticsAdapter, { storage, queue, context, trackEvent } from 'modules/eightPodAnalyticsAdapter.js'; +import { expect } from 'chai'; +import adapterManager from 'src/adapterManager.js'; +import eightPodAnalytics from 'modules/eightPodAnalyticsAdapter.js'; +import { EVENTS } from '../../../src/constants.js'; + +const { + BID_WON +} = EVENTS; + +describe('eightPodAnalyticAdapter', function() { + let sandbox; + + beforeEach(function() { + sandbox = sinon.sandbox.create(); + adapterManager.enableAnalytics({ + provider: 'eightPod' + }); + }); + + afterEach(function() { + sandbox.restore(); + analyticsAdapter.disableAnalytics(); + }); + + describe('setup page', function() { + let getDataFromLocalStorageStub, localStorageIsEnabledStub; + let addEventListenerSpy; + + beforeEach(function() { + localStorageIsEnabledStub = sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + getDataFromLocalStorageStub = sandbox.stub( + storage, + 'getDataFromLocalStorage' + ); + addEventListenerSpy = sandbox.spy(window, 'addEventListener'); + }); + + afterEach(function() { + getDataFromLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); + addEventListenerSpy.restore(); + }); + + it('should subscribe on messageEvents', function() { + getDataFromLocalStorageStub.returns(JSON.stringify([])); + sandbox.spy(eightPodAnalytics, 'eventSubscribe'); + + analyticsAdapter.setupPage(); + + sandbox.assert.callCount(analyticsAdapter.eventSubscribe, 1); + sandbox.assert.callCount(addEventListenerSpy, 1); + }); + + it('should receive saved events list', function() { + const eventList = [1, 2, 3]; + getDataFromLocalStorageStub.returns(JSON.stringify(eventList)); + sandbox.spy(eightPodAnalytics, 'eventSubscribe'); + + analyticsAdapter.setupPage(); + expect(queue).to.deep.equal(eventList) + }); + }); + + describe('track event', function() { + let setupPageStub; + + beforeEach(function() { + setupPageStub = sandbox.stub(eightPodAnalytics, 'setupPage'); + }); + + afterEach(function() { + setupPageStub.restore(); + }); + + it('should NOT call setup page and get context', function() { + eightPodAnalytics.track({ + eventType: 'wrong_event_type', + }) + + sandbox.assert.callCount(setupPageStub, 0); + expect(context).to.deep.equal(undefined) + }); + + it('should call setup page and get context', function() { + eightPodAnalytics.track({ + eventType: BID_WON, + args: { + bidder: 'eightPod', + creativeId: 'creativeId', + seatBidId: 'seatBidId', + params: [ + { + publisherId: 'publisherId', + placementId: 'placementId', + } + ] + } + }) + + sandbox.assert.callCount(setupPageStub, 1); + expect(context).to.deep.equal({ + bidId: 'seatBidId', + campaignId: 'campaignId', + placementId: 'placementId', + publisherId: 'publisherId', + variantId: 'creativeId' + }) + }); + }); + + describe('trackEvent', function() { + let getContextStub, getTimeStub; + + beforeEach(function() { + getContextStub = sandbox.stub(eightPodAnalytics, 'getContext'); + getTimeStub = sandbox.stub(Date.prototype, 'getTime').returns(1234); + eightPodAnalytics.resetQueue(); + }); + + afterEach(function() { + getContextStub.restore(); + getTimeStub.restore(); + }); + + it('should add event to the queue', function() { + getContextStub.returns({}); + + const event1 = { + detail: { + type: 'Counter', + name: 'next_slide', + payload: { + from: '1.1', + to: '2.2', + value: 3 + } + } + } + const result1 = { + context: {}, + eventType: 'Counter', + eventClass: 'adunit', + timestamp: 1234, + eventName: 'next_slide', + payload: { + from: '1.1', + to: '2.2', + value: 3 + } + } + + const event2 = { + detail: { + type: 'Counter', + name: 'pod_impression', + payload: { + value: 2 + } + } + } + const result2 = { + context: {}, + eventType: 'Counter', + eventClass: 'adunit', + timestamp: 1234, + eventName: 'pod_impression', + payload: { + value: 2 + } + } + trackEvent(event1) + expect(queue).to.deep.equal([result1]); + trackEvent(event2); + expect(queue).to.deep.equal([result1, result2]); + }); + }); +}); diff --git a/test/spec/modules/eightPodBidAdapter_spec.js b/test/spec/modules/eightPodBidAdapter_spec.js new file mode 100644 index 00000000000..7d55997d8cd --- /dev/null +++ b/test/spec/modules/eightPodBidAdapter_spec.js @@ -0,0 +1,203 @@ +import { expect } from 'chai' +import { spec, getPageKeywords, parseUserAgent } from 'modules/eightPodBidAdapter' +import 'modules/priceFloors.js' +import { config } from 'src/config.js' +import { newBidder } from 'src/adapters/bidderFactory' +import * as utils from '../../../src/utils'; +import sinon from 'sinon'; + +describe('eightPodBidAdapter', function () { + const adapter = newBidder(spec) + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + }) + + describe('isBidRequestValid', function () { + const validBid = { + bidder: 'eightPod', + adUnitCode: '/adunit-code/test-path', + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1', + transactionId: 'test-transactionId-1', + params: { + placementId: 'placementId1', + }, + } + const invalidBid = { + bidder: 'eightPod', + adUnitCode: '/adunit-code/test-path', + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1', + transactionId: 'test-transactionId-1', + } + + beforeEach(() => { + config.resetConfig() + }) + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(validBid)).to.equal(true) + }) + + it('should return false when required params found and invalid bid', function () { + expect(spec.isBidRequestValid(invalidBid)).to.equal(false) + }) + }) + + describe('buildRequests', function () { + let bidRequests, bidderRequest + beforeEach(function () { + bidRequests = [ + { + bidder: 'eightPod', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600], + ], + }, + }, + adUnitCode: '/adunit-code/test-path', + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1', + transactionId: 'test-transactionId-1', + params: { + placementId: 'placementId1', + } + } + ] + bidderRequest = { + refererInfo: {}, + ortb2: { + device: { + ua: 'ua', + language: 'en', + dnt: 1, + js: 1, + } + } } + }) + + it('should return an empty array when no bid requests', function () { + const bidRequest = spec.buildRequests([], bidderRequest) + expect(bidRequest).to.be.an('array') + expect(bidRequest.length).to.equal(0) + }) + + it('should return a valid bid request object', function () { + const request = spec.buildRequests(bidRequests, bidderRequest) + + expect(request).to.be.an('array') + expect(request[0].data).to.be.an('object') + expect(request[0].method).to.equal('POST') + expect(request[0].url).to.not.equal('') + expect(request[0].url).to.not.equal(undefined) + expect(request[0].url).to.not.equal(null) + }) + }) + + describe('onBidWon', function() { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + + it('Should not trigger pixel if bid does not contain nurl', function() { + spec.onBidWon({}); + expect(utils.triggerPixel.callCount).to.equal(0) + }) + + it('Should trigger pixel if bid nurl', function() { + spec.onBidWon({ + burl: 'https://example.com/some-tracker' + }); + expect(utils.triggerPixel.callCount).to.equal(1) + }) + }) + + describe('getPageKeywords function', function() { + let sandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should return the top document keywords if available', function() { + const keywordsContent = 'keyword1,keyword2,keyword3'; + const fakeTopDocument = { + querySelector: sandbox.stub() + .withArgs('meta[name="keywords"]').returns({ content: keywordsContent }) + }; + const fakeTopWindow = { document: fakeTopDocument }; + + const result = getPageKeywords({ top: fakeTopWindow }); + expect(result).to.equal(keywordsContent); + }); + + it('should return the current document keywords if top document is not accessible', function() { + const keywordsContent = 'keyword1,keyword2,keyword3'; + sandbox.stub(document, 'querySelector') + .withArgs('meta[name="keywords"]').returns({ content: keywordsContent }); + + const fakeWindow = { + get top() { + throw new Error('Access denied'); + } + }; + + const result = getPageKeywords(fakeWindow); + expect(result).to.equal(keywordsContent); + }); + + it('should return an empty string if no keywords meta tag is found', function() { + sandbox.stub(document, 'querySelector').withArgs('meta[name="keywords"]').returns(null); + + const result = getPageKeywords(); + expect(result).to.equal(''); + }); + }); + + describe('parseUserAgent function', function() { + let sandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should return the platform and version IOS', function() { + const uaStub = sandbox.stub(window.navigator, 'userAgent'); + uaStub.value('Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'); + + const result = parseUserAgent(); + expect(result.platform).to.equal('ios'); + expect(result.version).to.equal('iphone'); + expect(result.device).to.equal('16.6'); + }); + + it('should return the platform and version android', function() { + const uaStub = sandbox.stub(window.navigator, 'userAgent'); + uaStub.value('Mozilla/5.0 (Linux; Android 5.0.1; SM-G920V Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36'); + + const result = parseUserAgent(); + expect(result.platform).to.equal('android'); + expect(result.version).to.equal('5.0'); + expect(result.device).to.equal(''); + }) + }) +}) From 7ab6165e342294fafa087135af219f3f88f0e220 Mon Sep 17 00:00:00 2001 From: Ilia Medvedev Date: Thu, 2 May 2024 21:59:31 +0400 Subject: [PATCH 087/147] Limelight Digital Bid Adapter: fix page field filling (#11436) --- modules/limelightDigitalBidAdapter.js | 6 ++-- .../limelightDigitalBidAdapter_spec.js | 36 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index acc6876b822..c816f800fda 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -128,7 +128,8 @@ function buildRequest(winTop, host, adUnits, bidderRequest) { deviceWidth: winTop.screen.width, deviceHeight: winTop.screen.height, adUnits: adUnits, - sua: bidderRequest?.ortb2?.device?.sua + sua: bidderRequest?.ortb2?.device?.sua, + page: bidderRequest?.ortb2?.site?.page || bidderRequest?.refererInfo?.page } } } @@ -170,8 +171,7 @@ function buildPlacement(bidRequest) { custom2: bidRequest.params.custom2, custom3: bidRequest.params.custom3, custom4: bidRequest.params.custom4, - custom5: bidRequest.params.custom5, - page: bidRequest.refererInfo.page + custom5: bidRequest.params.custom5 } } } diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index 9e8a00959d4..51cf8cd14ee 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -17,9 +17,6 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, - refererInfo: { - page: 'https://publisher.com/page1' - }, placementCode: 'placement_0', auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', mediaTypes: { @@ -68,9 +65,6 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, - refererInfo: { - page: 'https://publisher.com/page2' - }, placementCode: 'placement_1', auctionId: '482f88de-29ab-45c8-981a-d25e39454a34', sizes: [[350, 200]], @@ -121,9 +115,6 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, - refererInfo: { - page: 'https://publisher.com/page3' - }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', sizes: [[800, 600]], @@ -171,9 +162,6 @@ describe('limelightDigitalAdapter', function () { custom4: 'custom4', custom5: 'custom5' }, - refererInfo: { - page: 'https://publisher.com/page4' - }, placementCode: 'placement_2', auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', video: { @@ -218,6 +206,9 @@ describe('limelightDigitalAdapter', function () { architecture: 'arm' } } + }, + refererInfo: { + page: 'testPage' } } const serverRequests = spec.buildRequests([bid1, bid2, bid3, bid4], bidderRequest) @@ -243,7 +234,8 @@ describe('limelightDigitalAdapter', function () { 'deviceHeight', 'secure', 'adUnits', - 'sua' + 'sua', + 'page' ); expect(data.deviceWidth).to.be.a('number'); expect(data.deviceHeight).to.be.a('number'); @@ -262,8 +254,7 @@ describe('limelightDigitalAdapter', function () { 'custom2', 'custom3', 'custom4', - 'custom5', - 'page' + 'custom5' ); expect(adUnit.id).to.be.a('number'); expect(adUnit.bidId).to.be.a('string'); @@ -277,12 +268,13 @@ describe('limelightDigitalAdapter', function () { expect(adUnit.custom3).to.be.a('string'); expect(adUnit.custom4).to.be.a('string'); expect(adUnit.custom5).to.be.a('string'); - expect(adUnit.page).to.be.a('string'); }) expect(data.sua.browsers).to.be.a('array'); expect(data.sua.platform).to.be.a('array'); expect(data.sua.mobile).to.be.a('number'); expect(data.sua.architecture).to.be.a('string'); + expect(data.page).to.be.a('string'); + expect(data.page).to.be.equal('testPage'); }) }) it('Returns valid URL', function () { @@ -298,6 +290,17 @@ describe('limelightDigitalAdapter', function () { const serverRequests = spec.buildRequests([]) expect(serverRequests).to.be.an('array').that.is.empty }) + it('Returns request with page field value from ortb2 object if ortb2 has page field', function () { + bidderRequest.ortb2.site = { + page: 'testSitePage' + } + const serverRequests = spec.buildRequests([bid1], bidderRequest) + expect(serverRequests).to.have.lengthOf(1) + serverRequests.forEach(serverRequest => { + expect(serverRequest.data.page).to.be.a('string'); + expect(serverRequest.data.page).to.be.equal('testSitePage'); + }) + }) }) describe('interpretBannerResponse', function () { let resObject = { @@ -716,5 +719,4 @@ function validateAdUnit(adUnit, bid) { expect(adUnit.publisherId).to.equal(bid.params.publisherId); expect(adUnit.userIdAsEids).to.deep.equal(bid.userIdAsEids); expect(adUnit.supplyChain).to.deep.equal(bid.schain); - expect(adUnit.page).to.equal(bid.refererInfo.page); } From 7d52b11169ab715284fa72162ec6425c61726d9c Mon Sep 17 00:00:00 2001 From: johnwier <49074029+johnwier@users.noreply.github.com> Date: Mon, 6 May 2024 10:32:16 -0700 Subject: [PATCH 088/147] Conversant Adapter - remove transformBidParams (#11441) Co-authored-by: johwier --- modules/conversantBidAdapter.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index ebcad38d866..76ff2a9e2ad 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -15,7 +15,6 @@ import { import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {getStorageManager} from '../src/storageManager.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; import {ortbConverter} from '../libraries/ortbConverter/converter.js'; import {ORTB_MTYPES} from '../libraries/ortbConverter/processors/mediaType.js'; @@ -180,20 +179,6 @@ export const spec = { return converter.fromORTB({request: bidRequest.data, response: serverResponse.body}); }, - /** - * Covert bid param types for S2S - * @param {Object} params bid params - * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol - * @return {Object} params bid params - */ - transformBidParams: function(params, isOpenRtb) { - return convertTypes({ - 'site_id': 'string', - 'secure': 'number', - 'mobile': 'number' - }, params); - }, - /** * Register User Sync. */ From 8a57af7acfd32e60c0cfa5d18117de3bde6a8746 Mon Sep 17 00:00:00 2001 From: Ruslan S Date: Tue, 7 May 2024 01:53:05 +0800 Subject: [PATCH 089/147] [Smaato] Migrating to ortbConverter requests build process (#11433) - Response handling will be done separately --- modules/smaatoBidAdapter.js | 421 ++++---- test/spec/modules/smaatoBidAdapter_spec.js | 1025 +++++++++++--------- 2 files changed, 755 insertions(+), 691 deletions(-) diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index 64d8765dc04..9a0a0f75623 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -3,10 +3,11 @@ import {find} from '../src/polyfill.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {ADPOD, BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import { NATIVE_IMAGE_TYPES } from '../src/constants.js'; +import {NATIVE_IMAGE_TYPES} from '../src/constants.js'; import {getAdUnitSizes} from '../libraries/sizeUtils/sizeUtils.js'; import {fill} from '../libraries/appnexusUtils/anUtils.js'; import {chunk} from '../libraries/chunk/chunk.js'; +import {ortbConverter} from '../libraries/ortbConverter/converter.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -18,134 +19,14 @@ import {chunk} from '../libraries/chunk/chunk.js'; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_1.8' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_2.0' +const TTL = 300; const CURRENCY = 'USD'; - -const buildOpenRtbBidRequest = (bidRequest, bidderRequest) => { - const requestTemplate = { - id: bidderRequest.bidderRequestId, - at: 1, - cur: [CURRENCY], - tmax: bidderRequest.timeout, - site: { - id: window.location.hostname, - // TODO: do the fallbacks make sense here? - domain: bidderRequest.refererInfo.domain || window.location.hostname, - page: bidderRequest.refererInfo.page || window.location.href, - ref: bidderRequest.refererInfo.ref - }, - device: { - language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', - ua: navigator.userAgent, - dnt: getDNT() ? 1 : 0, - h: screen.height, - w: screen.width - }, - regs: { - coppa: config.getConfig('coppa') === true ? 1 : 0, - ext: {} - }, - user: { - ext: {} - }, - source: { - ext: { - schain: bidRequest.schain - } - }, - ext: { - client: SMAATO_CLIENT - } - }; - - let ortb2 = bidderRequest.ortb2 || {}; - Object.assign(requestTemplate.user, ortb2.user); - Object.assign(requestTemplate.site, ortb2.site); - - deepSetValue(requestTemplate, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); - - if (bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies === true) { - deepSetValue(requestTemplate, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); - deepSetValue(requestTemplate, 'user.ext.consent', bidderRequest.gdprConsent.consentString); - } - - if (bidderRequest.uspConsent !== undefined) { - deepSetValue(requestTemplate, 'regs.ext.us_privacy', bidderRequest.uspConsent); - } - - if (ortb2.regs?.gpp !== undefined) { - deepSetValue(requestTemplate, 'regs.ext.gpp', ortb2.regs.gpp); - deepSetValue(requestTemplate, 'regs.ext.gpp_sid', ortb2.regs.gpp_sid); - } - - if (ortb2.device?.ifa !== undefined) { - deepSetValue(requestTemplate, 'device.ifa', ortb2.device.ifa); - } - - if (ortb2.device?.geo !== undefined) { - deepSetValue(requestTemplate, 'device.geo', ortb2.device.geo); - } - - if (deepAccess(bidRequest, 'params.app')) { - if (!deepAccess(requestTemplate, 'device.geo')) { - const geo = deepAccess(bidRequest, 'params.app.geo'); - deepSetValue(requestTemplate, 'device.geo', geo); - } - if (!deepAccess(requestTemplate, 'device.ifa')) { - const ifa = deepAccess(bidRequest, 'params.app.ifa'); - deepSetValue(requestTemplate, 'device.ifa', ifa); - } - } - - const eids = deepAccess(bidRequest, 'userIdAsEids'); - if (eids && eids.length) { - deepSetValue(requestTemplate, 'user.ext.eids', eids); - } - - let requests = []; - - if (deepAccess(bidRequest, 'mediaTypes.banner')) { - const bannerRequest = Object.assign({}, requestTemplate, createBannerImp(bidRequest)); - requests.push(bannerRequest); - } - - const videoMediaType = deepAccess(bidRequest, 'mediaTypes.video'); - if (videoMediaType) { - if (videoMediaType.context === ADPOD) { - const adPodRequest = Object.assign({}, requestTemplate, createAdPodImp(bidRequest, videoMediaType)); - addOptionalAdpodParameters(adPodRequest, videoMediaType); - requests.push(adPodRequest); - } else { - const videoRequest = Object.assign({}, requestTemplate, createVideoImp(bidRequest, videoMediaType)); - requests.push(videoRequest); - } - } - - const nativeOrtbRequest = bidRequest.nativeOrtbRequest; - if (nativeOrtbRequest) { - const nativeRequest = Object.assign({}, requestTemplate, createNativeImp(bidRequest, nativeOrtbRequest)); - requests.push(nativeRequest); - } - - return requests; -} - -const buildServerRequest = (validBidRequest, data) => { - logInfo('[SMAATO] OpenRTB Request:', data); - return { - method: 'POST', - url: validBidRequest.params.endpoint || SMAATO_ENDPOINT, - data: JSON.stringify(data), - options: { - withCredentials: true, - crossOrigin: true, - } - }; -} +const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO, NATIVE]; export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO, NATIVE], + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, gvlid: 82, /** @@ -195,13 +76,30 @@ export const spec = { return true; }, - buildRequests: (validBidRequests, bidderRequest) => { + buildRequests: (bidRequests, bidderRequest) => { logInfo('[SMAATO] Client version:', SMAATO_CLIENT); - return validBidRequests.map((validBidRequest) => { - const openRtbBidRequests = buildOpenRtbBidRequest(validBidRequest, bidderRequest); - return openRtbBidRequests.map((openRtbBidRequest) => buildServerRequest(validBidRequest, openRtbBidRequest)); - }).reduce((acc, item) => item != null && acc.concat(item), []); + let requests = []; + bidRequests.forEach(bid => { + // separate requests per mediaType + SUPPORTED_MEDIA_TYPES.forEach(mediaType => { + if ((bid.mediaTypes && bid.mediaTypes[mediaType]) || (mediaType === NATIVE && bid.nativeOrtbRequest)) { + const data = converter.toORTB({bidderRequest, bidRequests: [bid], context: {mediaType}}); + requests.push({ + method: 'POST', + url: bid.params.endpoint || SMAATO_ENDPOINT, + data: JSON.stringify(data), + options: { + withCredentials: true, + crossOrigin: true, + }, + bidderRequest + }) + } + }); + }); + + return requests; }, /** * Unpack the response from the server into a list of bids. @@ -239,7 +137,7 @@ export const spec = { creativeId: bid.crid, dealId: bid.dealid || null, netRevenue: deepAccess(bid, 'ext.net', true), - currency: response.cur, + currency: CURRENCY, meta: { advertiserDomains: bid.adomain, networkName: bid.bidderName, @@ -306,6 +204,172 @@ export const spec = { } registerBidder(spec); +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: TTL, + currency: CURRENCY + }, + request(buildRequest, imps, bidderRequest, context) { + function isGdprApplicable() { + return bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies; + } + + const request = buildRequest(imps, bidderRequest, context); + const bidRequest = context.bidRequests[0]; + let siteContent; + const mediaType = context.mediaType; + if (mediaType === VIDEO) { + const videoParams = bidRequest.mediaTypes[VIDEO]; + if (videoParams.context === ADPOD) { + request.imp = createAdPodImp(request.imp[0], videoParams); + siteContent = addOptionalAdpodParameters(videoParams); + } + } + + request.at = 1; + + if (request.user) { + if (isGdprApplicable()) { + deepSetValue(request.user, 'ext.consent', bidderRequest.gdprConsent.consentString); + } + } else { + const eids = deepAccess(bidRequest, 'userIdAsEids'); + request.user = { + ext: { + consent: isGdprApplicable() ? bidderRequest.gdprConsent.consentString : null, + eids: (eids && eids.length) ? eids : null + } + } + } + + if (request.site) { + request.site.id = window.location.hostname + if (siteContent) { + request.site.content = siteContent; + } + } else { + request.site = { + id: window.location.hostname, + domain: bidderRequest.refererInfo.domain || window.location.hostname, + page: bidderRequest.refererInfo.page || window.location.href, + ref: bidderRequest.refererInfo.ref, + content: siteContent || null + } + } + deepSetValue(request.site, 'publisher.id', bidRequest.params.publisherId); + + if (request.regs) { + if (isGdprApplicable()) { + deepSetValue(request.regs, 'ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + } + if (bidderRequest.uspConsent !== undefined) { + deepSetValue(request.regs, 'ext.us_privacy', bidderRequest.uspConsent); + } + if (request.regs?.gpp) { + deepSetValue(request.regs, 'ext.gpp', request.regs.gpp); + deepSetValue(request.regs, 'ext.gpp_sid', request.regs.gpp_sid); + } + } else { + request.regs = { + coppa: config.getConfig('coppa') === true ? 1 : 0, + ext: { + gdpr: isGdprApplicable() ? bidderRequest.gdprConsent.gdprApplies ? 1 : 0 : null, + us_privacy: bidderRequest.uspConsent + } + } + } + + if (request.device) { + if (bidRequest.params.app) { + if (!deepAccess(request.device, 'geo')) { + const geo = deepAccess(bidRequest, 'params.app.geo'); + deepSetValue(request.device, 'geo', geo); + } + if (!deepAccess(request.device, 'ifa')) { + const ifa = deepAccess(bidRequest, 'params.app.ifa'); + deepSetValue(request.device, 'ifa', ifa); + } + } + } else { + request.device = { + language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + ua: navigator.userAgent, + dnt: getDNT() ? 1 : 0, + h: screen.height, + w: screen.width + } + if (!deepAccess(request.device, 'geo')) { + const geo = deepAccess(bidRequest, 'params.app.geo'); + deepSetValue(request.device, 'geo', geo); + } + if (!deepAccess(request.device, 'ifa')) { + const ifa = deepAccess(bidRequest, 'params.app.ifa'); + deepSetValue(request.device, 'ifa', ifa); + } + } + + request.source = { + ext: { + schain: bidRequest.schain + } + }; + request.ext = { + client: SMAATO_CLIENT + } + return request; + }, + + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + deepSetValue(imp, 'tagid', bidRequest.params.adbreakId || bidRequest.params.adspaceId); + if (imp.bidfloorcur && imp.bidfloorcur !== CURRENCY) { + delete imp.bidfloor; + delete imp.bidfloorcur; + } + return imp; + }, + + overrides: { + imp: { + banner(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + + if (mediaType === BANNER) { + imp.bidfloor = getBidFloor(bidRequest, BANNER, getAdUnitSizes(bidRequest)); + } + + orig(imp, bidRequest, context); + }, + + video(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + if (mediaType === VIDEO) { + const videoParams = bidRequest.mediaTypes[VIDEO]; + imp.bidfloor = getBidFloor(bidRequest, VIDEO, videoParams.playerSize); + if (videoParams.context !== ADPOD) { + deepSetValue(imp, 'video.ext', { + rewarded: videoParams.ext && videoParams.ext.rewarded ? videoParams.ext.rewarded : 0 + }) + } + } + + orig(imp, bidRequest, context); + }, + + native(orig, imp, bidRequest, context) { + const mediaType = context.mediaType; + + if (mediaType === NATIVE) { + imp.bidfloor = getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(bidRequest.nativeOrtbRequest)); + } + + orig(imp, bidRequest, context); + } + }, + } +}); + const createImgAd = (adm) => { const image = JSON.parse(adm).image; @@ -346,65 +410,6 @@ const createNativeAd = (adm) => { } }; -function createBannerImp(bidRequest) { - const adUnitSizes = getAdUnitSizes(bidRequest); - const sizes = adUnitSizes.map((size) => ({w: size[0], h: size[1]})); - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, BANNER, adUnitSizes), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - banner: { - w: sizes[0].w, - h: sizes[0].h, - format: sizes - } - }] - }; -} - -function createVideoImp(bidRequest, videoMediaType) { - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, VIDEO, videoMediaType.playerSize), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - video: { - mimes: videoMediaType.mimes, - minduration: videoMediaType.minduration, - startdelay: videoMediaType.startdelay, - linearity: videoMediaType.linearity, - w: videoMediaType.playerSize[0][0], - h: videoMediaType.playerSize[0][1], - maxduration: videoMediaType.maxduration, - skip: videoMediaType.skip, - protocols: videoMediaType.protocols, - ext: { - rewarded: videoMediaType.ext && videoMediaType.ext.rewarded ? videoMediaType.ext.rewarded : 0 - }, - skipmin: videoMediaType.skipmin, - api: videoMediaType.api - } - }] - }; -} - -function createNativeImp(bidRequest, nativeRequest) { - return { - imp: [{ - id: bidRequest.bidId, - tagid: deepAccess(bidRequest, 'params.adspaceId'), - bidfloor: getBidFloor(bidRequest, NATIVE, getNativeMainImageSize(nativeRequest)), - native: { - request: JSON.stringify(nativeRequest), - ver: '1.2' - } - }] - }; -} - function getNativeMainImageSize(nativeRequest) { const mainImage = find(nativeRequest.assets, asset => asset.hasOwnProperty('img') && asset.img.type === NATIVE_IMAGE_TYPES.MAIN) if (mainImage) { @@ -418,30 +423,12 @@ function getNativeMainImageSize(nativeRequest) { return [] } -function createAdPodImp(bidRequest, videoMediaType) { - const tagid = deepAccess(bidRequest, 'params.adbreakId') +function createAdPodImp(imp, videoMediaType) { const bce = config.getConfig('adpod.brandCategoryExclusion') - let imp = { - id: bidRequest.bidId, - tagid: tagid, - bidfloor: getBidFloor(bidRequest, VIDEO, videoMediaType.playerSize), - instl: deepAccess(bidRequest.ortb2Imp, 'instl'), - video: { - w: videoMediaType.playerSize[0][0], - h: videoMediaType.playerSize[0][1], - mimes: videoMediaType.mimes, - startdelay: videoMediaType.startdelay, - linearity: videoMediaType.linearity, - skip: videoMediaType.skip, - protocols: videoMediaType.protocols, - skipmin: videoMediaType.skipmin, - api: videoMediaType.api, - ext: { - context: ADPOD, - brandcategoryexclusion: bce !== undefined && bce - } - } - } + imp.video.ext = { + context: ADPOD, + brandcategoryexclusion: bce !== undefined && bce + }; const numberOfPlacements = getAdPodNumberOfPlacements(videoMediaType) let imps = fill(imp, numberOfPlacements) @@ -471,9 +458,7 @@ function createAdPodImp(bidRequest, videoMediaType) { }); } - return { - imp: imps - } + return imps } function getAdPodNumberOfPlacements(videoMediaType) { @@ -486,7 +471,7 @@ function getAdPodNumberOfPlacements(videoMediaType) { : numberOfPlacements } -const addOptionalAdpodParameters = (request, videoMediaType) => { +const addOptionalAdpodParameters = (videoMediaType) => { const content = {} if (videoMediaType.tvSeriesName) { @@ -509,7 +494,7 @@ const addOptionalAdpodParameters = (request, videoMediaType) => { } if (!isEmpty(content)) { - request.site.content = content + return content } } diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index 185dee2430f..28fd06c4b8d 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -1,7 +1,16 @@ import {spec} from 'modules/smaatoBidAdapter.js'; import * as utils from 'src/utils.js'; import {config} from 'src/config.js'; -import {createEidsArray} from 'modules/userId/eids.js'; + +// load modules that register ORTB processors +import 'src/prebid.js' +import 'modules/currency.js'; +import 'modules/userId/index.js'; +import 'modules/multibid/index.js'; +import 'modules/priceFloors.js'; +import 'modules/consentManagement.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/schain.js'; const ADTYPE_IMG = 'Img'; const ADTYPE_RICHMEDIA = 'Richmedia'; @@ -112,14 +121,13 @@ describe('smaatoBidAdapterTest', () => { describe('buildRequests', () => { const BANNER_OPENRTB_IMP = { - w: 300, - h: 50, format: [ { h: 50, w: 300 } - ] + ], + topframe: 0, } describe('common', () => { @@ -145,13 +153,6 @@ describe('smaatoBidAdapterTest', () => { expect(req.at).to.be.equal(1); }) - it('currency is US dollar', () => { - const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.cur).to.be.deep.equal(['USD']); - }) - it('can override endpoint', () => { const overridenEndpoint = 'https://prebid/bidder'; const updatedBidRequest = utils.deepClone(singleBannerBidRequest); @@ -178,7 +179,7 @@ describe('smaatoBidAdapterTest', () => { it('sends bidfloor when configured', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function(arg) { + singleBannerBidRequestWithFloor.getFloor = function (arg) { if (arg.currency === 'USD' && arg.mediaType === 'banner' && JSON.stringify(arg.size) === JSON.stringify([300, 50])) { @@ -202,7 +203,7 @@ describe('smaatoBidAdapterTest', () => { } } }); - singleBannerMultipleSizesBidRequestWithFloor.getFloor = function(arg) { + singleBannerMultipleSizesBidRequestWithFloor.getFloor = function (arg) { if (arg.size === '*') { return { currency: 'USD', @@ -228,7 +229,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when invalid', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return undefined; } const reqs = spec.buildRequests([singleBannerBidRequestWithFloor], defaultBidderRequest); @@ -239,7 +240,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when not a number', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return { currency: 'USD', } @@ -252,7 +253,7 @@ describe('smaatoBidAdapterTest', () => { it('sends undefined bidfloor when wrong currency', () => { const singleBannerBidRequestWithFloor = Object.assign({}, singleBannerBidRequest); - singleBannerBidRequestWithFloor.getFloor = function() { + singleBannerBidRequestWithFloor.getFloor = function () { return { currency: 'EUR', floor: 0.123 @@ -275,6 +276,58 @@ describe('smaatoBidAdapterTest', () => { expect(req.site.publisher.id).to.equal('publisherId'); }) + it('sends correct site from ortb2', () => { + const domain = 'domain'; + const page = 'page'; + const ref = 'ref'; + const ortb2 = { + site: { + name: 'example', + domain: domain, + page: page, + ref: ref + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.id).to.exist.and.to.be.a('string'); + expect(req.site.domain).to.equal(domain); + expect(req.site.page).to.equal(page); + expect(req.site.ref).to.equal(ref); + expect(req.site.publisher.id).to.equal('publisherId'); + }) + + it('sends correct device from ortb2', () => { + const language = 'language' + const ua = 'ua' + const sua = 'sua' + const dnt = 1 + const w = 2 + const h = 3 + const ortb2 = { + device: { + language: language, + ua: ua, + sua: sua, + dnt: dnt, + w: w, + h: h + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.device.language).to.equal(language); + expect(req.device.ua).to.equal(ua); + expect(req.device.sua).to.equal(sua); + expect(req.device.dnt).to.equal(dnt); + expect(req.device.w).to.equal(w); + expect(req.device.h).to.equal(h); + }) + it('sends gdpr applies if exists', () => { const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); @@ -283,6 +336,19 @@ describe('smaatoBidAdapterTest', () => { expect(req.user.ext.consent).to.equal(CONSENT_STRING); }); + it('sends correct coppa from ortb2', () => { + const ortb2 = { + regs: { + coppa: 1 + }, + }; + + const reqs = spec.buildRequests([singleBannerBidRequest], {...defaultBidderRequest, ortb2}); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.regs.coppa).to.equal(1); + }) + it('sends no gdpr applies if no gdpr exists', () => { const reqs = spec.buildRequests([singleBannerBidRequest], MINIMAL_BIDDER_REQUEST); @@ -321,7 +387,7 @@ describe('smaatoBidAdapterTest', () => { }); it('sends instl if instl exists', () => { - const instl = { instl: 1 }; + const instl = {instl: 1}; const bidRequestWithInstl = Object.assign({}, singleBannerBidRequest, {ortb2Imp: instl}); const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); @@ -381,6 +447,16 @@ describe('smaatoBidAdapterTest', () => { expect(req.device.geo.lon).to.equal(9.9872); }); + it('sends user first party data when user is not defined', () => { + const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.user.gender).be.undefined; + expect(req.user.yob).to.be.undefined; + expect(req.user.keywords).to.be.undefined; + expect(req.user.ext.consent).to.equal(CONSENT_STRING); + }); + it('has no user ids', () => { const reqs = spec.buildRequests([singleBannerBidRequest], defaultBidderRequest); @@ -456,531 +532,534 @@ describe('smaatoBidAdapterTest', () => { bidderWinsCount: 0 }; - it('sends correct video imps', () => { - const reqs = spec.buildRequests([singleVideoBidRequest], defaultBidderRequest); + if (FEATURES.VIDEO) { + it('sends correct video imps', () => { + const reqs = spec.buildRequests([singleVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].id).to.be.equal('bidId'); - expect(req.imp[0].tagid).to.be.equal('adspaceId'); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].id).to.be.equal('bidId'); + expect(req.imp[0].tagid).to.be.equal('adspaceId'); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); + }); - it('sends bidfloor when configured', () => { - const singleVideoBidRequestWithFloor = Object.assign({}, singleVideoBidRequest); - singleVideoBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'video' && - JSON.stringify(arg.size) === JSON.stringify([768, 1024])) { - return { - currency: 'USD', - floor: 0.456 + it('sends bidfloor when configured', () => { + const singleVideoBidRequestWithFloor = Object.assign({}, singleVideoBidRequest); + singleVideoBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'video' && + JSON.stringify(arg.size) === JSON.stringify([768, 1024])) { + return { + currency: 'USD', + floor: 0.456 + } } } - } - const reqs = spec.buildRequests([singleVideoBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([singleVideoBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.456); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.456); + }); - it('sends instl if instl exists', () => { - const instl = { instl: 1 }; - const bidRequestWithInstl = Object.assign({}, singleVideoBidRequest, {ortb2Imp: instl}); + it('sends instl if instl exists', () => { + const instl = {instl: 1}; + const bidRequestWithInstl = Object.assign({}, singleVideoBidRequest, {ortb2Imp: instl}); - const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].instl).to.equal(1); - }); - - it('splits multi format bid requests', () => { - const combinedBannerAndVideoBidRequest = { - bidder: 'smaato', - params: { - publisherId: 'publisherId', - adspaceId: 'adspaceId' - }, - mediaTypes: { - banner: BANNER_PREBID_MEDIATYPE, - video: VIDEO_OUTSTREAM_PREBID_MEDIATYPE - }, - adUnitCode: '/19968336/header-bid-tag-0', - transactionId: 'transactionId', - sizes: [[300, 50]], - bidId: 'bidId', - bidderRequestId: 'bidderRequestId', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - }; - - const reqs = spec.buildRequests([combinedBannerAndVideoBidRequest], defaultBidderRequest); - - expect(reqs).to.have.length(2); - expect(JSON.parse(reqs[0].data).imp[0].banner).to.deep.equal(BANNER_OPENRTB_IMP); - expect(JSON.parse(reqs[0].data).imp[0].video).to.not.exist; - expect(JSON.parse(reqs[1].data).imp[0].banner).to.not.exist; - expect(JSON.parse(reqs[1].data).imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].instl).to.equal(1); + }); - describe('ad pod / long form video', () => { - describe('required parameters with requireExactDuration false', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 300; - const DURATION_RANGE = [15, 30]; - const longFormVideoBidRequest = { + it('splits multi format bid requests', () => { + const combinedBannerAndVideoBidRequest = { + bidder: 'smaato', params: { publisherId: 'publisherId', - adbreakId: ADBREAK_ID, + adspaceId: 'adspaceId' }, mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: false - } + banner: BANNER_PREBID_MEDIATYPE, + video: VIDEO_OUTSTREAM_PREBID_MEDIATYPE }, - bidId: BID_ID + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 }; - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(ADPOD_DURATION / DURATION_RANGE[0]); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].bidfloor).to.be.undefined; - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - }); + const reqs = spec.buildRequests([combinedBannerAndVideoBidRequest], defaultBidderRequest); - it('sends instl if instl exists', () => { - const instl = { instl: 1 }; - const bidRequestWithInstl = Object.assign({}, longFormVideoBidRequest, {ortb2Imp: instl}); + expect(reqs).to.have.length(2); + expect(JSON.parse(reqs[0].data).imp[0].banner).to.deep.equal(BANNER_OPENRTB_IMP); + expect(JSON.parse(reqs[0].data).imp[0].video).to.not.exist; + expect(JSON.parse(reqs[1].data).imp[0].banner).to.not.exist; + expect(JSON.parse(reqs[1].data).imp[0].video).to.deep.equal(VIDEO_OUTSTREAM_OPENRTB_IMP); + }); - const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + describe('ad pod / long form video', () => { + describe('required parameters with requireExactDuration false', () => { + const ADBREAK_ID = 'adbreakId'; + const ADPOD = 'adpod'; + const BID_ID = '4331'; + const W = 640; + const H = 480; + const ADPOD_DURATION = 300; + const DURATION_RANGE = [15, 30]; + const longFormVideoBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: ADBREAK_ID, + }, + mediaTypes: { + video: { + context: ADPOD, + playerSize: [[W, H]], + adPodDurationSec: ADPOD_DURATION, + durationRangeSec: DURATION_RANGE, + requireExactDuration: false + } + }, + bidId: BID_ID + }; + + it('sends required fields', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.id).to.exist; + expect(req.imp.length).to.be.equal(ADPOD_DURATION / DURATION_RANGE[0]); + expect(req.imp[0].id).to.be.equal(BID_ID); + expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[0].video.w).to.be.equal(W); + expect(req.imp[0].video.h).to.be.equal(H); + expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[0].video.sequence).to.be.equal(1); + expect(req.imp[1].id).to.be.equal(BID_ID); + expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[1].bidfloor).to.be.undefined; + expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[1].video.w).to.be.equal(W); + expect(req.imp[1].video.h).to.be.equal(H); + expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.sequence).to.be.equal(2); + }); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].instl).to.equal(1); - expect(req.imp[1].instl).to.equal(1); - }); + it('sends instl if instl exists', () => { + const instl = {instl: 1}; + const bidRequestWithInstl = Object.assign({}, longFormVideoBidRequest, {ortb2Imp: instl}); - it('sends bidfloor when configured', () => { - const longFormVideoBidRequestWithFloor = Object.assign({}, longFormVideoBidRequest); - longFormVideoBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'video' && - JSON.stringify(arg.size) === JSON.stringify([640, 480])) { - return { - currency: 'USD', - floor: 0.789 + const reqs = spec.buildRequests([bidRequestWithInstl], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].instl).to.equal(1); + expect(req.imp[1].instl).to.equal(1); + }); + + it('sends bidfloor when configured', () => { + const longFormVideoBidRequestWithFloor = Object.assign({}, longFormVideoBidRequest); + longFormVideoBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'video' && + JSON.stringify(arg.size) === JSON.stringify([640, 480])) { + return { + currency: 'USD', + floor: 0.789 + } } } - } - const reqs = spec.buildRequests([longFormVideoBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.789); - expect(req.imp[1].bidfloor).to.be.equal(0.789); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.789); + expect(req.imp[1].bidfloor).to.be.equal(0.789); + }); - it('sends brand category exclusion as true when config is set to true', () => { - config.setConfig({adpod: {brandCategoryExclusion: true}}); + it('sends brand category exclusion as true when config is set to true', () => { + config.setConfig({adpod: {brandCategoryExclusion: true}}); - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(true); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(true); + }); - it('sends brand category exclusion as false when config is set to false', () => { - config.setConfig({adpod: {brandCategoryExclusion: false}}); + it('sends brand category exclusion as false when config is set to false', () => { + config.setConfig({adpod: {brandCategoryExclusion: false}}); - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + }); - it('sends brand category exclusion as false when config is not set', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + it('sends brand category exclusion as false when config is not set', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.brandcategoryexclusion).to.be.equal(false); + }); }); - }); - describe('required parameters with requireExactDuration true', () => { - const ADBREAK_ID = 'adbreakId'; - const ADPOD = 'adpod'; - const BID_ID = '4331'; - const W = 640; - const H = 480; - const ADPOD_DURATION = 5; - const DURATION_RANGE = [5, 15, 25]; - const longFormVideoBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: ADBREAK_ID, - }, - mediaTypes: { - video: { - context: ADPOD, - playerSize: [[W, H]], - adPodDurationSec: ADPOD_DURATION, - durationRangeSec: DURATION_RANGE, - requireExactDuration: true - } - }, - bidId: BID_ID - }; - - it('sends required fields', () => { - const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.id).to.exist; - expect(req.imp.length).to.be.equal(DURATION_RANGE.length); - expect(req.imp[0].id).to.be.equal(BID_ID); - expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[0].video.w).to.be.equal(W); - expect(req.imp[0].video.h).to.be.equal(H); - expect(req.imp[0].video.minduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[0]); - expect(req.imp[0].video.sequence).to.be.equal(1); - expect(req.imp[1].id).to.be.equal(BID_ID); - expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[1].video.w).to.be.equal(W); - expect(req.imp[1].video.h).to.be.equal(H); - expect(req.imp[1].video.minduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); - expect(req.imp[1].video.sequence).to.be.equal(2); - expect(req.imp[2].id).to.be.equal(BID_ID); - expect(req.imp[2].tagid).to.be.equal(ADBREAK_ID); - expect(req.imp[2].video.ext.context).to.be.equal(ADPOD); - expect(req.imp[2].video.w).to.be.equal(W); - expect(req.imp[2].video.h).to.be.equal(H); - expect(req.imp[2].video.minduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.maxduration).to.be.equal(DURATION_RANGE[2]); - expect(req.imp[2].video.sequence).to.be.equal(3); + describe('required parameters with requireExactDuration true', () => { + const ADBREAK_ID = 'adbreakId'; + const ADPOD = 'adpod'; + const BID_ID = '4331'; + const W = 640; + const H = 480; + const ADPOD_DURATION = 5; + const DURATION_RANGE = [5, 15, 25]; + const longFormVideoBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: ADBREAK_ID, + }, + mediaTypes: { + video: { + context: ADPOD, + playerSize: [[W, H]], + adPodDurationSec: ADPOD_DURATION, + durationRangeSec: DURATION_RANGE, + requireExactDuration: true + } + }, + bidId: BID_ID + }; + + it('sends required fields', () => { + const reqs = spec.buildRequests([longFormVideoBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.id).to.exist; + expect(req.imp.length).to.be.equal(DURATION_RANGE.length); + expect(req.imp[0].id).to.be.equal(BID_ID); + expect(req.imp[0].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[0].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[0].video.w).to.be.equal(W); + expect(req.imp[0].video.h).to.be.equal(H); + expect(req.imp[0].video.minduration).to.be.equal(DURATION_RANGE[0]); + expect(req.imp[0].video.maxduration).to.be.equal(DURATION_RANGE[0]); + expect(req.imp[0].video.sequence).to.be.equal(1); + expect(req.imp[1].id).to.be.equal(BID_ID); + expect(req.imp[1].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[1].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[1].video.w).to.be.equal(W); + expect(req.imp[1].video.h).to.be.equal(H); + expect(req.imp[1].video.minduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.maxduration).to.be.equal(DURATION_RANGE[1]); + expect(req.imp[1].video.sequence).to.be.equal(2); + expect(req.imp[2].id).to.be.equal(BID_ID); + expect(req.imp[2].tagid).to.be.equal(ADBREAK_ID); + expect(req.imp[2].video.ext.context).to.be.equal(ADPOD); + expect(req.imp[2].video.w).to.be.equal(W); + expect(req.imp[2].video.h).to.be.equal(H); + expect(req.imp[2].video.minduration).to.be.equal(DURATION_RANGE[2]); + expect(req.imp[2].video.maxduration).to.be.equal(DURATION_RANGE[2]); + expect(req.imp[2].video.sequence).to.be.equal(3); + }); }); - }); - - describe('forwarding of optional parameters', () => { - const MIMES = ['video/mp4', 'video/quicktime', 'video/3gpp', 'video/x-m4v']; - const STARTDELAY = 0; - const LINEARITY = 1; - const SKIP = 1; - const PROTOCOLS = [7]; - const SKIPMIN = 5; - const API = [7]; - const validBasicAdpodBidRequest = { - params: { - publisherId: 'publisherId', - adbreakId: 'adbreakId', - }, - mediaTypes: { - video: { - context: 'adpod', - playerSize: [640, 480], - adPodDurationSec: 300, - durationRangeSec: [15, 30], - mimes: MIMES, - startdelay: STARTDELAY, - linearity: LINEARITY, - skip: SKIP, - protocols: PROTOCOLS, - skipmin: SKIPMIN, - api: API - } - }, - bidId: 'bidId' - }; - it('sends general video fields when they are present', () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.mimes).to.eql(MIMES); - expect(req.imp[0].video.startdelay).to.be.equal(STARTDELAY); - expect(req.imp[0].video.linearity).to.be.equal(LINEARITY); - expect(req.imp[0].video.skip).to.be.equal(SKIP); - expect(req.imp[0].video.protocols).to.eql(PROTOCOLS); - expect(req.imp[0].video.skipmin).to.be.equal(SKIPMIN); - expect(req.imp[0].video.api).to.eql(API); - }); + describe('forwarding of optional parameters', () => { + const MIMES = ['video/mp4', 'video/quicktime', 'video/3gpp', 'video/x-m4v']; + const STARTDELAY = 0; + const LINEARITY = 1; + const SKIP = 1; + const PROTOCOLS = [7]; + const SKIPMIN = 5; + const API = [7]; + const validBasicAdpodBidRequest = { + params: { + publisherId: 'publisherId', + adbreakId: 'adbreakId', + }, + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + mimes: MIMES, + startdelay: STARTDELAY, + linearity: LINEARITY, + skip: SKIP, + protocols: PROTOCOLS, + skipmin: SKIPMIN, + api: API + } + }, + bidId: 'bidId' + }; + + it('sends general video fields when they are present', () => { + const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); + + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.mimes).to.eql(MIMES); + expect(req.imp[0].video.startdelay).to.be.equal(STARTDELAY); + expect(req.imp[0].video.linearity).to.be.equal(LINEARITY); + expect(req.imp[0].video.skip).to.be.equal(SKIP); + expect(req.imp[0].video.protocols).to.eql(PROTOCOLS); + expect(req.imp[0].video.skipmin).to.be.equal(SKIPMIN); + expect(req.imp[0].video.api).to.eql(API); + }); - it('sends series name when parameter is present', () => { - const SERIES_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeriesName = SERIES_NAME; + it('sends series name when parameter is present', () => { + const SERIES_NAME = 'foo' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvSeriesName = SERIES_NAME; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.series).to.be.equal(SERIES_NAME); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.series).to.be.equal(SERIES_NAME); + }); - it('sends episode name when parameter is present', () => { - const EPISODE_NAME = 'foo' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeName = EPISODE_NAME; + it('sends episode name when parameter is present', () => { + const EPISODE_NAME = 'foo' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvEpisodeName = EPISODE_NAME; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.title).to.be.equal(EPISODE_NAME); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.title).to.be.equal(EPISODE_NAME); + }); - it('sends season number as string when parameter is present', () => { - const SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST = 42 - const SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST = '42' - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvSeasonNumber = SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST; + it('sends season number as string when parameter is present', () => { + const SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST = 42 + const SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST = '42' + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvSeasonNumber = SEASON_NUMBER_AS_NUMBER_IN_PREBID_REQUEST; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.season).to.be.equal(SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.season).to.be.equal(SEASON_NUMBER_AS_STRING_IN_OUTGOING_REQUEST); + }); - it('sends episode number when parameter is present', () => { - const EPISODE_NUMBER = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.tvEpisodeNumber = EPISODE_NUMBER; + it('sends episode number when parameter is present', () => { + const EPISODE_NUMBER = 42 + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.tvEpisodeNumber = EPISODE_NUMBER; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.episode).to.be.equal(EPISODE_NUMBER); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.episode).to.be.equal(EPISODE_NUMBER); + }); - it('sends content length when parameter is present', () => { - const LENGTH = 42 - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentLengthSec = LENGTH; + it('sends content length when parameter is present', () => { + const LENGTH = 42 + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentLengthSec = LENGTH; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.len).to.be.equal(LENGTH); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.len).to.be.equal(LENGTH); + }); - it('sends livestream as 1 when content mode parameter is live', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'live'; + it('sends livestream as 1 when content mode parameter is live', () => { + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentMode = 'live'; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(1); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.livestream).to.be.equal(1); + }); - it('sends livestream as 0 when content mode parameter is on-demand', () => { - const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); - adpodRequestWithParameter.mediaTypes.video.contentMode = 'on-demand'; + it('sends livestream as 0 when content mode parameter is on-demand', () => { + const adpodRequestWithParameter = utils.deepClone(validBasicAdpodBidRequest); + adpodRequestWithParameter.mediaTypes.video.contentMode = 'on-demand'; - const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); + const reqs = spec.buildRequests([adpodRequestWithParameter], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.site.content.livestream).to.be.equal(0); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.site.content.livestream).to.be.equal(0); + }); - it("doesn't send any optional parameters when none are present", () => { - const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); + it('doesn\'t send any optional parameters when none are present', () => { + const reqs = spec.buildRequests([validBasicAdpodBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].video.ext.requireExactDuration).to.not.exist; - expect(req.site.content).to.not.exist; + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].video.ext.requireExactDuration).to.not.exist; + expect(req.site.content).to.not.exist; + }); }); }); - }); + } }); - describe('buildRequests for native imps', () => { - const NATIVE_OPENRTB_REQUEST = { - ver: '1.2', - assets: [ - { - id: 4, - required: 1, - img: { - type: 3, - w: 150, - h: 50, - } - }, - { - id: 2, - required: 1, - img: { - type: 2, - w: 50, - h: 50 - } - }, - { - id: 0, - required: 1, - title: { - len: 80 - } - }, - { - id: 1, - required: 1, - data: { - type: 1 - } - }, - { - id: 3, - required: 1, - data: { - type: 2 - } - }, - { - id: 5, - required: 1, - data: { - type: 3 - } - }, - { - id: 6, - required: 1, - data: { - type: 4 - } - }, - { - id: 7, - required: 1, - data: { - type: 5 - } - }, - { - id: 8, - required: 1, - data: { - type: 6 - } - }, - { - id: 9, - required: 1, - data: { - type: 7 - } - }, - { - id: 10, - required: 0, - data: { - type: 8 - } - }, - { - id: 11, - required: 1, - data: { - type: 9 - } - }, - { - id: 12, - require: 0, - data: { - type: 10 - } - }, - { - id: 13, - required: 0, - data: { - type: 11 - } - }, - { - id: 14, - required: 1, - data: { - type: 12 + if (FEATURES.NATIVE) { + describe('buildRequests for native imps', () => { + const NATIVE_OPENRTB_REQUEST = { + ver: '1.2', + assets: [ + { + id: 4, + required: 1, + img: { + type: 3, + w: 150, + h: 50, + } + }, + { + id: 2, + required: 1, + img: { + type: 2, + w: 50, + h: 50 + } + }, + { + id: 0, + required: 1, + title: { + len: 80 + } + }, + { + id: 1, + required: 1, + data: { + type: 1 + } + }, + { + id: 3, + required: 1, + data: { + type: 2 + } + }, + { + id: 5, + required: 1, + data: { + type: 3 + } + }, + { + id: 6, + required: 1, + data: { + type: 4 + } + }, + { + id: 7, + required: 1, + data: { + type: 5 + } + }, + { + id: 8, + required: 1, + data: { + type: 6 + } + }, + { + id: 9, + required: 1, + data: { + type: 7 + } + }, + { + id: 10, + required: 0, + data: { + type: 8 + } + }, + { + id: 11, + required: 1, + data: { + type: 9 + } + }, + { + id: 12, + require: 0, + data: { + type: 10 + } + }, + { + id: 13, + required: 0, + data: { + type: 11 + } + }, + { + id: 14, + required: 1, + data: { + type: 12 + } } - } - ] - }; + ] + }; - const singleNativeBidRequest = { - bidder: 'smaato', - params: { - publisherId: 'publisherId', - adspaceId: 'adspaceId' - }, - nativeOrtbRequest: NATIVE_OPENRTB_REQUEST, - adUnitCode: '/19968336/header-bid-tag-0', - transactionId: 'transactionId', - bidId: 'bidId', - bidderRequestId: 'bidderRequestId', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - }; + const singleNativeBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + nativeOrtbRequest: NATIVE_OPENRTB_REQUEST, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 + }; - it('sends correct native imps', () => { - const reqs = spec.buildRequests([singleNativeBidRequest], defaultBidderRequest); + it('sends correct native imps', () => { + const reqs = spec.buildRequests([singleNativeBidRequest], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].id).to.be.equal('bidId'); - expect(req.imp[0].tagid).to.be.equal('adspaceId'); - expect(req.imp[0].bidfloor).to.be.undefined; - expect(req.imp[0].native.request).to.deep.equal(JSON.stringify(NATIVE_OPENRTB_REQUEST)); - }); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].id).to.be.equal('bidId'); + expect(req.imp[0].tagid).to.be.equal('adspaceId'); + expect(req.imp[0].bidfloor).to.be.undefined; + expect(req.imp[0].native.request).to.deep.equal(JSON.stringify(NATIVE_OPENRTB_REQUEST)); + }); - it('sends bidfloor when configured', () => { - const singleNativeBidRequestWithFloor = Object.assign({}, singleNativeBidRequest); - singleNativeBidRequestWithFloor.getFloor = function(arg) { - if (arg.currency === 'USD' && - arg.mediaType === 'native' && - JSON.stringify(arg.size) === JSON.stringify([150, 50])) { - return { - currency: 'USD', - floor: 0.123 + it('sends bidfloor when configured', () => { + const singleNativeBidRequestWithFloor = Object.assign({}, singleNativeBidRequest); + singleNativeBidRequestWithFloor.getFloor = function (arg) { + if (arg.currency === 'USD' && + arg.mediaType === 'native' && + JSON.stringify(arg.size) === JSON.stringify([150, 50])) { + return { + currency: 'USD', + floor: 0.123 + } } } - } - const reqs = spec.buildRequests([singleNativeBidRequestWithFloor], defaultBidderRequest); + const reqs = spec.buildRequests([singleNativeBidRequestWithFloor], defaultBidderRequest); - const req = extractPayloadOfFirstAndOnlyRequest(reqs); - expect(req.imp[0].bidfloor).to.be.equal(0.123); + const req = extractPayloadOfFirstAndOnlyRequest(reqs); + expect(req.imp[0].bidfloor).to.be.equal(0.123); + }); }); - }); - + } describe('in-app requests', () => { const LOCATION = { lat: 33.3, @@ -1263,7 +1342,7 @@ describe('smaatoBidAdapterTest', () => { adm = ''; break; case ADTYPE_NATIVE: - adm = JSON.stringify({ native: NATIVE_RESPONSE }) + adm = JSON.stringify({native: NATIVE_RESPONSE}) break; default: throw Error('Invalid AdType'); From 3a1dff0f635139eca591585ebcde178271ae7265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kowalski?= <112544015+pkowalski-id5@users.noreply.github.com> Date: Mon, 6 May 2024 20:16:11 +0200 Subject: [PATCH 090/147] ID5 ID module: config call as bounce (#11424) --- modules/id5IdSystem.js | 44 +++--- test/spec/modules/id5IdSystem_spec.js | 203 ++++++++++++++------------ 2 files changed, 131 insertions(+), 116 deletions(-) diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index 42f0044edc3..e7a7ec7f037 100644 --- a/modules/id5IdSystem.js +++ b/modules/id5IdSystem.js @@ -148,7 +148,7 @@ export const id5IdSubmodule = { id5id: { uid: universalUid, ext: ext - }, + } }; if (isPlainObject(ext.euid)) { @@ -156,7 +156,7 @@ export const id5IdSubmodule = { uid: ext.euid.uids[0].id, source: ext.euid.source, ext: {provider: ID5_DOMAIN} - } + }; } const abTestingResult = deepAccess(value, 'ab_testing.result'); @@ -196,7 +196,7 @@ export const id5IdSubmodule = { } if (!hasWriteConsentToLocalStorage(consentData)) { - logInfo(LOG_PREFIX + 'Skipping ID5 local storage write because no consent given.') + logInfo(LOG_PREFIX + 'Skipping ID5 local storage write because no consent given.'); return undefined; } @@ -204,7 +204,7 @@ export const id5IdSubmodule = { const fetchFlow = new IdFetchFlow(submoduleConfig, consentData, cacheIdObj, uspDataHandler.getConsentData(), gppDataHandler.getConsentData()); fetchFlow.execute() .then(response => { - cbFunction(response) + cbFunction(response); }) .catch(error => { logError(LOG_PREFIX + 'getId fetch encountered an error', error); @@ -227,7 +227,7 @@ export const id5IdSubmodule = { */ extendId(config, consentData, cacheIdObj) { if (!hasWriteConsentToLocalStorage(consentData)) { - logInfo(LOG_PREFIX + 'No consent given for ID5 local storage writing, skipping nb increment.') + logInfo(LOG_PREFIX + 'No consent given for ID5 local storage writing, skipping nb increment.'); return cacheIdObj; } @@ -239,12 +239,12 @@ export const id5IdSubmodule = { }, eids: { 'id5id': { - getValue: function(data) { - return data.uid + getValue: function (data) { + return data.uid; }, source: ID5_DOMAIN, atype: 1, - getUidExt: function(data) { + getUidExt: function (data) { if (data.ext) { return data.ext; } @@ -264,16 +264,16 @@ export const id5IdSubmodule = { } } } - }, + } }; export class IdFetchFlow { constructor(submoduleConfig, gdprConsentData, cacheIdObj, usPrivacyData, gppData) { - this.submoduleConfig = submoduleConfig - this.gdprConsentData = gdprConsentData - this.cacheIdObj = cacheIdObj - this.usPrivacyData = usPrivacyData - this.gppData = gppData + this.submoduleConfig = submoduleConfig; + this.gdprConsentData = gdprConsentData; + this.cacheIdObj = cacheIdObj; + this.usPrivacyData = usPrivacyData; + this.gppData = gppData; } /** @@ -324,7 +324,11 @@ export class IdFetchFlow { let url = this.submoduleConfig.params.configUrl || ID5_API_CONFIG_URL; // override for debug/test purposes only const response = await fetch(url, { method: 'POST', - body: JSON.stringify(this.submoduleConfig) + body: JSON.stringify({ + ...this.submoduleConfig, + bounce: true + }), + credentials: 'include' }); if (!response.ok) { throw new Error('Error while calling config endpoint: ', response); @@ -342,7 +346,7 @@ export class IdFetchFlow { const extensionsUrl = extensionsCallConfig.url; const method = extensionsCallConfig.method || 'GET'; const body = method === 'GET' ? undefined : JSON.stringify(extensionsCallConfig.body || {}); - const response = await fetch(extensionsUrl, { method, body }); + const response = await fetch(extensionsUrl, {method, body}); if (!response.ok) { throw new Error('Error while calling extensions endpoint: ', response); } @@ -360,7 +364,7 @@ export class IdFetchFlow { ...additionalData, extensions: extensionsData }); - const response = await fetch(fetchUrl, { method: 'POST', body, credentials: 'include' }); + const response = await fetch(fetchUrl, {method: 'POST', body, credentials: 'include'}); if (!response.ok) { throw new Error('Error while calling fetch endpoint: ', response); } @@ -456,7 +460,7 @@ function validateConfig(config) { return false; } - const partner = config.params.partner + const partner = config.params.partner; if (typeof partner === 'string' || partner instanceof String) { let parsedPartnerId = parseInt(partner); if (isNaN(parsedPartnerId) || parsedPartnerId < 0) { @@ -566,8 +570,8 @@ export function storeInLocalStorage(key, value, expDays) { */ function hasWriteConsentToLocalStorage(consentData) { const hasGdpr = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies; - const localstorageConsent = deepAccess(consentData, `vendorData.purpose.consents.1`) - const id5VendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${GVLID.toString()}`) + const localstorageConsent = deepAccess(consentData, `vendorData.purpose.consents.1`); + const id5VendorConsent = deepAccess(consentData, `vendorData.vendor.consents.${GVLID.toString()}`); if (hasGdpr && (!localstorageConsent || !id5VendorConsent)) { return false; } diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js index fd5d24295f5..1da862cc007 100644 --- a/test/spec/modules/id5IdSystem_spec.js +++ b/test/spec/modules/id5IdSystem_spec.js @@ -8,7 +8,7 @@ import { } from '../../../modules/userId/index.js'; import {config} from '../../../src/config.js'; import * as events from '../../../src/events.js'; -import { EVENTS } from '../../../src/constants.js'; +import {EVENTS} from '../../../src/constants.js'; import * as utils from '../../../src/utils.js'; import {uspDataHandler, gppDataHandler} from '../../../src/adapterManager.js'; import '../../../src/prebid.js'; @@ -81,11 +81,11 @@ describe('ID5 ID System', function () { 131: true } } - } + }; const HEADERS_CONTENT_TYPE_JSON = { 'Content-Type': 'application/json' - } + }; function getId5FetchConfig(partner = ID5_TEST_PARTNER_ID, storageName = id5System.ID5_STORAGE_NAME, storageType = 'html5') { return { @@ -98,7 +98,7 @@ describe('ID5 ID System', function () { type: storageType, expires: 90 } - } + }; } function getId5ValueConfig(value) { @@ -109,7 +109,7 @@ describe('ID5 ID System', function () { uid: value } } - } + }; } function getUserSyncConfig(userIds) { @@ -118,7 +118,7 @@ describe('ID5 ID System', function () { userIds: userIds, syncDelay: 0 } - } + }; } function getFetchLocalStorageConfig() { @@ -167,6 +167,7 @@ describe('ID5 ID System', function () { const configRequest = await this.expectFirstRequest(); expect(configRequest.url).is.eq(ID5_API_CONFIG_URL); expect(configRequest.method).is.eq('POST'); + expect(configRequest.withCredentials).is.eq(true); return configRequest; } @@ -184,7 +185,7 @@ describe('ID5 ID System', function () { } async #waitOnRequest(index) { - const server = this.server + const server = this.server; return new GreedyPromise((resolve) => { const waitForCondition = () => { if (server.requests && server.requests.length > index) { @@ -214,31 +215,37 @@ describe('ID5 ID System', function () { expect(id5System.id5IdSubmodule.getId({})).is.eq(undefined); // valid params, invalid id5System.storage - expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 } })).to.be.eq(undefined); - expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: {} })).to.be.eq(undefined); - expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: { name: '' } })).to.be.eq(undefined); - expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: { type: '' } })).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({params: {partner: 123}})).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({params: {partner: 123}, storage: {}})).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({params: {partner: 123}, storage: {name: ''}})).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({params: {partner: 123}, storage: {type: ''}})).to.be.eq(undefined); // valid id5System.storage, invalid params - expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, })).to.be.eq(undefined); - expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { } })).to.be.eq(undefined); - expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 'abc' } })).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({storage: {name: 'name', type: 'html5'}})).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({storage: {name: 'name', type: 'html5'}, params: {}})).to.be.eq(undefined); + expect(id5System.id5IdSubmodule.getId({ + storage: {name: 'name', type: 'html5'}, + params: {partner: 'abc'} + })).to.be.eq(undefined); }); it('should warn with non-recommended id5System.storage params', function () { const logWarnStub = sinon.stub(utils, 'logWarn'); - id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 123 } }); + id5System.id5IdSubmodule.getId({storage: {name: 'name', type: 'html5'}, params: {partner: 123}}); expect(logWarnStub.calledOnce).to.be.true; logWarnStub.restore(); - id5System.id5IdSubmodule.getId({ storage: { name: id5System.ID5_STORAGE_NAME, type: 'cookie', }, params: { partner: 123 } }); + id5System.id5IdSubmodule.getId({ + storage: {name: id5System.ID5_STORAGE_NAME, type: 'cookie'}, + params: {partner: 123} + }); expect(logWarnStub.calledOnce).to.be.true; logWarnStub.restore(); }); }); - describe('Check for valid consent', function() { + describe('Check for valid consent', function () { const dataConsentVals = [ [{purpose: {consents: {1: false}}}, {vendor: {consents: {131: true}}}, ' no purpose consent'], [{purpose: {consents: {1: true}}}, {vendor: {consents: {131: false}}}, ' no vendor consent'], @@ -250,15 +257,15 @@ describe('ID5 ID System', function () { [{purpose: {consents: {1: true}}}, {vendor: {consents: {31: true}}}, ' incorrect vendor consent'] ]; - dataConsentVals.forEach(function([purposeConsent, vendorConsent, caseName]) { - it('should fail with invalid consent because of ' + caseName, function() { + dataConsentVals.forEach(function ([purposeConsent, vendorConsent, caseName]) { + it('should fail with invalid consent because of ' + caseName, function () { const dataConsent = { gdprApplies: true, consentString: 'consentString', vendorData: { purposeConsent, vendorConsent } - } + }; expect(id5System.id5IdSubmodule.getId(config)).is.eq(undefined); expect(id5System.id5IdSubmodule.getId(config, dataConsent)).is.eq(undefined); @@ -270,25 +277,25 @@ describe('ID5 ID System', function () { }); describe('Xhr Requests from getId()', function () { - const responseHeader = HEADERS_CONTENT_TYPE_JSON - let gppStub + const responseHeader = HEADERS_CONTENT_TYPE_JSON; + let gppStub; beforeEach(function () { }); afterEach(function () { - uspDataHandler.reset() - gppStub?.restore() + uspDataHandler.reset(); + gppStub?.restore(); }); it('should call the ID5 server and handle a valid response', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const config = getId5FetchConfig(); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(config, undefined, undefined); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); expect(fetchRequest.url).to.contain(ID5_ENDPOINT); expect(fetchRequest.withCredentials).is.true; @@ -298,12 +305,12 @@ describe('ID5 ID System', function () { expect(requestBody.o).is.eq('pbjs'); expect(requestBody.pd).is.undefined; expect(requestBody.s).is.undefined; - expect(requestBody.provider).is.undefined + expect(requestBody.provider).is.undefined; expect(requestBody.v).is.eq('$prebid.version$'); expect(requestBody.gdpr).is.eq(0); expect(requestBody.gdpr_consent).is.undefined; expect(requestBody.us_privacy).is.undefined; - expect(requestBody.storage).is.deep.eq(config.storage) + expect(requestBody.storage).is.deep.eq(config.storage); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); @@ -312,17 +319,17 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with gdpr data ', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const consentData = { gdprApplies: true, consentString: 'consentString', vendorData: ALLOWED_ID5_VENDOR_DATA - } + }; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); const requestBody = JSON.parse(fetchRequest.requestBody); expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID); expect(requestBody.gdpr).to.eq(1); @@ -335,19 +342,19 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server without gdpr data when gdpr not applies ', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const consentData = { gdprApplies: false, consentString: 'consentString' - } + }; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); const requestBody = JSON.parse(fetchRequest.requestBody); expect(requestBody.gdpr).to.eq(0); - expect(requestBody.gdpr_consent).is.undefined + expect(requestBody.gdpr_consent).is.undefined; fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); @@ -357,18 +364,18 @@ describe('ID5 ID System', function () { it('should call the ID5 server with us privacy consent', async function () { const usPrivacyString = '1YN-'; - uspDataHandler.setConsentData(usPrivacyString) - const xhrServerMock = new XhrServerMock(server) + uspDataHandler.setConsentData(usPrivacyString); + const xhrServerMock = new XhrServerMock(server); const consentData = { gdprApplies: true, consentString: 'consentString', vendorData: ALLOWED_ID5_VENDOR_DATA - } + }; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); const requestBody = JSON.parse(fetchRequest.requestBody); expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID); expect(requestBody.us_privacy).to.eq(usPrivacyString); @@ -380,12 +387,12 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with no signature field when no stored object', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); const requestBody = JSON.parse(fetchRequest.requestBody); expect(requestBody.s).is.undefined; @@ -394,7 +401,7 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server for config with submodule config object', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5FetchConfig = getId5FetchConfig(); id5FetchConfig.params.extraParam = { x: 'X', @@ -402,22 +409,25 @@ describe('ID5 ID System', function () { a: 1, b: '3' } - } + }; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined); const configRequest = await xhrServerMock.expectConfigRequest(); const requestBody = JSON.parse(configRequest.requestBody); - expect(requestBody).is.deep.eq(id5FetchConfig) + expect(requestBody).is.deep.eq({ + ...id5FetchConfig, + bounce: true + }); - const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest) + const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); await submoduleResponsePromise; }); it('should call the ID5 server for config with partner id being a string', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5FetchConfig = getId5FetchConfig(); id5FetchConfig.params.partner = '173'; @@ -425,18 +435,18 @@ describe('ID5 ID System', function () { const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined); const configRequest = await xhrServerMock.expectConfigRequest(); - const requestBody = JSON.parse(configRequest.requestBody) - expect(requestBody.params.partner).is.eq(173) + const requestBody = JSON.parse(configRequest.requestBody); + expect(requestBody.params.partner).is.eq(173); - const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest) + const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); await submoduleResponsePromise; }); it('should call the ID5 server for config with overridden url', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5FetchConfig = getId5FetchConfig(); - id5FetchConfig.params.configUrl = 'http://localhost/x/y/z' + id5FetchConfig.params.configUrl = 'http://localhost/x/y/z'; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined); @@ -444,13 +454,13 @@ describe('ID5 ID System', function () { const configRequest = await xhrServerMock.expectFirstRequest(); expect(configRequest.url).is.eq('http://localhost/x/y/z'); - const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest) + const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); await submoduleResponsePromise; }); it('should call the ID5 server with additional data when provided', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined); @@ -472,18 +482,18 @@ describe('ID5 ID System', function () { expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID); expect(requestBody.o).is.eq('pbjs'); expect(requestBody.v).is.eq('$prebid.version$'); - expect(requestBody.arg1).is.eq('123') + expect(requestBody.arg1).is.eq('123'); expect(requestBody.arg2).is.deep.eq({ x: '1', y: 2 - }) + }); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); await submoduleResponsePromise; }); it('should call the ID5 server with extensions', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined); @@ -498,8 +508,8 @@ describe('ID5 ID System', function () { method: 'GET' } }); - expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT) - expect(extensionsRequest.method).is.eq('GET') + expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT); + expect(extensionsRequest.method).is.eq('GET'); extensionsRequest.respond(200, responseHeader, JSON.stringify({ lb: 'ex' @@ -511,14 +521,14 @@ describe('ID5 ID System', function () { expect(requestBody.v).is.eq('$prebid.version$'); expect(requestBody.extensions).is.deep.eq({ lb: 'ex' - }) + }); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); await submoduleResponsePromise; }); it('should call the ID5 server with extensions fetched using method POST', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined); @@ -537,15 +547,15 @@ describe('ID5 ID System', function () { } } }); - expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT) - expect(extensionsRequest.method).is.eq('POST') - const extRequestBody = JSON.parse(extensionsRequest.requestBody) + expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT); + expect(extensionsRequest.method).is.eq('POST'); + const extRequestBody = JSON.parse(extensionsRequest.requestBody); expect(extRequestBody).is.deep.eq({ x: '1', y: 2 - }) + }); extensionsRequest.respond(200, responseHeader, JSON.stringify({ - lb: 'post', + lb: 'post' })); const fetchRequest = await xhrServerMock.expectNextRequest(); @@ -562,12 +572,12 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with signature field from stored object', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ); - const fetchRequest = await xhrServerMock.expectFetchRequest() + const fetchRequest = await xhrServerMock.expectFetchRequest(); const requestBody = JSON.parse(fetchRequest.requestBody); expect(requestBody.s).is.eq(ID5_STORED_SIGNATURE); @@ -576,7 +586,7 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with pd field when pd config is set', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const pubData = 'b50ca08271795a8e7e4012813f23d505193d75c0f2e2bb99baa63aa822f66ed3'; const id5Config = getId5FetchConfig(); @@ -594,7 +604,7 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with no pd field when pd config is not set', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5Config = getId5FetchConfig(); id5Config.params.pd = undefined; @@ -610,7 +620,7 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with nb=1 when no stored value exists and reset after', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const TEST_PARTNER_ID = 189; coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(TEST_PARTNER_ID)); @@ -647,9 +657,9 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server with ab_testing object when abTesting is turned on', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5Config = getId5FetchConfig(); - id5Config.params.abTesting = {enabled: true, controlGroupPct: 0.234} + id5Config.params.abTesting = {enabled: true, controlGroupPct: 0.234}; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ); @@ -664,9 +674,9 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server without ab_testing object when abTesting is turned off', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5Config = getId5FetchConfig(); - id5Config.params.abTesting = {enabled: false, controlGroupPct: 0.55} + id5Config.params.abTesting = {enabled: false, controlGroupPct: 0.55}; // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ); @@ -680,7 +690,7 @@ describe('ID5 ID System', function () { }); it('should call the ID5 server without ab_testing when when abTesting is not set', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const id5Config = getId5FetchConfig(); // Trigger the fetch but we await on it later @@ -695,7 +705,7 @@ describe('ID5 ID System', function () { }); it('should store the privacy object from the ID5 server response', async function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ); @@ -733,7 +743,7 @@ describe('ID5 ID System', function () { expect(id5System.getFromLocalStorage(id5System.ID5_PRIVACY_STORAGE_NAME)).is.null; }); - describe('with successful external module call', function() { + describe('with successful external module call', function () { const MOCK_RESPONSE = { ...ID5_JSON_RESPONSE, universal_uid: 'my_mock_reponse' @@ -743,7 +753,8 @@ describe('ID5 ID System', function () { beforeEach(() => { window.id5Prebid = { integration: { - fetchId5Id: function() {} + fetchId5Id: function () { + } } }; mockId5ExternalModule = sinon.stub(window.id5Prebid.integration, 'fetchId5Id') @@ -755,7 +766,7 @@ describe('ID5 ID System', function () { delete window.id5Prebid; }); - it('should retrieve the response from the external module interface', async function() { + it('should retrieve the response from the external module interface', async function () { const xhrServerMock = new XhrServerMock(server); const config = getId5FetchConfig(); config.params.externalModuleUrl = 'https://test-me.test'; @@ -772,8 +783,8 @@ describe('ID5 ID System', function () { }); }); - describe('with failing external module loading', function() { - it('should fallback to regular logic if external module fails to load', async function() { + describe('with failing external module loading', function () { + it('should fallback to regular logic if external module fails to load', async function () { const xhrServerMock = new XhrServerMock(server); const config = getId5FetchConfig(); config.params.externalModuleUrl = 'https://test-me.test'; // Fails by loading this fake URL @@ -791,7 +802,7 @@ describe('ID5 ID System', function () { }); it('should pass gpp_string and gpp_sid to ID5 server', function () { - let xhrServerMock = new XhrServerMock(server) + let xhrServerMock = new XhrServerMock(server); gppStub = sinon.stub(gppDataHandler, 'getConsentData'); gppStub.returns({ ready: true, @@ -806,7 +817,7 @@ describe('ID5 ID System', function () { expect(requestBody.gpp_string).is.equal('GPP_STRING'); expect(requestBody.gpp_sid).contains(2); fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); - return submoduleResponse + return submoduleResponse; }); }); @@ -823,7 +834,7 @@ describe('ID5 ID System', function () { id5System.storage.getCookie.callsFake(() => ' Not JSON '); id5System.id5IdSubmodule.getId(getId5FetchConfig()); }); - }) + }); }); describe('Local storage', () => { @@ -839,9 +850,9 @@ describe('ID5 ID System', function () { [true, 1], [false, 0] ].forEach(([isEnabled, expectedValue]) => { - it(`should check localStorage availability and log in request. Available=${isEnabled}`, async function() { - const xhrServerMock = new XhrServerMock(server) - id5System.storage.localStorageIsEnabled.callsFake(() => isEnabled) + it(`should check localStorage availability and log in request. Available=${isEnabled}`, async function () { + const xhrServerMock = new XhrServerMock(server); + id5System.storage.localStorageIsEnabled.callsFake(() => isEnabled); // Trigger the fetch but we await on it later const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ); @@ -868,7 +879,7 @@ describe('ID5 ID System', function () { coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME); coreStorage.removeDataFromLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`); coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(ID5_TEST_PARTNER_ID)); - coreStorage.setDataInLocalStorage(id5System.ID5_STORAGE_NAME + '_cst', getConsentHash()) + coreStorage.setDataInLocalStorage(id5System.ID5_STORAGE_NAME + '_cst', getConsentHash()); adUnits = [getAdUnitMock()]; }); afterEach(function () { @@ -876,7 +887,7 @@ describe('ID5 ID System', function () { coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME); coreStorage.removeDataFromLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`); coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(ID5_TEST_PARTNER_ID)); - coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME + '_cst') + coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME + '_cst'); sandbox.restore(); }); @@ -930,7 +941,7 @@ describe('ID5 ID System', function () { provider: ID5_SOURCE } }] - }) + }); }); }); done(); @@ -967,7 +978,7 @@ describe('ID5 ID System', function () { requestBidsHook((adUnitConfig) => { expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(1); - done() + done(); }, {adUnits}); }); @@ -981,12 +992,12 @@ describe('ID5 ID System', function () { requestBidsHook(() => { expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(2); - done() + done(); }, {adUnits}); }); it('should call ID5 servers with signature and incremented nb post auction if refresh needed', function () { - const xhrServerMock = new XhrServerMock(server) + const xhrServerMock = new XhrServerMock(server); const initialLocalStorageValue = JSON.stringify(ID5_STORED_OBJ); id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, initialLocalStorageValue, 1); id5System.storeInLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`, id5System.expDaysStr(-1), 1); @@ -1000,7 +1011,7 @@ describe('ID5 ID System', function () { return new Promise((resolve) => { requestBidsHook(() => { - resolve() + resolve(); }, {adUnits}); }).then(() => { expect(xhrServerMock.hasReceivedAnyRequest()).is.false; @@ -1018,11 +1029,11 @@ describe('ID5 ID System', function () { if (id5System.getFromLocalStorage(id5System.ID5_STORAGE_NAME) !== initialLocalStorageValue) return resolve(); setTimeout(waitForCondition, 30); })(); - }) + }); }).then(() => { expect(decodeURIComponent(id5System.getFromLocalStorage(id5System.ID5_STORAGE_NAME))).is.eq(JSON.stringify(ID5_JSON_RESPONSE)); expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0); - }) + }); }); }); From 2bb9f9759da25d53203b716f225adebf063ef09a Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Tue, 7 May 2024 02:05:31 +0530 Subject: [PATCH 091/147] DeepIntent Id Module : fix user ids not being passed on page reload due to getValue func miss (#11383) * fix user ids not being passed on page reload due to extendId func miss * remove extendId and add function to read value for eids * handle inconsistent localstorage values in deepintent id * remove unused imports * revert to getValue changes * revert version in package-lock * update test suite for deepintent id system --- modules/deepintentDpesIdSystem.js | 9 ++- .../modules/deepintentDpesIdsystem_spec.js | 60 +++++++------------ 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/modules/deepintentDpesIdSystem.js b/modules/deepintentDpesIdSystem.js index 2d3eae980cd..a1f1e29a4ce 100644 --- a/modules/deepintentDpesIdSystem.js +++ b/modules/deepintentDpesIdSystem.js @@ -8,6 +8,7 @@ import { submodule } from '../src/hook.js'; import {getStorageManager} from '../src/storageManager.js'; import {MODULE_TYPE_UID} from '../src/activities/modules.js'; +import {isPlainObject} from '../src/utils.js'; /** * @typedef {import('../modules/userId/index.js').Submodule} Submodule @@ -49,7 +50,13 @@ export const deepintentDpesSubmodule = { eids: { 'deepintentId': { source: 'deepintent.com', - atype: 3 + atype: 3, + getValue: (userIdData) => { + if (isPlainObject(userIdData) && userIdData?.id) { + return userIdData.id; + } + return userIdData; + } }, }, }; diff --git a/test/spec/modules/deepintentDpesIdsystem_spec.js b/test/spec/modules/deepintentDpesIdsystem_spec.js index 4c26b118a98..3bd1e71d8f6 100644 --- a/test/spec/modules/deepintentDpesIdsystem_spec.js +++ b/test/spec/modules/deepintentDpesIdsystem_spec.js @@ -1,12 +1,8 @@ import { expect } from 'chai'; -import {find} from 'src/polyfill.js'; -import { storage, deepintentDpesSubmodule } from 'modules/deepintentDpesIdSystem.js'; -import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js'; -import { config } from 'src/config.js'; +import { deepintentDpesSubmodule } from 'modules/deepintentDpesIdSystem.js'; -const DI_COOKIE_NAME = '_dpes_id'; -const DI_COOKIE_STORED = '{"id":"2cf40748c4f7f60d343336e08f80dc99"}'; const DI_COOKIE_OBJECT = {id: '2cf40748c4f7f60d343336e08f80dc99'}; +const DI_UPDATED_STORAGE = '2cf40748c4f7f60d343336e08f80dc99'; const cookieConfig = { name: 'deepintentId', @@ -27,50 +23,40 @@ const html5Config = { } describe('Deepintent DPES System', () => { - let getDataFromLocalStorageStub, localStorageIsEnabledStub; - let getCookieStub, cookiesAreEnabledStub; - - beforeEach(() => { - getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); - localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); - getCookieStub = sinon.stub(storage, 'getCookie'); - cookiesAreEnabledStub = sinon.stub(storage, 'cookiesAreEnabled'); - }); - - afterEach(() => { - getDataFromLocalStorageStub.restore(); - localStorageIsEnabledStub.restore(); - getCookieStub.restore(); - cookiesAreEnabledStub.restore(); - }); - describe('Deepintent Dpes Sytsem: test "getId" method', () => { - it('Wrong config should fail the tests', () => { - // no config - expect(deepintentDpesSubmodule.getId()).to.be.eq(undefined); - expect(deepintentDpesSubmodule.getId({ })).to.be.eq(undefined); - - expect(deepintentDpesSubmodule.getId({params: {}, storage: {}})).to.be.eq(undefined); - expect(deepintentDpesSubmodule.getId({params: {}, storage: {type: 'cookie'}})).to.be.eq(undefined); - expect(deepintentDpesSubmodule.getId({params: {}, storage: {name: '_dpes_id'}})).to.be.eq(undefined); + it('If nothing is found in cache, return undefined', () => { + let diId = deepintentDpesSubmodule.getId({}, undefined, undefined); + expect(diId).to.be.eq(undefined); }); it('Get value stored in cookie for getId', () => { - getCookieStub.withArgs(DI_COOKIE_NAME).returns(DI_COOKIE_STORED); let diId = deepintentDpesSubmodule.getId(cookieConfig, undefined, DI_COOKIE_OBJECT); expect(diId).to.deep.equal(DI_COOKIE_OBJECT); }); it('provides the stored deepintentId if cookie is absent but present in local storage', () => { - getDataFromLocalStorageStub.withArgs(DI_COOKIE_NAME).returns(DI_COOKIE_STORED); - let idx = deepintentDpesSubmodule.getId(html5Config, undefined, DI_COOKIE_OBJECT); - expect(idx).to.deep.equal(DI_COOKIE_OBJECT); + let idx = deepintentDpesSubmodule.getId(html5Config, undefined, DI_UPDATED_STORAGE); + expect(idx).to.be.eq(DI_UPDATED_STORAGE); }); }); describe('Deepintent Dpes System : test "decode" method', () => { - it('Get the correct decoded value for dpes id', () => { - expect(deepintentDpesSubmodule.decode(DI_COOKIE_OBJECT, cookieConfig)).to.deep.equal({'deepintentId': {'id': '2cf40748c4f7f60d343336e08f80dc99'}}); + it('Get the correct decoded value for dpes id, if an object is set return object', () => { + expect(deepintentDpesSubmodule.decode(DI_COOKIE_OBJECT, cookieConfig)).to.deep.equal({'deepintentId': DI_COOKIE_OBJECT}); + }); + + it('Get the correct decoded value for dpes id, if a string is set return string', () => { + expect(deepintentDpesSubmodule.decode(DI_UPDATED_STORAGE, {})).to.deep.equal({'deepintentId': DI_UPDATED_STORAGE}); + }); + }); + + describe('Deepintent Dpes System : test "getValue" method in eids', () => { + it('Get the correct string value for dpes id, if an object is set in local storage', () => { + expect(deepintentDpesSubmodule.eids.deepintentId.getValue(DI_COOKIE_OBJECT)).to.be.equal(DI_UPDATED_STORAGE); + }); + + it('Get the correct string value for dpes id, if a string is set in local storage', () => { + expect(deepintentDpesSubmodule.eids.deepintentId.getValue(DI_UPDATED_STORAGE)).to.be.eq(DI_UPDATED_STORAGE); }); }); }); From 55d008a5934e035f3cb3adb36ef0376e4483264f Mon Sep 17 00:00:00 2001 From: ecoeco163 <147788250+ecoeco163@users.noreply.github.com> Date: Tue, 7 May 2024 04:58:58 +0800 Subject: [PATCH 092/147] Discovery Bid Adapter : get UTM tag data (#11380) * feat(isBidRequestValid): just filter token once. not filter publisher and tagid * feat(isBidRequestValid): add unit test * feat(spec): fix eslint * feat(spec): fix unit test * feat(spec): fix unit test * feat(ext): change default value * feat(utm): build UTMTag data * feat(spec): fix utm test * feat(utm): get UTMTag * feat(utm): add unit tests * feat(utm): fix unit tests * feat(utm): fix unit tests * feat(utm): fix unit tests --------- Co-authored-by: yubei01 --- modules/discoveryBidAdapter.js | 3 +- test/spec/modules/discoveryBidAdapter_spec.js | 53 +++++++------------ 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/modules/discoveryBidAdapter.js b/modules/discoveryBidAdapter.js index 7493dcb9af4..3ac905ef6b5 100644 --- a/modules/discoveryBidAdapter.js +++ b/modules/discoveryBidAdapter.js @@ -414,7 +414,7 @@ function getItems(validBidRequests, bidderRequest) { export const buildUTMTagData = (url) => { if (!storage.cookiesAreEnabled()) return; - const urlParams = utils.parseUrl(url).search; + const urlParams = utils.parseUrl(url).search || {}; const UTMParams = {}; Object.keys(urlParams).forEach(key => { if (/^utm_/.test(key)) { @@ -486,6 +486,7 @@ function getParam(validBidRequests, bidderRequest) { ssppid: storage.getCookie(COOKIE_KEY_SSPPID) || undefined, pmguid: getPmgUID(), tpData, + utm: storage.getCookie(UTM_KEY), page: { title: title ? title.slice(0, 100) : undefined, desc: desc ? desc.slice(0, 300) : undefined, diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js index d148d5062a4..42cc6ff68eb 100644 --- a/test/spec/modules/discoveryBidAdapter_spec.js +++ b/test/spec/modules/discoveryBidAdapter_spec.js @@ -15,6 +15,25 @@ import { import * as utils from 'src/utils.js'; describe('discovery:BidAdapterTests', function () { + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + sandbox.stub(storage, 'getCookie'); + sandbox.stub(storage, 'setCookie'); + sandbox.stub(utils, 'generateUUID').returns('new-uuid'); + sandbox.stub(utils, 'parseUrl').returns({ + search: { + utm_source: 'example.com' + } + }); + sandbox.stub(storage, 'cookiesAreEnabled'); + }) + + afterEach(() => { + sandbox.restore(); + }); + let bidRequestData = { bidderCode: 'discovery', auctionId: 'ff66e39e-4075-4d18-9854-56fde9b879ac', @@ -200,8 +219,8 @@ describe('discovery:BidAdapterTests', function () { }) ).to.equal(true); }); - it('discovery:validate_generated_params', function () { + storage.getCookie.withArgs('_ss_pp_utm').callsFake(() => '{"utm_source":"example.com","utm_medium":"123","utm_campaign":"456"}'); request = spec.buildRequests(bidRequestData.bids, bidRequestData); let req_data = JSON.parse(request.data); expect(req_data.imp).to.have.lengthOf(1); @@ -216,20 +235,6 @@ describe('discovery:BidAdapterTests', function () { describe('discovery: buildRequests', function() { describe('getPmgUID function', function() { - let sandbox; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - sandbox.stub(storage, 'getCookie'); - sandbox.stub(storage, 'setCookie'); - sandbox.stub(utils, 'generateUUID').returns('new-uuid'); - sandbox.stub(storage, 'cookiesAreEnabled'); - }) - - afterEach(() => { - sandbox.restore(); - }); - it('should generate new UUID and set cookie if not exists', () => { storage.cookiesAreEnabled.callsFake(() => true); storage.getCookie.callsFake(() => null); @@ -254,24 +259,6 @@ describe('discovery:BidAdapterTests', function () { }); }) describe('buildUTMTagData function', function() { - let sandbox; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - sandbox.stub(storage, 'getCookie'); - sandbox.stub(storage, 'setCookie'); - sandbox.stub(utils, 'parseUrl').returns({ - search: { - utm_source: 'example.com' - } - }); - sandbox.stub(storage, 'cookiesAreEnabled'); - }) - - afterEach(() => { - sandbox.restore(); - }); - it('should set UTM cookie', () => { storage.cookiesAreEnabled.callsFake(() => true); storage.getCookie.callsFake(() => null); From 3ccef438e439c962fa68675c7cace9101c6cf350 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 6 May 2024 17:08:21 -0400 Subject: [PATCH 093/147] README: note about build-bundle-dev (#11448) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 70e058d122b..f890f055104 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,16 @@ Or, if you are consuming Prebid through npm, with the `disableFeatures` option i **Note**: this is still a work in progress - at the moment, `NATIVE` is the only feature that can be disabled this way, resulting in a minimal decrease in size (but you can expect that to improve over time). +## Unminified code + +You can get a version of the code that's unminified for debugging with `build-bundle-dev`: + +```bash +gulp build-bundle-dev --modules=bidderA,module1,... +``` + +The results will be in build/dev/prebid.js. + ## Test locally To lint the code: From b6c25e18be3e70bc3e50eb47c3367483848b9f8a Mon Sep 17 00:00:00 2001 From: joseluis laso Date: Mon, 6 May 2024 14:41:16 -0700 Subject: [PATCH 094/147] adding the domain when calling home (#11440) --- modules/hadronIdSystem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hadronIdSystem.js b/modules/hadronIdSystem.js index 66cb5624a38..bdb8e634de6 100644 --- a/modules/hadronIdSystem.js +++ b/modules/hadronIdSystem.js @@ -115,7 +115,7 @@ export const hadronIdSubmodule = { // config.params.url and config.params.urlArg are not documented // since their use is for debugging purposes only paramOrDefault(config.params.url, DEFAULT_HADRON_URL_ENDPOINT, config.params.urlArg), - `partner_id=${partnerId}&_it=prebid&t=1&src=id` // src=id => the backend was called from getId + `partner_id=${partnerId}&_it=prebid&t=1&src=id&domain=${document.location.hostname}` // src=id => the backend was called from getId ); if (isDebug) { url += '&debug=1' From 93533276030e4748503a20b2028845a8d5fbf6fb Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 6 May 2024 18:44:14 -0400 Subject: [PATCH 095/147] Update PULL_REQUEST_TEMPLATE.md (#11449) Updating the notes: - new adapters are pointed to the docs rather than the repo - updated client-side adapters are asked to consider whether PBS adapter update is needed --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 09ef5c445f2..b225be162a8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,7 +16,8 @@ For any user facing change, submit a link to a PR on the docs repo at https://gi - [ ] Bugfix - [ ] Feature -- [ ] New bidder adapter +- [ ] New bidder adapter +- [ ] Updated bidder adapter - [ ] Code style update (formatting, local variables) - [ ] Refactoring (no functional changes, no api changes) - [ ] Build related changes From 14d2a0e844ed9f75ea8478011c0e3e886ea5eb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Millet?= Date: Tue, 7 May 2024 16:39:23 +0200 Subject: [PATCH 096/147] Dailymotion Bid Adapter: accept ortb2 field (#11366) * Dailymotion Bid Adaptor: initial release * .md file lint issue resolved * Dailymotion Bid Adaptor: build bidder request based on param with fallbacks * Dailymotion Bid Adaptor: support video metadata * Dailymotion Bid Adaptor: add support for sending adUnitCode * Dailymotion Bid Adaptor: add support for sending startDelay * feat(LEO-528): Allow multiple IAB categories in video metadata The same way as we can have an array of IAB categories level 1 in the ORTB request, this PR introduces an array for the IAB categories level 2. To be forward compatible with level [2.2](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.2.tsv) and [3.0](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%203.0.tsv) specifications, the category IDs should be sent as strings. * Dailymotion bid adapter: Clarify the video metadata to provide in each player context * Dailymotion bid adapter: Move API key to bid params * Dailymotion bid adapter: Verify API key is string Co-authored-by: Rumesh * Dailymotion bid adapter: Move API key to bid params (fix tests) * Dailymotion Bid Adaptor: add gpp support and get coppa from request * Dailymotion Bid Adaptor: fix lint error * Dailymotion Bid Adaptor: add iabcat1 and fallback to ortb2 for iabcat2 * Dailymotion Bid Adaptor: get iabcats from ortb2.site.content.data * Dailymotion Bid Adaptor: get content data from ortb2.site.content * Dailymotion Bid Adaptor: add support for iabcat1 in videoParams and document mapping of ortb2 fpd to video metadata * Dailymotion Bid Adaptor: add support for Object: App * Dailymotion Bid Adaptor: only support video adunits in context instream * Dailymotion bid adapter: Add standard ORTB video parameters Note: I changed the case of `startdelay` to be consistent with the other parameters, but it won't have any impact on current deployments as this parameter is not used onsite. * Dailymotion Bid Adaptor: add support for livestream and app * Dailymotion Bid Adaptor: drop support for non standard fields in mediaTypes.video * Dailymotion Bid Adaptor: update docs examples --------- Co-authored-by: Kevin Siow Co-authored-by: Aditi Chaudhary Co-authored-by: Kevin Siow Co-authored-by: Rumesh --- modules/dailymotionBidAdapter.js | 105 +++++--- modules/dailymotionBidAdapter.md | 83 ++++-- .../modules/dailymotionBidAdapter_spec.js | 255 +++++++++++++++--- 3 files changed, 354 insertions(+), 89 deletions(-) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index 2be5edad78e..afded538fd0 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -9,27 +9,33 @@ import { deepAccess } from '../src/utils.js'; * @return video metadata */ function getVideoMetadata(bidRequest, bidderRequest) { - const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video', {}); - const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + const videoParams = deepAccess(bidRequest, 'params.video', {}); - const videoParams = { - ...videoAdUnit, - ...videoBidderParams, // Bidder Specific overrides - }; + // As per oRTB 2.5 spec, "A bid request must not contain both an App and a Site object." + // See section 3.2.14 + // Content object is either from Object: Site or Object: App + const contentObj = deepAccess(bidderRequest, 'ortb2.site') + ? deepAccess(bidderRequest, 'ortb2.site.content') + : deepAccess(bidderRequest, 'ortb2.app.content'); - // Store as object keys to ensure uniqueness - const iabcat1 = {}; - const iabcat2 = {}; + const parsedContentData = { + // Store as object keys to ensure uniqueness + iabcat1: {}, + iabcat2: {}, + }; - deepAccess(bidderRequest, 'ortb2.site.content.data', []).forEach((data) => { + deepAccess(contentObj, 'data', []).forEach((data) => { if ([4, 5, 6, 7].includes(data?.ext?.segtax)) { (Array.isArray(data.segment) ? data.segment : []).forEach((segment) => { if (typeof segment.id === 'string') { // See https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy // Only take IAB cats of taxonomy V1 - if (data.ext.segtax === 4) iabcat1[segment.id] = 1; - // Only take IAB cats of taxonomy V2 or higher - if ([5, 6, 7].includes(data.ext.segtax)) iabcat2[segment.id] = 1; + if (data.ext.segtax === 4) { + parsedContentData.iabcat1[segment.id] = 1; + } else { + // Only take IAB cats of taxonomy V2 or higher + parsedContentData.iabcat2[segment.id] = 1; + } } }); } @@ -37,18 +43,25 @@ function getVideoMetadata(bidRequest, bidderRequest) { const videoMetadata = { description: videoParams.description || '', - duration: videoParams.duration || 0, - iabcat1: Object.keys(iabcat1), + duration: videoParams.duration || deepAccess(contentObj, 'len', 0), + iabcat1: Array.isArray(videoParams.iabcat1) + ? videoParams.iabcat1 + : Array.isArray(deepAccess(contentObj, 'cat')) + ? contentObj.cat + : Object.keys(parsedContentData.iabcat1), iabcat2: Array.isArray(videoParams.iabcat2) ? videoParams.iabcat2 - : Object.keys(iabcat2), - id: videoParams.id || '', - lang: videoParams.lang || '', + : Object.keys(parsedContentData.iabcat2), + id: videoParams.id || deepAccess(contentObj, 'id', ''), + lang: videoParams.lang || deepAccess(contentObj, 'language', ''), private: videoParams.private || false, - tags: videoParams.tags || '', - title: videoParams.title || '', + tags: videoParams.tags || deepAccess(contentObj, 'keywords', ''), + title: videoParams.title || deepAccess(contentObj, 'title', ''), topics: videoParams.topics || '', xid: videoParams.xid || '', + livestream: typeof videoParams.livestream === 'number' + ? !!videoParams.livestream + : !!deepAccess(contentObj, 'livestream', 0), }; return videoMetadata; @@ -67,7 +80,24 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return typeof bid?.params?.apiKey === 'string' && bid.params.apiKey.length > 10; + if (bid?.params) { + // We only accept video adUnits + if (!bid?.mediaTypes?.[VIDEO]) return false; + + // As `context`, `placement` & `plcmt` are optional (although recommended) + // values, we check the 3 of them to see if we are in an instream video context + const isInstream = bid.mediaTypes[VIDEO].context === 'instream' || + bid.mediaTypes[VIDEO].placement === 1 || + bid.mediaTypes[VIDEO].plcmt === 1; + + // We only accept instream video context + if (!isInstream) return false; + + // We need API key + return typeof bid.params.apiKey === 'string' && bid.params.apiKey.length > 10; + } + + return false; }, /** @@ -83,15 +113,15 @@ export const spec = { data: { bidder_request: { gdprConsent: { - apiVersion: bidderRequest?.gdprConsent?.apiVersion || 1, - consentString: bidderRequest?.gdprConsent?.consentString || '', + apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1), + consentString: deepAccess(bidderRequest, 'gdprConsent.consentString', ''), // Cast boolean in any case (eg: if value is int) to ensure type - gdprApplies: !!bidderRequest?.gdprConsent?.gdprApplies, + gdprApplies: !!deepAccess(bidderRequest, 'gdprConsent.gdprApplies'), }, refererInfo: { - page: bidderRequest?.refererInfo?.page || '', + page: deepAccess(bidderRequest, 'refererInfo.page', ''), }, - uspConsent: bidderRequest?.uspConsent || '', + uspConsent: deepAccess(bidderRequest, 'uspConsent', ''), gppConsent: { gppString: deepAccess(bidderRequest, 'gppConsent.gppString') || deepAccess(bidderRequest, 'ortb2.regs.gpp', ''), @@ -104,15 +134,28 @@ export const spec = { }, // Cast boolean in any case (value should be 0 or 1) to ensure type coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'), + // In app context, we need to retrieve additional informations + ...(!deepAccess(bidderRequest, 'ortb2.site') && !!deepAccess(bidderRequest, 'ortb2.app') ? { + appBundle: deepAccess(bidderRequest, 'ortb2.app.bundle', ''), + appStoreUrl: deepAccess(bidderRequest, 'ortb2.app.storeurl', ''), + } : {}), request: { - adUnitCode: bid.adUnitCode || '', - auctionId: bid.auctionId || '', - bidId: bid.bidId || '', + adUnitCode: deepAccess(bid, 'adUnitCode', ''), + auctionId: deepAccess(bid, 'auctionId', ''), + bidId: deepAccess(bid, 'bidId', ''), mediaTypes: { video: { - playerSize: bid.mediaTypes?.[VIDEO]?.playerSize || [], api: bid.mediaTypes?.[VIDEO]?.api || [], - startDelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, + mimes: bid.mediaTypes?.[VIDEO]?.mimes || [], + minduration: bid.mediaTypes?.[VIDEO]?.minduration || 0, + maxduration: bid.mediaTypes?.[VIDEO]?.maxduration || 0, + protocols: bid.mediaTypes?.[VIDEO]?.protocols || [], + skip: bid.mediaTypes?.[VIDEO]?.skip || 0, + skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0, + skipmin: bid.mediaTypes?.[VIDEO]?.skipmin || 0, + startdelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, + w: bid.mediaTypes?.[VIDEO]?.w || 0, + h: bid.mediaTypes?.[VIDEO]?.h || 0, }, }, sizes: bid.sizes || [], diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 795273c9229..7c871b0d536 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -9,10 +9,11 @@ Maintainer: ad-leo-engineering@dailymotion.com # Description Dailymotion prebid adapter. +Supports video ad units in instream context. # Configuration options -Before calling this adapter, you need to set at least the API key in the bid parameters: +Before calling this adapter, you need to at least set a video adUnit in an instream context and the API key in the bid parameters: ```javascript const adUnits = [ @@ -21,8 +22,14 @@ const adUnits = [ bidder: 'dailymotion', params: { apiKey: 'fake_api_key' - } - }] + }, + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + context: 'instream', + }, + }, } ]; ``` @@ -39,9 +46,15 @@ const adUnits = [ bids: [{ bidder: 'dailymotion', params: { - apiKey: 'dailymotion-testing' - } - }] + apiKey: 'dailymotion-testing', + }, + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + context: 'instream', + }, + }, } ]; ``` @@ -51,7 +64,7 @@ Please note that failing to set these will result in the adapter not bidding at # Sample video AdUnit To allow better targeting, you should provide as much context about the video as possible. -There are two ways of doing this depending on if you're using Dailymotion player or a third party one. +There are three ways of doing this depending on if you're using Dailymotion player or a third party one. If you are using the Dailymotion player, you should only provide the video `xid` in your ad unit, example: @@ -61,7 +74,10 @@ const adUnits = [ bids: [{ bidder: 'dailymotion', params: { - apiKey: 'dailymotion-testing' + apiKey: 'dailymotion-testing', + video: { + xid: 'x123456' // Dailymotion infrastructure unique video ID + }, } }], code: 'test-ad-unit', @@ -69,9 +85,9 @@ const adUnits = [ video: { api: [2, 7], context: 'instream', - playerSize: [ [1280, 720] ], - startDelay: 0, - xid: 'x123456' // Dailymotion infrastructure unique video ID + startdelay: 0, + w: 1280, + h: 720, }, } } @@ -91,7 +107,17 @@ const adUnits = [ params: { apiKey: 'dailymotion-testing', video: { - description: 'overriden video description' + description: 'this is a video description', + duration: 556, + iabcat1: ['IAB-2'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + livestream: 0, + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', } } }], @@ -100,37 +126,42 @@ const adUnits = [ video: { api: [2, 7], context: 'instream', - description: 'this is a video description', - duration: 556, - iabcat2: ['6', '17'], - id: '54321', - lang: 'FR', - playerSize: [ [1280, 720] ], - private: false, - startDelay: 0, - tags: 'tag_1,tag_2,tag_3', - title: 'test video', - topics: 'topic_1, topic_2', + startdelay: 0, + w: 1280, + h: 720, }, } } ]; ``` -Each of the following video metadata fields can be added in mediaTypes.video or bids.params.video. -If a field exists in both places, it will be overridden by bids.params.video. +Each of the following video metadata fields can be added in bids.params.video. * `description` - Video description * `duration` - Video duration in seconds -* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) +* `iabcat1` - List of IAB category IDs from the [1.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%201.0.tsv) +* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) and above * `id` - Video unique ID in host video infrastructure * `lang` - ISO 639-1 code for main language used in the video +* `livestream` - 0 = not live, 1 = content is live * `private` - True if video is not publicly available * `tags` - Tags for the video, comma separated * `title` - Video title * `topics` - Main topics for the video, comma separated * `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player) +If you already specify [First-Party data](https://docs.prebid.org/features/firstPartyData.html) through the `ortb2` object when calling [`pbjs.requestBids(requestObj)`](https://docs.prebid.org/dev-docs/publisher-api-reference/requestBids.html), we will fallback to those values when possible. See the mapping below. + +| From ortb2 | Metadata fields | +|---------------------------------------------------------------------------------|-----------------| +| `ortb2.site.content.cat` OR `ortb2.site.content.data` where `ext.segtax` is `4` | `iabcat1` | +| `ortb2.site.content.data` where `ext.segtax` is `5`, `6` or `7` | `iabcat2` | +| `ortb2.site.content.id` | `id` | +| `ortb2.site.content.language` | `lang` | +| `ortb2.site.content.livestream` | `livestream` | +| `ortb2.site.content.keywords` | `tags` | +| `ortb2.site.content.title` | `title` | + # Integrating the adapter To use the adapter with any non-test request, you first need to ask an API key from Dailymotion. Please contact us through **DailymotionPrebid.js@dailymotion.com**. diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index a102c26dca2..fe9484b2814 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -1,7 +1,7 @@ import { config } from 'src/config.js'; import { expect } from 'chai'; import { spec } from 'modules/dailymotionBidAdapter.js'; -import { VIDEO } from '../../../src/mediaTypes'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; describe('dailymotionBidAdapterTests', () => { // Validate that isBidRequestValid only validates requests with apiKey @@ -12,6 +12,11 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: '', }, + mediaTypes: { + [VIDEO]: { + context: 'instream', + }, + }, }; expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyApi))).to.be.false; @@ -20,9 +25,57 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: 'test_api_key', }, + mediaTypes: { + [VIDEO]: { + context: 'instream', + }, + }, }; expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithApi))).to.be.true; + + const bidWithEmptyMediaTypes = { + params: { + apiKey: '', + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyMediaTypes))).to.be.false; + + const bidWithEmptyVideoAdUnit = { + params: { + apiKey: '', + }, + mediaTypes: { + [VIDEO]: {}, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyVideoAdUnit))).to.be.false; + + const bidWithBannerMediaType = { + params: { + apiKey: 'test_api_key', + }, + mediaTypes: { + [BANNER]: {}, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithBannerMediaType))).to.be.false; + + const bidWithOutstreamContext = { + params: { + apiKey: 'test_api_key', + }, + mediaTypes: { + video: { + context: 'outstream', + }, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithOutstreamContext))).to.be.false; }); // Validate request generation @@ -33,20 +86,27 @@ describe('dailymotionBidAdapterTests', () => { adUnitCode: 'preroll', mediaTypes: { video: { - playerSize: [[1280, 720]], api: [2, 7], - description: 'this is a test video', - duration: 300, - iabcat2: ['6', '17'], - lang: 'ENG', + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, startdelay: 0, + w: 1280, + h: 720 }, }, sizes: [[1920, 1080]], params: { apiKey: 'test_api_key', video: { + description: 'this is a test video', duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], id: '54321', lang: 'FR', private: false, @@ -54,6 +114,7 @@ describe('dailymotionBidAdapterTests', () => { title: 'test video', topics: 'topic_1, topic_2', xid: 'x123456', + livestream: 1, }, }, }]; @@ -78,6 +139,117 @@ describe('dailymotionBidAdapterTests', () => { }, site: { content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + const { data: reqData } = request; + + expect(request.url).to.equal('https://pb.dmxleo.com'); + + expect(reqData.bidder_request).to.eql({ + refererInfo: bidderRequestData.refererInfo, + uspConsent: bidderRequestData.uspConsent, + gdprConsent: bidderRequestData.gdprConsent, + gppConsent: bidderRequestData.gppConsent, + }); + expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); + expect(reqData.coppa).to.be.true; + expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); + expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); + expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); + expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.video_metadata).to.eql({ + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-1'], + iabcat2: bidRequestData[0].params.video.iabcat2, + id: bidRequestData[0].params.video.id, + lang: bidRequestData[0].params.video.lang, + private: bidRequestData[0].params.video.private, + tags: bidRequestData[0].params.video.tags, + title: bidRequestData[0].params.video.title, + topics: bidRequestData[0].params.video.topics, + xid: bidRequestData[0].params.video.xid, + duration: bidRequestData[0].params.video.duration, + livestream: !!bidRequestData[0].params.video.livestream, + }); + }); + + it('validates buildRequests with content values from App', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + app: { + bundle: 'app-bundle', + storeurl: 'https://play.google.com/store/apps/details?id=app-bundle', + content: { + len: 556, data: [ { name: 'dataprovider.com', @@ -112,15 +284,25 @@ describe('dailymotionBidAdapterTests', () => { }); expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); expect(reqData.coppa).to.be.true; + expect(reqData.appBundle).to.eql(bidderRequestData.ortb2.app.bundle); + expect(reqData.appStoreUrl).to.eql(bidderRequestData.ortb2.app.storeurl); expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); - expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.mimes).to.eql(bidRequestData[0].mediaTypes.video.mimes); + expect(reqData.request.mediaTypes.video.minduration).to.eql(bidRequestData[0].mediaTypes.video.minduration); + expect(reqData.request.mediaTypes.video.maxduration).to.eql(bidRequestData[0].mediaTypes.video.maxduration); + expect(reqData.request.mediaTypes.video.protocols).to.eql(bidRequestData[0].mediaTypes.video.protocols); + expect(reqData.request.mediaTypes.video.skip).to.eql(bidRequestData[0].mediaTypes.video.skip); + expect(reqData.request.mediaTypes.video.skipafter).to.eql(bidRequestData[0].mediaTypes.video.skipafter); + expect(reqData.request.mediaTypes.video.skipmin).to.eql(bidRequestData[0].mediaTypes.video.skipmin); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.w).to.eql(bidRequestData[0].mediaTypes.video.w); + expect(reqData.request.mediaTypes.video.h).to.eql(bidRequestData[0].mediaTypes.video.h); expect(reqData.video_metadata).to.eql({ - description: bidRequestData[0].mediaTypes.video.description, - iabcat1: ['IAB-1'], // Taxonomy v2 or higher is excluded - iabcat2: bidRequestData[0].mediaTypes.video.iabcat2, + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-1'], + iabcat2: bidRequestData[0].params.video.iabcat2, id: bidRequestData[0].params.video.id, lang: bidRequestData[0].params.video.lang, private: bidRequestData[0].params.video.private, @@ -129,22 +311,19 @@ describe('dailymotionBidAdapterTests', () => { topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, // Overriden through bidder params - duration: bidRequestData[0].params.video.duration, + duration: bidderRequestData.ortb2.app.content.len, + livestream: !!bidRequestData[0].params.video.livestream, }); }); - it('validates buildRequests with fallback values on ortb2 for gpp & iabcat', () => { + it('validates buildRequests with fallback values on ortb2 (gpp, iabcat2, id...)', () => { const bidRequestData = [{ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', bidId: 123456, adUnitCode: 'preroll', mediaTypes: { video: { - playerSize: [[1280, 720]], api: [2, 7], - description: 'this is a test video', - duration: 300, - lang: 'ENG', startdelay: 0, }, }, @@ -152,11 +331,9 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: 'test_api_key', video: { + description: 'this is a test video', duration: 556, - id: '54321', - lang: 'FR', private: false, - tags: 'tag_1,tag_2,tag_3', title: 'test video', topics: 'topic_1, topic_2', xid: 'x123456', @@ -182,6 +359,12 @@ describe('dailymotionBidAdapterTests', () => { }, site: { content: { + id: '54321', + language: 'FR', + keywords: 'tag_1,tag_2,tag_3', + title: 'test video', + livestream: 1, + cat: ['IAB-2'], data: [ undefined, // Undefined to check proper handling of edge cases {}, // Empty object to check proper handling of edge cases @@ -203,7 +386,7 @@ describe('dailymotionBidAdapterTests', () => { }, { name: 'dataprovider.com', - ext: { segtax: 4 }, + ext: { segtax: 5 }, segment: [{ id: 2222 }], // Invalid segment id to check proper handling of edge cases }, { @@ -251,21 +434,20 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); expect(reqData.video_metadata).to.eql({ - description: bidRequestData[0].mediaTypes.video.description, - // No iabcat1 here because nothing matches taxonomy - iabcat1: [], + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-2'], iabcat2: ['6', '17', '20'], - id: bidRequestData[0].params.video.id, - lang: bidRequestData[0].params.video.lang, + id: bidderRequestData.ortb2.site.content.id, + lang: bidderRequestData.ortb2.site.content.language, private: bidRequestData[0].params.video.private, - tags: bidRequestData[0].params.video.tags, - title: bidRequestData[0].params.video.title, + tags: bidderRequestData.ortb2.site.content.keywords, + title: bidderRequestData.ortb2.site.content.title, topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, - // Overriden through bidder params duration: bidRequestData[0].params.video.duration, + livestream: !!bidderRequestData.ortb2.site.content.livestream, }); }); @@ -310,9 +492,17 @@ describe('dailymotionBidAdapterTests', () => { adUnitCode: '', mediaTypes: { video: { - playerSize: [], - startDelay: 0, api: [], + mimes: [], + minduration: 0, + maxduration: 0, + protocols: [], + skip: 0, + skipafter: 0, + skipmin: 0, + startdelay: 0, + w: 0, + h: 0, }, }, sizes: [], @@ -330,6 +520,7 @@ describe('dailymotionBidAdapterTests', () => { title: '', topics: '', xid: '', + livestream: false, }); }); From 685d72c50472b3e99dbe33c809b3d14fa8ec97ee Mon Sep 17 00:00:00 2001 From: Irakli Gotsiridze Date: Tue, 7 May 2024 18:41:12 +0400 Subject: [PATCH 097/147] enhance fledge (#11455) --- modules/sovrnBidAdapter.js | 38 ++++++- test/spec/modules/sovrnBidAdapter_spec.js | 132 +++++++++++++++++----- 2 files changed, 139 insertions(+), 31 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 3df025b1619..b6563cac4c5 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -6,7 +6,7 @@ import { logError, deepAccess, isInteger, - logWarn, getBidIdParameter + logWarn, getBidIdParameter, isEmptyStr } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js' import { @@ -254,16 +254,38 @@ export const spec = { })) .flat() - let fledgeAuctionConfigs = deepAccess(ext, 'fledge_auction_configs'); + let fledgeAuctionConfigs = null; + if (isArray(ext?.igbid)) { + const seller = ext.seller + const decisionLogicUrl = ext.decisionLogicUrl + const sellerTimeout = ext.sellerTimeout + ext.igbid.filter(item => isValidIgBid(item)).forEach((igbid) => { + const perBuyerSignals = {} + igbid.igbuyer.filter(item => isValidIgBuyer(item)).forEach(buyerItem => { + perBuyerSignals[buyerItem.igdomain] = buyerItem.buyerdata + }) + const interestGroupBuyers = [...Object.keys(perBuyerSignals)] + if (interestGroupBuyers.length) { + fledgeAuctionConfigs = fledgeAuctionConfigs || {} + fledgeAuctionConfigs[igbid.impid] = { + seller, + decisionLogicUrl, + sellerTimeout, + interestGroupBuyers: interestGroupBuyers, + perBuyerSignals, + } + } + }) + } if (fledgeAuctionConfigs) { fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => { return { bidId, config: Object.assign({ - auctionSignals: {}, + auctionSignals: {} }, cfg) } - }); + }) return { bids, fledgeAuctionConfigs, @@ -367,4 +389,12 @@ function _getBidFloors(bid) { return !isNaN(paramValue) ? paramValue : undefined } +function isValidIgBid(igBid) { + return !isEmptyStr(igBid.impid) && isArray(igBid.igbuyer) && igBid.igbuyer.length +} + +function isValidIgBuyer(igBuyer) { + return !isEmptyStr(igBuyer.igdomain) +} + registerBidder(spec) diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 9c7f433ef96..10f5ab8e89d 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -844,26 +844,56 @@ describe('sovrnBidAdapter', function() { }] }], ext: { - fledge_auction_configs: { - 'test_bid_id': { - seller: 'ap.lijit.com', - interestGroupBuyers: ['dsp1.com'], - sellerTimeout: 0, - perBuyerSignals: { - 'dsp1.com': { - bid_macros: 0.1, - disallowed_adv_ids: [ - '8765', - '4321' - ], - } + seller: 'seller.lijit.com', + decisionLogicUrl: 'https://decision.lijit.com', + igbid: [{ + impid: 'test_imp_id', + igbuyer: [{ + igdomain: 'ap.lijit.com', + buyerdata: { + base_bid_micros: 0.1, + use_bid_multiplier: true, + multiplier: '1.3' } - } - } + }, { + igdomain: 'buyer2.com', + buyerdata: {} + }, { + igdomain: 'buyer3.com', + buyerdata: {} + }] + }, { + impid: 'test_imp_id_2', + igbuyer: [{ + igdomain: 'ap2.lijit.com', + buyerdata: { + base_bid_micros: '0.2', + } + }] + }, { + impid: '', + igbuyer: [{ + igdomain: 'ap3.lijit.com', + buyerdata: { + base_bid_micros: '0.3', + } + }] + }, { + impid: 'test_imp_id_3', + igbuyer: [{ + igdomain: '', + buyerdata: { + base_bid_micros: '0.3', + } + }] + }, { + impid: 'test_imp_id_4', + igbuyer: [] + }] } } } - let invalidFledgeResponse = { + let emptyFledgeResponse = { body: { id: '37386aade21a71', seatbid: [{ @@ -879,25 +909,73 @@ describe('sovrnBidAdapter', function() { }] }], ext: { - fledge_auction_configs: { + igbid: { } } } } - it('should return fledge auction configs alongside bids', function () { + let expectedResponse = { + requestId: '263c448586f5a1', + cpm: 0.45882675, + width: 728, + height: 90, + creativeId: 'creativelycreatedcreativecreative', + dealId: null, + currency: 'USD', + netRevenue: true, + mediaType: 'banner', + ttl: 60000, + meta: { advertiserDomains: [] }, + ad: decodeURIComponent(`>`) + } + let expectedFledgeResponse = [ + { + bidId: 'test_imp_id', + config: { + seller: 'seller.lijit.com', + decisionLogicUrl: 'https://decision.lijit.com', + sellerTimeout: undefined, + auctionSignals: {}, + interestGroupBuyers: ['ap.lijit.com', 'buyer2.com', 'buyer3.com'], + perBuyerSignals: { + 'ap.lijit.com': { + base_bid_micros: 0.1, + use_bid_multiplier: true, + multiplier: '1.3' + }, + 'buyer2.com': {}, + 'buyer3.com': {} + } + } + }, + { + bidId: 'test_imp_id_2', + config: { + seller: 'seller.lijit.com', + decisionLogicUrl: 'https://decision.lijit.com', + sellerTimeout: undefined, + auctionSignals: {}, + interestGroupBuyers: ['ap2.lijit.com'], + perBuyerSignals: { + 'ap2.lijit.com': { + base_bid_micros: '0.2', + } + } + } + } + ] + + it('should return valid fledge auction configs alongside bids', function () { const result = spec.interpretResponse(fledgeResponse) expect(result).to.have.property('bids') expect(result).to.have.property('fledgeAuctionConfigs') - expect(result.fledgeAuctionConfigs.length).to.equal(1) - expect(result.fledgeAuctionConfigs[0].bidId).to.equal('test_bid_id') - expect(result.fledgeAuctionConfigs[0].config).to.not.be.undefined - expect(result.fledgeAuctionConfigs[0].config).to.contain.keys('seller', 'interestGroupBuyers', 'sellerTimeout', 'perBuyerSignals') + expect(result.fledgeAuctionConfigs.length).to.equal(2) + expect(result.fledgeAuctionConfigs).to.deep.equal(expectedFledgeResponse) }) - it('should ignore invalid fledge auction configs', function () { - const result = spec.interpretResponse(invalidFledgeResponse) - expect(result).to.have.property('bids') - expect(result).to.have.property('fledgeAuctionConfigs') - expect(result.fledgeAuctionConfigs.length).to.equal(0) + it('should ignore empty fledge auction configs array', function () { + const result = spec.interpretResponse(emptyFledgeResponse) + expect(result.length).to.equal(1) + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse)) }) }) From 80f627d33c164e680fa78b37dfe4395cacfea3b0 Mon Sep 17 00:00:00 2001 From: ecdrsvc <82906140+ecdrsvc@users.noreply.github.com> Date: Tue, 7 May 2024 10:46:29 -0400 Subject: [PATCH 098/147] Mabidder Bid Adapter : use ortbConverter facility to pass ortb2 (#11447) * Add lmpIdSystem userId submodule * Use ortbConverter facility in mabidder --------- Co-authored-by: Antoine Niek --- modules/mabidderBidAdapter.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/mabidderBidAdapter.js b/modules/mabidderBidAdapter.js index 632403c6643..8d97f48f604 100644 --- a/modules/mabidderBidAdapter.js +++ b/modules/mabidderBidAdapter.js @@ -1,9 +1,12 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; -import {getGlobal} from '../src/prebidGlobal.js'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; const BIDDER_CODE = 'mabidder'; export const baseUrl = 'https://prebid.ecdrsvc.com/bid'; +const converter = ortbConverter({}) + export const spec = { supportedMediaTypes: [BANNER], code: BIDDER_CODE, @@ -14,7 +17,8 @@ export const spec = { return !!(bid.params.ppid && bid.sizes && Array.isArray(bid.sizes) && Array.isArray(bid.sizes[0])) }, buildRequests: function(validBidRequests, bidderRequest) { - const fpd = bidderRequest.ortb2; + const fpd = converter.toORTB({ bidRequests: validBidRequests, bidderRequest: bidderRequest }); + const bids = []; validBidRequests.forEach(bidRequest => { const sizes = []; From 8ebc22d462fe40f51ab2c5e5cfb0231ed6c9807e Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 7 May 2024 10:47:22 -0400 Subject: [PATCH 099/147] Update sharethroughBidAdapter.js (#11451) * Update the logic to determine how `gpid` is applied to a bid request. --- modules/sharethroughBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index 2264bc37ebb..590fddca079 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -103,7 +103,7 @@ export const sharethroughAdapterSpec = { // mergeDeep(impression, bidReq.ortb2Imp); // leaving this out for now as we may want to leave stuff out on purpose const tid = deepAccess(bidReq, 'ortb2Imp.ext.tid'); if (tid) impression.ext.tid = tid; - const gpid = deepAccess(bidReq, 'ortb2Imp.ext.gpid', deepAccess(bidReq, 'ortb2Imp.ext.data.pbadslot')); + const gpid = deepAccess(bidReq, 'ortb2Imp.ext.gpid') || deepAccess(bidReq, 'ortb2Imp.ext.data.pbadslot'); if (gpid) impression.ext.gpid = gpid; const videoRequest = deepAccess(bidReq, 'mediaTypes.video'); From ff458c5d1feac0df3a2f654406bb9ee1bb1fee80 Mon Sep 17 00:00:00 2001 From: Taro FURUKAWA <6879289+0tarof@users.noreply.github.com> Date: Tue, 7 May 2024 23:49:21 +0900 Subject: [PATCH 100/147] remove format guard (#11452) --- modules/ajaBidAdapter.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/ajaBidAdapter.js b/modules/ajaBidAdapter.js index e02ab920707..699dfd6fa04 100644 --- a/modules/ajaBidAdapter.js +++ b/modules/ajaBidAdapter.js @@ -55,11 +55,6 @@ export const spec = { for (let i = 0, len = validBidRequests.length; i < len; i++) { const bidRequest = validBidRequests[i]; - if ( - (bidRequest.mediaTypes?.native || bidRequest.mediaTypes?.video) && - bidRequest.mediaTypes?.banner) { - continue - } let queryString = ''; From 10830eed32b5412c20839a9b8e4931b430ddd69d Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 7 May 2024 11:13:24 -0700 Subject: [PATCH 101/147] EXADS bid adapter: replace broken logic with merely bad logic (#11456) --- modules/exadsBidAdapter.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/exadsBidAdapter.js b/modules/exadsBidAdapter.js index 31d75db470d..20ead7a7e6b 100644 --- a/modules/exadsBidAdapter.js +++ b/modules/exadsBidAdapter.js @@ -319,24 +319,25 @@ function getEnvParams() { language: '' }; + // TODO: all of this is already in first party data envParams.domain = window.location.hostname; envParams.page = window.location.protocol + '//' + window.location.host + window.location.pathname; envParams.lang = navigator.language.indexOf('-') > -1 ? navigator.language.split('-')[0] : navigator.language; envParams.userAgent = navigator.userAgent; - if (envParams.userAgent.match(/Windows/i)) { envParams.osName = 'Windows'; } else if (envParams.userAgent.match(/Mac OS|Macintosh/i)) { envParams.osName = 'MacOS'; } else if (envParams.userAgent.match(/Unix/i)) { envParams.osName = 'Unix'; - } else if (envParams.userAgent.userAgent.match(/Android/i)) { + // TODO: what is userAgent.userAgent supposed to be? + } else if (envParams.userAgent.userAgent?.match(/Android/i)) { envParams.osName = 'Android'; - } else if (envParams.userAgent.userAgent.match(/iPhone|iPad|iPod/i)) { + } else if (envParams.userAgent.userAgent?.match(/iPhone|iPad|iPod/i)) { envParams.osName = 'iOS'; - } else if (envParams.userAgent.userAgent.match(/Linux/i)) { + } else if (envParams.userAgent.userAgent?.match(/Linux/i)) { envParams.osName = 'Linux'; } else { envParams.osName = 'Unknown'; From 4a4ada816117cc8c085ca3966af12121283ac68e Mon Sep 17 00:00:00 2001 From: JonGoSonobi Date: Tue, 7 May 2024 14:59:29 -0400 Subject: [PATCH 102/147] look for gpid in the ortb2Imp.ext.gpid (#11460) --- modules/sonobiBidAdapter.js | 2 +- test/spec/modules/sonobiBidAdapter_spec.js | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index e1b51affd09..edc4f255d18 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -329,7 +329,7 @@ function _validateFloor(bid) { } function _validateGPID(bid) { - const gpid = deepAccess(bid, 'ortb2Imp.ext.data.pbadslot') || deepAccess(getGptSlotInfoForAdUnitCode(bid.adUnitCode), 'gptSlot') || bid.params.ad_unit; + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid') || deepAccess(bid, 'ortb2Imp.ext.data.pbadslot') || deepAccess(getGptSlotInfoForAdUnitCode(bid.adUnitCode), 'gptSlot') || bid.params.ad_unit; if (gpid) { return `gpid=${gpid},` diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index c7f954cfdcf..75da1983f0c 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -302,6 +302,29 @@ describe('SonobiBidAdapter', function () { } } }, + { + + 'bidder': 'sonobi', + 'params': { + 'keywords': 'sports,news,some_other_keyword', + 'placement_id': '1a2b3c4d5e6f1a2b3c4d', + 'sizes': [[300, 250], [300, 600]], + 'floor': '1.25', + }, + 'adUnitCode': 'adunit-code-42', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1g', + ortb2Imp: { + ext: { + gpid: '/123123/gpt_publisher/adunit-code-42' + } + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + } + }, { 'bidder': 'sonobi', 'params': { @@ -343,6 +366,7 @@ describe('SonobiBidAdapter', function () { let keyMakerData = { '30b31c1838de1f': '1a2b3c4d5e6f1a2b3c4d|640x480|f=1.25,gpid=/123123/gpt_publisher/adunit-code-1,c=v,pm=1:2:3,p=2,pl=3,', + '30b31c1838de1g': '1a2b3c4d5e6f1a2b3c4d|300x250,300x600|f=1.25,gpid=/123123/gpt_publisher/adunit-code-42,c=d,', '30b31c1838de1d': '1a2b3c4d5e6f1a2b3c4e|300x250,300x600|f=0.42,gpid=/123123/gpt_publisher/adunit-code-3,c=d,', '/7780971/sparks_prebid_LB|30b31c1838de1e': '300x250,300x600|gpid=/7780971/sparks_prebid_LB,c=d,', }; From eb5ae983c8bc958f27b6ca6d353a245aa6796cbb Mon Sep 17 00:00:00 2001 From: lukashakl <107847079+lukashakl@users.noreply.github.com> Date: Tue, 7 May 2024 21:01:03 +0200 Subject: [PATCH 103/147] Performax Bid Adapter: New bidder adapter (#11325) --- modules/performaxBidAdapter.js | 77 ++++++++ modules/performaxBidAdapter.md | 36 ++++ test/spec/modules/performaxBidAdapter_spec.js | 175 ++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 modules/performaxBidAdapter.js create mode 100644 modules/performaxBidAdapter.md create mode 100644 test/spec/modules/performaxBidAdapter_spec.js diff --git a/modules/performaxBidAdapter.js b/modules/performaxBidAdapter.js new file mode 100644 index 00000000000..a765c4d9d78 --- /dev/null +++ b/modules/performaxBidAdapter.js @@ -0,0 +1,77 @@ +import { deepSetValue, deepAccess } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js' +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; + +const BIDDER_CODE = 'performax'; +const BIDDER_SHORT_CODE = 'px'; +const GVLID = 732 +const ENDPOINT = 'https://dale.performax.cz/ortb' +export const converter = ortbConverter({ + + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + deepSetValue(imp, 'tagid', bidRequest.params.tagid); + return imp; + }, + + bidResponse(buildBidResponse, bid, context) { + context.netRevenue = deepAccess(bid, 'netRevenue'); + context.mediaType = deepAccess(bid, 'mediaType'); + context.currency = deepAccess(bid, 'currency'); + + return buildBidResponse(bid, context) + }, + + context: { + ttl: 360, + } +}) + +export const spec = { + code: BIDDER_CODE, + aliases: [BIDDER_SHORT_CODE], + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + isBidRequestValid: function (bid) { + return !!bid.params.tagid; + }, + + buildRequests: function (bidRequests, bidderRequest) { + let data = converter.toORTB({bidderRequest, bidRequests}) + return [{ + method: 'POST', + url: ENDPOINT, + options: {'contentType': 'application/json'}, + data: data + }] + }, + + interpretResponse: function (bidderResponse, request) { + if (!bidderResponse.body) return []; + const response = bidderResponse.body + const data = { + + seatbid: response.seatbid.map(seatbid => ({ + seat: seatbid.seat, + bid: seatbid.bid.map(bid => ({ + impid: bid.imp_id, + w: bid.w, + h: bid.h, + requestId: request.data.id, + price: bid.price, + currency: response.cur, + adm: bid.adm, + crid: bid.id, + netRevenue: true, + mediaType: BANNER, + })) + })) + }; + return converter.fromORTB({ response: data, request: request.data }).bids + }, + +} + +registerBidder(spec); diff --git a/modules/performaxBidAdapter.md b/modules/performaxBidAdapter.md new file mode 100644 index 00000000000..8b5b702a8e6 --- /dev/null +++ b/modules/performaxBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Performax Bid Adapter +Module Type: Bidder Adapter +Maintainer: development@performax.cz +``` + +# Description + +Connects to Performax exchange for bids. + +Performax bid adapter supports Banner. + + +# Sample Banner Ad Unit: For Publishers + +```javascript + var adUnits = [ + { + code: 'performax-div', + mediaTypes: { + banner: {sizes: [[300, 300]]}, + }, + bids: [ + { + bidder: "performax", + params: { + tagid: "sample" // required + } + } + ] + }, + ]; +``` + diff --git a/test/spec/modules/performaxBidAdapter_spec.js b/test/spec/modules/performaxBidAdapter_spec.js new file mode 100644 index 00000000000..49a6a83e29d --- /dev/null +++ b/test/spec/modules/performaxBidAdapter_spec.js @@ -0,0 +1,175 @@ +import { expect } from 'chai'; +import { spec, converter } from 'modules/performaxBidAdapter.js'; + +describe('Performax adapter', function () { + let bids = [{ + bidder: 'performax', + params: { + tagid: 'sample' + }, + ortb2Imp: { + ext: {} + }, + mediaTypes: { + banner: { + sizes: [ + [300, 300], + ]}}, + adUnitCode: 'postbid_iframe', + transactionId: '84deda92-e9ba-4b0d-a797-43be5e522430', + adUnitId: '4ee4643b-931f-4a17-a571-ccba57886dc8', + sizes: [ + [300, 300], + ], + bidId: '2bc545c347dbbe', + bidderRequestId: '1534dec005b9a', + auctionId: 'acd97e55-01e1-45ad-813c-67fa27fc5c1b', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + ortb2: { + source: {}, + site: {}, + device: {} + }, + }, + + { + bidder: 'performax', + params: { + tagid: '1545' + }, + ortb2Imp: { + ext: {} + }, + mediaTypes: { + banner: { + sizes: [ + [300, 600], + ]}}, + adUnitCode: 'postbid_halfpage_iframe', + transactionId: '84deda92-e9ba-4b0d-a797-43be5e522430', + adUnitId: '4ee4643b-931f-4a17-a571-ccba57886dc8', + sizes: [ + [300, 600], + ], + bidId: '3dd53d30c691fe', + bidderRequestId: '1534dec005b9a', + auctionId: 'acd97e55-01e1-45ad-813c-67fa27fc5c1b', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + ortb2: { + source: {}, + site: {}, + device: {} + }}]; + + let bidderRequest = { + bidderCode: 'performax2', + auctionId: 'acd97e55-01e1-45ad-813c-67fa27fc5c1b', + id: 'acd97e55-01e1-45ad-813c-67fa27fc5c1b', + bidderRequestId: '1534dec005b9a', + bids: bids, + ortb2: { + regs: { + ext: { + gdpr: 1 + }}, + user: { + ext: { + consent: 'consent-string' + } + }, + site: {}, + device: {} + }}; + + let serverResponse = { + body: { + cur: 'CZK', + seatbid: [ + { + seat: 'performax', + bid: [ + { + id: 'sample', + price: 20, + w: 300, + h: 300, + adm: 'My ad' + } + ]}]}, + } + + describe('isBidRequestValid', function () { + let bid = {}; + it('should return false when missing "tagid" param', function() { + bid.params = {slotId: 'param'}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return true when tagid is correct', function() { + bid.params = {tagid: 'sample'}; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + }) + + describe('buildRequests', function () { + it('should set correct request method and url', function () { + let requests = spec.buildRequests([bids[0]], bidderRequest); + expect(requests).to.be.an('array').that.has.lengthOf(1); + let request = requests[0]; + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('https://dale.performax.cz/ortb'); + expect(request.data).to.be.an('object'); + }); + + it('should pass correct imp', function () { + let requests = spec.buildRequests([bids[0]], bidderRequest); + let {data} = requests[0]; + let {imp} = data; + expect(imp).to.be.an('array').that.has.lengthOf(1); + expect(imp[0]).to.be.an('object'); + let bid = imp[0]; + expect(bid.id).to.equal('2bc545c347dbbe'); + expect(bid.banner).to.deep.equal({topframe: 0, format: [{w: 300, h: 300}]}); + }); + + it('should process multiple bids', function () { + let requests = spec.buildRequests(bids, bidderRequest); + expect(requests).to.be.an('array').that.has.lengthOf(1); + let {data} = requests[0]; + let {imp} = data; + expect(imp).to.be.an('array').that.has.lengthOf(bids.length); + let bid1 = imp[0]; + expect(bid1.banner).to.deep.equal({topframe: 0, format: [{w: 300, h: 300}]}); + let bid2 = imp[1]; + expect(bid2.banner).to.deep.equal({topframe: 0, format: [{w: 300, h: 600}]}); + }); + }); + + describe('interpretResponse', function () { + it('should map params correctly', function () { + let ortbRequest = {data: converter.toORTB({bidderRequest, bids})}; + serverResponse.body.id = ortbRequest.data.id; + serverResponse.body.seatbid[0].bid[0].imp_id = ortbRequest.data.imp[0].id; + + let result = spec.interpretResponse(serverResponse, ortbRequest); + expect(result).to.be.an('array').that.has.lengthOf(1); + let bid = result[0]; + + expect(bid.cpm).to.equal(20); + expect(bid.ad).to.equal('My ad'); + expect(bid.currency).to.equal('CZK'); + expect(bid.mediaType).to.equal('banner'); + expect(bid.netRevenue).to.equal(true); + expect(bid.ttl).to.equal(360); + expect(bid.creativeId).to.equal('sample'); + }); + }); +}); From 0b574b3adfaecf756ccb7233229541e74241f3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bo=C5=BEidar=20Bare=C5=A1i=C4=87?= <153560835+bbaresic@users.noreply.github.com> Date: Tue, 7 May 2024 15:20:27 -0500 Subject: [PATCH 104/147] faster-deep-clone (#11418) --- allowedModules.js | 2 +- modules/browsiRtdProvider.js | 2 +- package-lock.json | 25 ++++++++++++++----------- package.json | 2 +- src/utils.js | 4 ++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/allowedModules.js b/allowedModules.js index 75ad4141a6c..bc9ada39571 100644 --- a/allowedModules.js +++ b/allowedModules.js @@ -7,7 +7,7 @@ module.exports = { ], 'src': [ 'fun-hooks/no-eval', - 'just-clone', + 'klona', 'dlv', 'dset' ], diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index ad4019ed03c..01a38c63b69 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -57,7 +57,7 @@ export function addBrowsiTag(data) { script.setAttribute('prebidbpt', 'true'); script.setAttribute('id', 'browsi-tag'); script.setAttribute('src', data.u); - script.prebidData = deepClone(data); + script.prebidData = deepClone(typeof data === 'string' ? Object(data) : data) if (_moduleParams.keyName) { script.prebidData.kn = _moduleParams.keyName; } diff --git a/package-lock.json b/package-lock.json index 261cbdb1fb7..9a373144ebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "gulp-wrap": "^0.15.0", - "just-clone": "^1.0.2", + "klona": "^2.0.6", "live-connect-js": "^6.3.4" }, "devDependencies": { @@ -19198,11 +19198,6 @@ "node": ">=0.6.0" } }, - "node_modules/just-clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" - }, "node_modules/just-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", @@ -19677,6 +19672,14 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/konan": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/konan/-/konan-2.1.1.tgz", @@ -43994,11 +43997,6 @@ "verror": "1.10.0" } }, - "just-clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha512-p93GINPwrve0w3HUzpXmpTl7MyzzWz1B5ag44KEtq/hP1mtK8lA2b9Q0VQaPlnY87352osJcE6uBmN0e8kuFMw==" - }, "just-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", @@ -44382,6 +44380,11 @@ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==" + }, "konan": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/konan/-/konan-2.1.1.tgz", diff --git a/package.json b/package.json index acac0a99da7..28ce27dce05 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "express": "^4.15.4", "fun-hooks": "^0.9.9", "gulp-wrap": "^0.15.0", - "just-clone": "^1.0.2", + "klona": "^2.0.6", "live-connect-js": "^6.3.4" }, "optionalDependencies": { diff --git a/src/utils.js b/src/utils.js index abb69209020..3225eac162e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ import {config} from './config.js'; -import clone from 'just-clone'; +import {klona} from 'klona/json'; import {includes} from './polyfill.js'; import { EVENTS, S2S } from './constants.js'; import {GreedyPromise} from './utils/promise.js'; @@ -609,7 +609,7 @@ export function shuffle(array) { } export function deepClone(obj) { - return clone(obj); + return klona(obj) || {}; } export function inIframe() { From 3870124588e92a2728a4577ea73f5772223b4da3 Mon Sep 17 00:00:00 2001 From: Viktor Dreiling <34981284+3link@users.noreply.github.com> Date: Wed, 8 May 2024 15:57:04 +0200 Subject: [PATCH 105/147] LiveIntent User ID Module: Stabilize Tests (#11463) * Filter for relevant events in tests * Fix expectation --- test/spec/modules/liveIntentIdSystem_spec.js | 83 +++++++++++--------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/test/spec/modules/liveIntentIdSystem_spec.js b/test/spec/modules/liveIntentIdSystem_spec.js index 084b4de212a..373142db82e 100644 --- a/test/spec/modules/liveIntentIdSystem_spec.js +++ b/test/spec/modules/liveIntentIdSystem_spec.js @@ -10,6 +10,18 @@ const PUBLISHER_ID = '89899'; const defaultConfigParams = { params: {publisherId: PUBLISHER_ID, fireEventDelay: 1} }; const responseHeader = {'Content-Type': 'application/json'} +function requests(...urlRegExps) { + return server.requests.filter((request) => urlRegExps.some((regExp) => request.url.match(regExp))) +} + +function rpRequests() { + return requests(/https:\/\/rp.liadm.com.*/) +} + +function idxRequests() { + return requests(/https:\/\/idx.liadm.com.*/) +} + describe('LiveIntentId', function() { let logErrorStub; let uspConsentDataStub; @@ -57,7 +69,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.match(/.*us_privacy=1YNY.*&gdpr=1&n3pc=1&gdpr_consent=consentDataString.*&gpp_s=gppConsentDataString&gpp_as=1%2C2.*/); const response = { unifiedId: 'a_unified_id', @@ -83,7 +95,7 @@ describe('LiveIntentId', function() { }) liveIntentIdSubmodule.getId(defaultConfigParams); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*&us_privacy=1YNY.*&wpn=prebid.*&gdpr=1&n3pc=1&n3pct=1&nb=1&gdpr_consent=consentDataString&gpp_s=gppConsentDataString&gpp_as=1.*/); + expect(rpRequests()[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*&us_privacy=1YNY.*&wpn=prebid.*&gdpr=1&n3pc=1&n3pct=1&nb=1&gdpr_consent=consentDataString&gpp_s=gppConsentDataString&gpp_as=1.*/); done(); }, 300); }); @@ -94,7 +106,7 @@ describe('LiveIntentId', function() { emailHash: '58131bc547fb87af94cebdaf3102321f' }}); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*e=58131bc547fb87af94cebdaf3102321f.+/) + expect(rpRequests()[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*e=58131bc547fb87af94cebdaf3102321f.+/) done(); }, 300); }); @@ -102,7 +114,7 @@ describe('LiveIntentId', function() { it('should initialize LiveConnect and forward the prebid version when decode and emit an event', function(done) { liveIntentIdSubmodule.decode({}, defaultConfigParams); setTimeout(() => { - expect(server.requests[0].url).to.contain('tv=$prebid.version$') + expect(rpRequests()[0].url).to.contain('tv=$prebid.version$') done(); }, 300); }); @@ -119,7 +131,7 @@ describe('LiveIntentId', function() { } }}); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/collector.liveintent.com\/j\?.*aid=a-0001.*&wpn=prebid.*/); + expect(requests(/https:\/\/collector.liveintent.com.*/)[0].url).to.match(/https:\/\/collector.liveintent.com\/j\?.*aid=a-0001.*&wpn=prebid.*/); done(); }, 300); }); @@ -127,7 +139,7 @@ describe('LiveIntentId', function() { it('should fire an event with the provided distributorId', function (done) { liveIntentIdSubmodule.decode({}, { params: { fireEventDelay: 1, distributorId: 'did-1111' } }); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*did=did-1111.*&wpn=prebid.*/); + expect(rpRequests()[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*did=did-1111.*&wpn=prebid.*/); done(); }, 300); }); @@ -135,8 +147,9 @@ describe('LiveIntentId', function() { it('should fire an event without the provided distributorId when appId is provided', function (done) { liveIntentIdSubmodule.decode({}, { params: { fireEventDelay: 1, distributorId: 'did-1111', liCollectConfig: { appId: 'a-0001' } } }); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*aid=a-0001.*&wpn=prebid.*/); - expect(server.requests[0].url).to.not.match(/.*did=*/); + const request = rpRequests()[0]; + expect(request.url).to.match(/https:\/\/rp.liadm.com\/j\?.*aid=a-0001.*&wpn=prebid.*/); + expect(request.url).to.not.match(/.*did=*/); done(); }, 300); }); @@ -153,7 +166,7 @@ describe('LiveIntentId', function() { }) liveIntentIdSubmodule.decode({}, defaultConfigParams); setTimeout(() => { - expect(server.requests[0].url).to.match(/.*us_privacy=1YNY.*&gdpr=0&gdpr_consent=consentDataString.*&gpp_s=gppConsentDataString&gpp_as=1.*/); + expect(rpRequests()[0].url).to.match(/.*us_privacy=1YNY.*&gdpr=0&gdpr_consent=consentDataString.*&gpp_s=gppConsentDataString&gpp_as=1.*/); done(); }, 300); }); @@ -164,7 +177,7 @@ describe('LiveIntentId', function() { emailHash: '58131bc547fb87af94cebdaf3102321f' }}); setTimeout(() => { - expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*e=58131bc547fb87af94cebdaf3102321f.+/); + expect(rpRequests()[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*e=58131bc547fb87af94cebdaf3102321f.+/); done(); }, 300); }); @@ -177,7 +190,7 @@ describe('LiveIntentId', function() { it('should fire an event when decode', function(done) { liveIntentIdSubmodule.decode({}, defaultConfigParams); setTimeout(() => { - expect(server.requests[0].url).to.be.not.null + expect(rpRequests()[0].url).to.be.not.null done(); }, 300); }); @@ -188,7 +201,7 @@ describe('LiveIntentId', function() { liveIntentIdSubmodule.getId(defaultConfigParams); liveIntentIdSubmodule.decode({}, defaultConfigParams); setTimeout(() => { - expect(server.requests.length).to.be.eq(1); + expect(rpRequests().length).to.be.eq(1); done(); }, 300); }); @@ -198,7 +211,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId({ params: {...defaultConfigParams.params, ...{'url': 'https://dummy.liveintent.com/idex'}} }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = requests(/https:\/\/dummy.liveintent.com\/idex\/.*/)[0]; expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?cd=.localhost&resolve=nonId'); request.respond( 204, @@ -212,7 +225,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111' } }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq('https://idx.liadm.com/idex/did-1111/any?did=did-1111&cd=.localhost&resolve=nonId'); request.respond( 204, @@ -226,7 +239,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111', liCollectConfig: { appId: 'a-0001' } } }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/any?cd=.localhost&resolve=nonId'); request.respond( 204, @@ -246,7 +259,7 @@ describe('LiveIntentId', function() { } } }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = requests(/https:\/\/dummy.liveintent.com\/idex\/.*/)[0]; expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?cd=.localhost&resolve=nonId'); request.respond( 200, @@ -261,7 +274,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId'); request.respond( 200, @@ -276,7 +289,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId'); request.respond( 503, @@ -293,7 +306,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&cd=.localhost&resolve=nonId`); request.respond( 200, @@ -316,7 +329,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&cd=.localhost&_thirdPC=third-pc&resolve=nonId`); request.respond( 200, @@ -338,7 +351,7 @@ describe('LiveIntentId', function() { let callBackSpy = sinon.spy(); let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&_thirdPC=%7B%22key%22%3A%22value%22%7D&resolve=nonId'); request.respond( 200, @@ -355,12 +368,12 @@ describe('LiveIntentId', function() { }); it('should decode a unifiedId to lipbId and remove it', function() { - const result = liveIntentIdSubmodule.decode({ unifiedId: 'data' }); + const result = liveIntentIdSubmodule.decode({ unifiedId: 'data' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'data'}}); }); it('should decode a nonId to lipbId', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'data' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'data' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'data', 'nonId': 'data'}}); }); @@ -371,7 +384,7 @@ describe('LiveIntentId', function() { ...{ requestedAttributesOverrides: { 'foo': true, 'bar': false } } } }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId&resolve=foo`); request.respond( 200, @@ -382,54 +395,54 @@ describe('LiveIntentId', function() { }); it('should decode a uid2 to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'uid2': 'bar'}, 'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode values with uid2 but no nonId', function() { - const result = liveIntentIdSubmodule.decode({ uid2: 'bar' }); + const result = liveIntentIdSubmodule.decode({ uid2: 'bar' }, defaultConfigParams); expect(result).to.eql({'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode a bidswitch id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', bidswitch: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', bidswitch: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'bidswitch': 'bar'}, 'bidswitch': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode a medianet id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', medianet: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', medianet: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'medianet': 'bar'}, 'medianet': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode a sovrn id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', sovrn: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', sovrn: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'sovrn': 'bar'}, 'sovrn': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode a magnite id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', magnite: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', magnite: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'magnite': 'bar'}, 'magnite': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode an index id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', index: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', index: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'index': 'bar'}, 'index': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode an openx id to a separate object when present', function () { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', openx: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', openx: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'openx': 'bar'}, 'openx': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode an pubmatic id to a separate object when present', function() { - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', pubmatic: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', pubmatic: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'pubmatic': 'bar'}, 'pubmatic': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}}); }); it('should decode a thetradedesk id to a separate object when present', function() { const provider = 'liveintent.com' refererInfoStub.returns({domain: provider}) - const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' }); + const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' }, defaultConfigParams); expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'tdid': 'bar'}, 'tdid': {'id': 'bar', 'ext': {'rtiPartner': 'TDID', 'provider': provider}}}); }); @@ -440,7 +453,7 @@ describe('LiveIntentId', function() { ...{ requestedAttributesOverrides: { 'nonId': false, 'uid2': true } } } }).callback; submoduleCallback(callBackSpy); - let request = server.requests[0]; + let request = idxRequests()[0]; expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=uid2`); request.respond( 200, From 5438945e9d8de671a2b15db2f5fee1b9aa5b885d Mon Sep 17 00:00:00 2001 From: Ruslan S Date: Wed, 8 May 2024 22:29:22 +0800 Subject: [PATCH 106/147] Smaato: Change server response type (#11450) --- modules/smaatoBidAdapter.js | 46 ++++---------- test/spec/modules/smaatoBidAdapter_spec.js | 74 ++-------------------- 2 files changed, 18 insertions(+), 102 deletions(-) diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js index 9a0a0f75623..8f325aa13c9 100644 --- a/modules/smaatoBidAdapter.js +++ b/modules/smaatoBidAdapter.js @@ -19,7 +19,7 @@ import {ortbConverter} from '../libraries/ortbConverter/converter.js'; const BIDDER_CODE = 'smaato'; const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; -const SMAATO_CLIENT = 'prebid_js_$prebid.version$_2.0' +const SMAATO_CLIENT = 'prebid_js_$prebid.version$_3.0' const TTL = 300; const CURRENCY = 'USD'; const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO, NATIVE]; @@ -160,12 +160,8 @@ export const spec = { } else { switch (smtAdType) { case 'Img': - resultingBid.ad = createImgAd(bid.adm); - resultingBid.mediaType = BANNER; - bids.push(resultingBid); - break; case 'Richmedia': - resultingBid.ad = createRichmediaAd(bid.adm); + resultingBid.ad = createBannerAd(bid); resultingBid.mediaType = BANNER; bids.push(resultingBid); break; @@ -370,37 +366,17 @@ const converter = ortbConverter({ } }); -const createImgAd = (adm) => { - const image = JSON.parse(adm).image; - +const createBannerAd = (bid) => { let clickEvent = ''; - image.clicktrackers.forEach(src => { - clickEvent += `fetch(decodeURIComponent('${encodeURIComponent(src)}'), {cache: 'no-cache'});`; - }) - - let markup = `
`; - - image.impressiontrackers.forEach(src => { - markup += ``; - }); - - return markup + '
'; -}; - -const createRichmediaAd = (adm) => { - const rich = JSON.parse(adm).richmedia; - let clickEvent = ''; - rich.clicktrackers.forEach(src => { - clickEvent += `fetch(decodeURIComponent('${encodeURIComponent(src)}'), {cache: 'no-cache'});`; - }) - - let markup = `
${rich.mediadata.content}`; - - rich.impressiontrackers.forEach(src => { - markup += ``; - }); + if (bid.ext && bid.ext.curls) { + let clicks = '' + bid.ext.curls.forEach(src => { + clicks += `fetch(decodeURIComponent('${encodeURIComponent(src)}'), {cache: 'no-cache'});`; + }) + clickEvent = `onclick="${clicks}"` + } - return markup + '
'; + return `
${bid.adm}
`; }; const createNativeAd = (adm) => { diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js index 28fd06c4b8d..2ac2a1e5c33 100644 --- a/test/spec/modules/smaatoBidAdapter_spec.js +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -13,7 +13,6 @@ import 'modules/consentManagementUsp.js'; import 'modules/schain.js'; const ADTYPE_IMG = 'Img'; -const ADTYPE_RICHMEDIA = 'Richmedia'; const ADTYPE_VIDEO = 'Video'; const ADTYPE_NATIVE = 'Native'; @@ -1300,43 +1299,7 @@ describe('smaatoBidAdapterTest', () => { switch (adType) { case ADTYPE_IMG: - adm = JSON.stringify( - { - image: { - img: { - url: 'https://prebid/static/ad.jpg', - w: 320, - h: 50, - ctaurl: 'https://prebid/track/ctaurl' - }, - impressiontrackers: [ - 'https://prebid/track/imp/1', - 'https://prebid/track/imp/2' - ], - clicktrackers: [ - 'https://prebid/track/click/1' - ] - } - }); - break; - case ADTYPE_RICHMEDIA: - adm = JSON.stringify( - { - richmedia: { - mediadata: { - content: '

RICHMEDIA CONTENT

', - w: 800, - h: 600 - }, - impressiontrackers: [ - 'https://prebid/track/imp/1', - 'https://prebid/track/imp/2' - ], - clicktrackers: [ - 'https://prebid/track/click/1' - ] - } - }); + adm = '' break; case ADTYPE_VIDEO: adm = ''; @@ -1372,7 +1335,10 @@ describe('smaatoBidAdapterTest', () => { 'nurl': 'https://prebid/nurl', 'price': 0.01, 'w': 350, - 'h': 50 + 'h': 50, + 'ext': { + curls: ['https://prebid/track/click/1'] + } } ], seat: 'CM6523' @@ -1398,7 +1364,7 @@ describe('smaatoBidAdapterTest', () => { }); describe('non ad pod', () => { - it('single image response', () => { + it('single banner response', () => { const bids = spec.interpretResponse(buildOpenRtbBidResponse(ADTYPE_IMG), buildBidRequest()); expect(bids).to.deep.equal([ @@ -1407,33 +1373,7 @@ describe('smaatoBidAdapterTest', () => { cpm: 0.01, width: 350, height: 50, - ad: '
', - ttl: 300, - creativeId: 'CR69381', - dealId: '12345', - netRevenue: true, - currency: 'USD', - mediaType: 'banner', - meta: { - advertiserDomains: ['smaato.com'], - agencyId: 'CM6523', - networkName: 'smaato', - mediaType: 'banner' - } - } - ]); - }); - - it('single richmedia response', () => { - const bids = spec.interpretResponse(buildOpenRtbBidResponse(ADTYPE_RICHMEDIA), buildBidRequest()); - - expect(bids).to.deep.equal([ - { - requestId: '226416e6e6bf41', - cpm: 0.01, - width: 350, - height: 50, - ad: '

RICHMEDIA CONTENT

', + ad: '
', ttl: 300, creativeId: 'CR69381', dealId: '12345', From 8c5c9d52ef996d90958b41b02808677e0ff7f4bb Mon Sep 17 00:00:00 2001 From: Giuseppe Cera <117671343+giuseppe-exads@users.noreply.github.com> Date: Wed, 8 May 2024 17:10:03 +0100 Subject: [PATCH 107/147] EXADS Bid Adapter : update bidder code before adapter is published (#11464) * First commit * fix: readme.md * fix: changed exads urls * fix: Tools and suggestions related to the doc * fix: from code review * fix: from code review * fix: from code review * fix: error from code review - native example * fox: from code review * fix: from code review * fix: from code review * fix: native img set as mandatory * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: from code review * fix: bidfloor and bidfloorcur set as optional * fix: dsa * fix: mananing multiple responses * fix: unit test after code review * fix: fixing native snippet code * fix: from code review * fix: video events after code review * fix: video module into documentation * fix: impression tracker for native * fix: afeter code review * fix: unit tests * fix: added badv and bcat * fix: video -> mimes and protocols * fix * fix: removed image_output and video_output params, forcing always html for rtb banner * fix: gulp * fix: added site.name * fix: removed EXADS dir * fix: after linting * fix: unit tests * fix: final dsa solution * fix: dsa * fix: fix instream example * fix: doc media type context * fix: documented the endpoint param into native section * fix: related to markdown lint validation (#2) * fix: from CR (#3) * fix: changed bidder code to exads * fix: userAgent --------- Co-authored-by: tfoliveira --- modules/exadsBidAdapter.js | 9 ++++----- modules/exadsBidAdapter.md | 8 ++++---- test/spec/modules/exadsBidAdapter_spec.js | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/exadsBidAdapter.js b/modules/exadsBidAdapter.js index 20ead7a7e6b..e50c141f4b0 100644 --- a/modules/exadsBidAdapter.js +++ b/modules/exadsBidAdapter.js @@ -2,7 +2,7 @@ import * as utils from '../src/utils.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -const BIDDER = 'exadsadserver'; +const BIDDER = 'exads'; const PARTNERS = { ORTB_2_4: 'ortb_2_4' @@ -332,12 +332,11 @@ function getEnvParams() { envParams.osName = 'MacOS'; } else if (envParams.userAgent.match(/Unix/i)) { envParams.osName = 'Unix'; - // TODO: what is userAgent.userAgent supposed to be? - } else if (envParams.userAgent.userAgent?.match(/Android/i)) { + } else if (envParams.userAgent.match(/Android/i)) { envParams.osName = 'Android'; - } else if (envParams.userAgent.userAgent?.match(/iPhone|iPad|iPod/i)) { + } else if (envParams.userAgent.match(/iPhone|iPad|iPod/i)) { envParams.osName = 'iOS'; - } else if (envParams.userAgent.userAgent?.match(/Linux/i)) { + } else if (envParams.userAgent.match(/Linux/i)) { envParams.osName = 'Linux'; } else { envParams.osName = 'Unknown'; diff --git a/modules/exadsBidAdapter.md b/modules/exadsBidAdapter.md index 06b873d8da8..4c8eedffdd0 100644 --- a/modules/exadsBidAdapter.md +++ b/modules/exadsBidAdapter.md @@ -123,7 +123,7 @@ adUnits = } }, bids: [{ - bidder: 'exadsadserver', + bidder: 'exads', params: { zoneId: 12345, fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', @@ -162,7 +162,7 @@ adUnits = } }, bids: [{ - bidder: 'exadsadserver', + bidder: 'exads', params: { zoneId: 12345, fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', @@ -237,7 +237,7 @@ adUnits = [{ } }, bids: [{ - bidder: 'exadsadserver', + bidder: 'exads', params: { zoneId: 12345, fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', @@ -365,7 +365,7 @@ adUnits = [{ } }, bids: [{ - bidder: 'exadsadserver', + bidder: 'exads', params: { zoneId: 12345, fid: '829a896f011475d50da0d82cfdd1af8d9cdb07ff', diff --git a/test/spec/modules/exadsBidAdapter_spec.js b/test/spec/modules/exadsBidAdapter_spec.js index 9253f21ddf1..ca24dad3959 100644 --- a/test/spec/modules/exadsBidAdapter_spec.js +++ b/test/spec/modules/exadsBidAdapter_spec.js @@ -3,7 +3,7 @@ import { spec, imps } from 'modules/exadsBidAdapter.js'; import { BANNER, NATIVE, VIDEO } from '../../../src/mediaTypes.js'; describe('exadsBidAdapterTest', function () { - const bidder = 'exadsadserver'; + const bidder = 'exads'; const partners = { ORTB_2_4: 'ortb_2_4' From 85fd44e1e29939bbda2614553fa9ff787579cdbc Mon Sep 17 00:00:00 2001 From: Harry King-Riches <109534328+harrykingriches@users.noreply.github.com> Date: Wed, 8 May 2024 18:49:47 +0100 Subject: [PATCH 108/147] Rubicon Bid Adapter: Provide backwards compatibility for transparency object (#11426) * Provide backwards compatibility for transparency object When the property `transparency.params` gets passed in the `ortb2` object, the Rubicon adapter throws an error. This change will provide backwards compatibility for the `params` property by adding it to the `dsaparams` property. If `params` or `dsaparams` does not exist, the value will be turned into an empty string. The same is done for the `domain` property. This ensures that the Bid Adapter will not error if these properties do not exist. * Refactor RubiconBidAdapter to fix transparency object compatibility * Fix transparency object compatibility in RubiconBidAdapter * Fix transparency object compatibility in RubiconBidAdapter * Refactor dsatransparency check --------- Co-authored-by: Harry King-Riches <109534328+Strife9224@users.noreply.github.com> --- modules/rubiconBidAdapter.js | 18 ++++++- test/spec/modules/rubiconBidAdapter_spec.js | 58 +++++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index c03065cd5a5..9e47807bdc0 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -982,11 +982,25 @@ function applyFPD(bidRequest, mediaType, data) { 'transparency', (transparency) => { if (Array.isArray(transparency) && transparency.length) { data['dsatransparency'] = transparency.reduce((param, transp) => { + // make sure domain is there, otherwise skip entry + const domain = transp.domain || ''; + if (!domain) { + return param; + } + + // make sure dsaParam array is there (try both 'dsaparams' and 'params', but prefer dsaparams) + const dsaParamArray = transp.dsaparams || transp.params; + if (!Array.isArray(dsaParamArray) || dsaParamArray.length === 0) { + return param; + } + + // finally we will add this one, if param has been added already, add our seperator if (param) { param += '~~' } - return param += `${transp.domain}~${transp.dsaparams.join('_')}` - }, '') + + return param += `${domain}~${dsaParamArray.join('_')}`; + }, ''); } } ]) diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 55e8909f6c8..494943f9f7d 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -1735,6 +1735,64 @@ describe('the rubicon adapter', function () { } } } + it('should send valid dsaparams but filter out invalid ones', function () { + const ortb2Clone = JSON.parse(JSON.stringify(ortb2)); + ortb2Clone.regs.ext.dsa.transparency = [ + { + domain: 'testdomain.com', + dsaparams: [1], + }, + { + domain: '', + dsaparams: [2], + } + ]; + + const expectedTransparency = 'testdomain.com~1'; + const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({ ...b, ortb2: ortb2Clone })), bidderRequest); + const data = parseQuery(request.data); + + expect(data['dsatransparency']).to.equal(expectedTransparency); + }) + it('should send dsaparams if \"ortb2.regs.ext.dsa.transparancy[0].params\"', function() { + const ortb2Clone = JSON.parse(JSON.stringify(ortb2)); + + ortb2Clone.regs.ext.dsa.transparency = [{ + domain: 'testdomain.com', + dsaparams: [1], + }]; + + const expectedTransparency = 'testdomain.com~1'; + const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2: ortb2Clone})), bidderRequest); + const data = parseQuery(request.data); + + expect(data['dsatransparency']).to.equal(expectedTransparency); + }) + it('should pass an empty transparency param if \"ortb2.regs.ext.dsa.transparency[0].params\" is empty', function() { + const ortb2Clone = JSON.parse(JSON.stringify(ortb2)); + + ortb2Clone.regs.ext.dsa.transparency = [{ + domain: 'testdomain.com', + params: [], + }]; + + const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2: ortb2Clone})), bidderRequest); + const data = parseQuery(request.data); + expect(data['dsatransparency']).to.be.undefined + }) + it('should send an empty transparency if \"ortb2.regs.ext.dsa.transparency[0].domain\" is empty', function() { + const ortb2Clone = JSON.parse(JSON.stringify(ortb2)); + + ortb2Clone.regs.ext.dsa.transparency = [{ + domain: '', + dsaparams: [1], + }]; + + const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2: ortb2Clone})), bidderRequest); + const data = parseQuery(request.data); + + expect(data['dsatransparency']).to.be.undefined + }) it('should send dsa signals if \"ortb2.regs.ext.dsa\"', function() { const expectedTransparency = 'testdomain.com~1~~testdomain2.com~1_2' const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2})), bidderRequest) From b76cddda19812501f67772296e4936cc216ec3f3 Mon Sep 17 00:00:00 2001 From: Yanivplaydigo <165155195+Yanivplaydigo@users.noreply.github.com> Date: Wed, 8 May 2024 22:36:40 +0300 Subject: [PATCH 109/147] Playdigo: new adapter (#11378) * init adapter * add gpp support * upd --- modules/playdigoBidAdapter.js | 199 +++++++++ modules/playdigoBidAdapter.md | 78 ++++ test/spec/modules/playdigoBidAdapter_spec.js | 446 +++++++++++++++++++ 3 files changed, 723 insertions(+) create mode 100644 modules/playdigoBidAdapter.js create mode 100644 modules/playdigoBidAdapter.md create mode 100644 test/spec/modules/playdigoBidAdapter_spec.js diff --git a/modules/playdigoBidAdapter.js b/modules/playdigoBidAdapter.js new file mode 100644 index 00000000000..6c4ea6492d9 --- /dev/null +++ b/modules/playdigoBidAdapter.js @@ -0,0 +1,199 @@ +import { logMessage, logError } from '../src/utils.js'; +import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'playdigo'; +const AD_URL = 'https://server.playdigo.com/pbjs'; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl || bid.vastXml); + case NATIVE: + return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length); + default: + return false; + } +} + +function getPlacementReqData(bid) { + const { params, bidId, mediaTypes } = bid; + const schain = bid.schain || {}; + const { placementId, endpointId } = params; + const bidfloor = getBidFloor(bid); + + const placement = { + bidId, + schain, + bidfloor + }; + + if (placementId) { + placement.placementId = placementId; + placement.type = 'publisher'; + } else if (endpointId) { + placement.endpointId = endpointId; + placement.type = 'network'; + } + + if (mediaTypes && mediaTypes[BANNER]) { + placement.adFormat = BANNER; + placement.sizes = mediaTypes[BANNER].sizes; + } else if (mediaTypes && mediaTypes[VIDEO]) { + placement.adFormat = VIDEO; + placement.playerSize = mediaTypes[VIDEO].playerSize; + placement.minduration = mediaTypes[VIDEO].minduration; + placement.maxduration = mediaTypes[VIDEO].maxduration; + placement.mimes = mediaTypes[VIDEO].mimes; + placement.protocols = mediaTypes[VIDEO].protocols; + placement.startdelay = mediaTypes[VIDEO].startdelay; + placement.placement = mediaTypes[VIDEO].placement; + placement.skip = mediaTypes[VIDEO].skip; + placement.skipafter = mediaTypes[VIDEO].skipafter; + placement.minbitrate = mediaTypes[VIDEO].minbitrate; + placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; + placement.delivery = mediaTypes[VIDEO].delivery; + placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; + placement.api = mediaTypes[VIDEO].api; + placement.linearity = mediaTypes[VIDEO].linearity; + } else if (mediaTypes && mediaTypes[NATIVE]) { + placement.native = mediaTypes[NATIVE]; + placement.adFormat = NATIVE; + } + + return placement; +} + +function getBidFloor(bid) { + if (!bid.getFloor || typeof bid.getFloor !== 'function') { + return 0; + } + + try { + const bidFloor = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid = {}) => { + const { params, bidId, mediaTypes } = bid; + let valid = Boolean(bidId && params && (params.placementId || params.endpointId)); + + if (mediaTypes && mediaTypes[BANNER]) { + valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes); + } else if (mediaTypes && mediaTypes[VIDEO]) { + valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize); + } else if (mediaTypes && mediaTypes[NATIVE]) { + valid = valid && Boolean(mediaTypes[NATIVE]); + } else { + valid = false; + } + return valid; + }, + + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + // convert Native ORTB definition to old-style prebid native definition + validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); + + let deviceWidth = 0; + let deviceHeight = 0; + + let winLocation; + try { + const winTop = window.top; + deviceWidth = winTop.screen.width; + deviceHeight = winTop.screen.height; + winLocation = winTop.location; + } catch (e) { + logMessage(e); + winLocation = window.location; + } + + const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page; + let refferLocation; + try { + refferLocation = refferUrl && new URL(refferUrl); + } catch (e) { + logMessage(e); + } + let location = refferLocation || winLocation; + const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : ''; + const host = location.host; + const page = location.pathname; + const secure = location.protocol === 'https:' ? 1 : 0; + const placements = []; + const request = { + deviceWidth, + deviceHeight, + language, + secure, + host, + page, + placements, + coppa: config.getConfig('coppa') === true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined, + tmax: config.getConfig('bidderTimeout') + }; + + if (bidderRequest.gdprConsent) { + request.gdpr = { + consentString: bidderRequest.gdprConsent.consentString + }; + } + + if (bidderRequest.gppConsent) { + request.gpp = bidderRequest.gppConsent.gppString; + request.gpp_sid = bidderRequest.gppConsent.applicableSections; + } else if (bidderRequest.ortb2?.regs?.gpp) { + request.gpp = bidderRequest.ortb2.regs.gpp; + request.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; + } + + const len = validBidRequests.length; + for (let i = 0; i < len; i++) { + const bid = validBidRequests[i]; + placements.push(getPlacementReqData(bid)); + } + + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; + resItem.meta = { ...resItem.meta, advertiserDomains }; + + response.push(resItem); + } + } + return response; + } +}; + +registerBidder(spec); diff --git a/modules/playdigoBidAdapter.md b/modules/playdigoBidAdapter.md new file mode 100644 index 00000000000..1c63cce79a1 --- /dev/null +++ b/modules/playdigoBidAdapter.md @@ -0,0 +1,78 @@ +# Overview + +``` +Module Name: Playdigo Bidder Adapter +Module Type: Playdigo Bidder Adapter +Maintainer: yr@playdigo.com +``` + +# Description + +One of the easiest way to gain access to Playdigo demand sources - Playdigo header bidding adapter. +Playdigo header bidding adapter connects with Playdigo demand sources to fetch bids for display placements + +# Test Parameters +``` + var adUnits = [ + { + code: 'adunit1', + mediaTypes: { + banner: { + sizes: [ [300, 250], [320, 50] ], + } + }, + bids: [ + { + bidder: 'playdigo', + params: { + placementId: 'testBanner', + } + } + ] + }, + { + code: 'addunit2', + mediaTypes: { + video: { + playerSize: [ [640, 480] ], + context: 'instream', + minduration: 5, + maxduration: 60, + } + }, + bids: [ + { + bidder: 'playdigo', + params: { + placementId: 'testVideo', + } + } + ] + }, + { + code: 'addunit3', + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + }, + bids: [ + { + bidder: 'playdigo', + params: { + placementId: 'testNative', + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/playdigoBidAdapter_spec.js b/test/spec/modules/playdigoBidAdapter_spec.js new file mode 100644 index 00000000000..80fc3c96e81 --- /dev/null +++ b/test/spec/modules/playdigoBidAdapter_spec.js @@ -0,0 +1,446 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/playdigoBidAdapter.js'; +import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js'; +import { getUniqueIdentifierStr } from '../../../src/utils.js'; + +const bidder = 'playdigo' + +describe('PlaydigoBidAdapter', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'testBanner', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [VIDEO]: { + playerSize: [[300, 300]], + minduration: 5, + maxduration: 60 + } + }, + params: { + placementId: 'testVideo', + } + }, + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [NATIVE]: { + native: { + title: { + required: true + }, + body: { + required: true + }, + icon: { + required: true, + size: [64, 64] + } + } + } + }, + params: { + placementId: 'testNative' + } + } + ]; + + const invalidBid = { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + + } + } + + const bidderRequest = { + uspConsent: '1---', + gdprConsent: { + consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', + vendorData: {} + }, + refererInfo: { + referer: 'https://test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and key parameters present', function () { + expect(spec.isBidRequestValid(bids[0])).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests(bids, bidderRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('Returns general data valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', + 'deviceHeight', + 'language', + 'secure', + 'host', + 'page', + 'placements', + 'coppa', + 'ccpa', + 'gdpr', + 'tmax' + ); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + expect(data.coppa).to.be.a('number'); + expect(data.gdpr).to.be.a('object'); + expect(data.ccpa).to.be.a('string'); + expect(data.tmax).to.be.a('number'); + expect(data.placements).to.have.lengthOf(3); + }); + + it('Returns valid placements', function () { + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('publisher'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns valid endpoints', function () { + const bids = [ + { + bidId: getUniqueIdentifierStr(), + bidder: bidder, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + endpointId: 'testBanner', + } + } + ] + + let serverRequest = spec.buildRequests(bids, bidderRequest); + + const { placements } = serverRequest.data; + for (let i = 0, len = placements.length; i < len; i++) { + const placement = placements[i]; + expect(placement.endpointId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']); + expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]); + expect(placement.bidId).to.be.a('string'); + expect(placement.schain).to.be.an('object'); + expect(placement.bidfloor).to.exist.and.to.equal(0); + expect(placement.type).to.exist.and.to.equal('network'); + + if (placement.adFormat === BANNER) { + expect(placement.sizes).to.be.an('array'); + } + switch (placement.adFormat) { + case BANNER: + expect(placement.sizes).to.be.an('array'); + break; + case VIDEO: + expect(placement.playerSize).to.be.an('array'); + expect(placement.minduration).to.be.an('number'); + expect(placement.maxduration).to.be.an('number'); + break; + case NATIVE: + expect(placement.native).to.be.an('object'); + break; + } + } + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + delete bidderRequest.uspConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('object'); + expect(data.gdpr).to.have.property('consentString'); + expect(data.gdpr).to.not.have.property('vendorData'); + expect(data.gdpr.consentString).to.equal(bidderRequest.gdprConsent.consentString); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = '1---'; + delete bidderRequest.gdprConsent; + serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + }); + + describe('gpp consent', function () { + it('bidderRequest.gppConsent', () => { + bidderRequest.gppConsent = { + gppString: 'abc123', + applicableSections: [8] + }; + + let serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.property('gpp'); + expect(data).to.have.property('gpp_sid'); + + delete bidderRequest.gppConsent; + }) + + it('bidderRequest.ortb2.regs.gpp', () => { + bidderRequest.ortb2 = bidderRequest.ortb2 || {}; + bidderRequest.ortb2.regs = bidderRequest.ortb2.regs || {}; + bidderRequest.ortb2.regs.gpp = 'abc123'; + bidderRequest.ortb2.regs.gpp_sid = [8]; + + let serverRequest = spec.buildRequests(bids, bidderRequest); + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.property('gpp'); + expect(data).to.have.property('gpp_sid'); + + bidderRequest.ortb2; + }) + }); + + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal(banner.body[0].requestId); + expect(dataItem.cpm).to.equal(banner.body[0].cpm); + expect(dataItem.width).to.equal(banner.body[0].width); + expect(dataItem.height).to.equal(banner.body[0].height); + expect(dataItem.ad).to.equal(banner.body[0].ad); + expect(dataItem.ttl).to.equal(banner.body[0].ttl); + expect(dataItem.creativeId).to.equal(banner.body[0].creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(banner.body[0].currency); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['google.com'], + advertiserId: 1234 + } + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); +}); From 3c814105d86e66dcde8353754493840f953ebd8d Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Wed, 8 May 2024 22:38:07 +0300 Subject: [PATCH 110/147] Twist Digital Bid Adapter: initial release (#11370) * Added twist digital bid adapter. * Add maintainer email to twistDigitalBidAdapter * Update default subdomain in twistDigitalBidAdapter. * remove unneeded dealId. --- modules/twistDigitalBidAdapter.js | 463 +++++++++ modules/twistDigitalBidAdapter.md | 42 + .../modules/twistDigitalBidAdapter_spec.js | 937 ++++++++++++++++++ 3 files changed, 1442 insertions(+) create mode 100644 modules/twistDigitalBidAdapter.js create mode 100644 modules/twistDigitalBidAdapter.md create mode 100644 test/spec/modules/twistDigitalBidAdapter_spec.js diff --git a/modules/twistDigitalBidAdapter.js b/modules/twistDigitalBidAdapter.js new file mode 100644 index 00000000000..f509e68f9a2 --- /dev/null +++ b/modules/twistDigitalBidAdapter.js @@ -0,0 +1,463 @@ +import { + _each, + deepAccess, + isFn, + parseSizesInput, + parseUrl, + uniques, + isArray, + formatQS, + triggerPixel +} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {getStorageManager} from '../src/storageManager.js'; +import {bidderSettings} from '../src/bidderSettings.js'; +import {config} from '../src/config.js'; +import {chunk} from '../libraries/chunk/chunk.js'; + +const GVLID = 1292; +const DEFAULT_SUB_DOMAIN = 'exchange'; +const BIDDER_CODE = 'twistdigital'; +const BIDDER_VERSION = '1.0.0'; +const CURRENCY = 'USD'; +const TTL_SECONDS = 60 * 5; +const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 60; + +export const webSessionId = 'wsid_' + parseInt(Date.now() * Math.random()); +const storage = getStorageManager({bidderCode: BIDDER_CODE}); + +function getTopWindowQueryParams() { + try { + const parsedUrl = parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.twist.win`; +} + +export function extractCID(params) { + return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; +} + +export function extractPID(params) { + return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; +} + +export function extractSubDomain(params) { + return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; +} + +function isBidRequestValid(bid) { + const params = bid.params || {}; + return !!(extractCID(params) && extractPID(params)); +} + +function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { + const { + params, + bidId, + userId, + adUnitCode, + schain, + mediaTypes, + ortb2Imp, + bidderRequestId, + bidRequestsCount, + bidderRequestsCount, + bidderWinsCount + } = bid; + const {ext} = params; + let {bidFloor} = params; + const hashUrl = hashCode(topWindowUrl); + const uniqueDealId = getUniqueDealId(hashUrl); + const pId = extractPID(params); + const isStorageAllowed = bidderSettings.get(BIDDER_CODE, 'storageAllowed'); + + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); + const cat = deepAccess(bidderRequest, 'ortb2.site.cat', []); + const pagecat = deepAccess(bidderRequest, 'ortb2.site.pagecat', []); + const contentData = deepAccess(bidderRequest, 'ortb2.site.content.data', []); + const userData = deepAccess(bidderRequest, 'ortb2.user.data', []); + + if (isFn(bid.getFloor)) { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: '*', + size: '*' + }); + + if (floorInfo.currency === 'USD') { + bidFloor = floorInfo.floor; + } + } + + let data = { + url: encodeURIComponent(topWindowUrl), + uqs: getTopWindowQueryParams(), + cb: Date.now(), + bidFloor: bidFloor, + bidId: bidId, + referrer: bidderRequest.refererInfo.ref, + adUnitCode: adUnitCode, + publisherId: pId, + sizes: sizes, + uniqueDealId: uniqueDealId, + bidderVersion: BIDDER_VERSION, + prebidVersion: '$prebid.version$', + res: `${screen.width}x${screen.height}`, + schain: schain, + mediaTypes: mediaTypes, + isStorageAllowed: isStorageAllowed, + gpid: gpid, + cat: cat, + contentData, + userData: userData, + pagecat: pagecat, + transactionId: ortb2Imp?.ext?.tid, + bidderRequestId: bidderRequestId, + bidRequestsCount: bidRequestsCount, + bidderRequestsCount: bidderRequestsCount, + bidderWinsCount: bidderWinsCount, + bidderTimeout: bidderTimeout, + webSessionId: webSessionId + }; + + appendUserIdsToRequestPayload(data, userId); + + const sua = deepAccess(bidderRequest, 'ortb2.device.sua'); + + if (sua) { + data.sua = sua; + } + + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString) { + data.gdprConsent = bidderRequest.gdprConsent.consentString; + } + if (bidderRequest.gdprConsent.gdprApplies !== undefined) { + data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + } + } + if (bidderRequest.uspConsent) { + data.usPrivacy = bidderRequest.uspConsent; + } + + if (bidderRequest.gppConsent) { + data.gppString = bidderRequest.gppConsent.gppString; + data.gppSid = bidderRequest.gppConsent.applicableSections; + } else if (bidderRequest.ortb2?.regs?.gpp) { + data.gppString = bidderRequest.ortb2.regs.gpp; + data.gppSid = bidderRequest.ortb2.regs.gpp_sid; + } + + if (bidderRequest.fledgeEnabled) { + const fledge = deepAccess(bidderRequest, 'ortb2Imp.ext.ae'); + if (fledge) { + data.fledge = fledge; + } + } + + _each(ext, (value, key) => { + data['ext.' + key] = value; + }); + + return data; +} + +function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { + const {params} = bid; + const cId = extractCID(params); + const subDomain = extractSubDomain(params); + const data = buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout); + const dto = { + method: 'POST', + url: `${createDomain(subDomain)}/prebid/multi/${cId}`, + data: data + }; + return dto; +} + +function buildSingleRequest(bidRequests, bidderRequest, topWindowUrl, bidderTimeout) { + const {params} = bidRequests[0]; + const cId = extractCID(params); + const subDomain = extractSubDomain(params); + const data = bidRequests.map(bid => { + const sizes = parseSizesInput(bid.sizes); + return buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) + }); + const chunkSize = Math.min(20, config.getConfig('twistdigital.chunkSize') || 10); + + const chunkedData = chunk(data, chunkSize); + return chunkedData.map(chunk => { + return { + method: 'POST', + url: `${createDomain(subDomain)}/prebid/multi/${cId}`, + data: { + bids: chunk + } + }; + }); +} + +function appendUserIdsToRequestPayload(payloadRef, userIds) { + let key; + _each(userIds, (userId, idSystemProviderName) => { + key = `uid.${idSystemProviderName}`; + switch (idSystemProviderName) { + case 'digitrustid': + payloadRef[key] = deepAccess(userId, 'data.id'); + break; + case 'lipb': + payloadRef[key] = userId.lipbid; + break; + case 'parrableId': + payloadRef[key] = userId.eid; + break; + case 'id5id': + payloadRef[key] = userId.uid; + break; + default: + payloadRef[key] = userId; + } + }); +} + +function buildRequests(validBidRequests, bidderRequest) { + const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation; + const bidderTimeout = config.getConfig('bidderTimeout'); + + const singleRequestMode = config.getConfig('twistdigital.singleRequest'); + + const requests = []; + + if (singleRequestMode) { + // banner bids are sent as a single request + const bannerBidRequests = validBidRequests.filter(bid => isArray(bid.mediaTypes) ? bid.mediaTypes.includes(BANNER) : bid.mediaTypes[BANNER] !== undefined); + if (bannerBidRequests.length > 0) { + const singleRequests = buildSingleRequest(bannerBidRequests, bidderRequest, topWindowUrl, bidderTimeout); + requests.push(...singleRequests); + } + + // video bids are sent as a single request for each bid + + const videoBidRequests = validBidRequests.filter(bid => bid.mediaTypes[VIDEO] !== undefined); + videoBidRequests.forEach(validBidRequest => { + const sizes = parseSizesInput(validBidRequest.sizes); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); + requests.push(request); + }); + } else { + validBidRequests.forEach(validBidRequest => { + const sizes = parseSizesInput(validBidRequest.sizes); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout); + requests.push(request); + }); + } + return requests; +} + +function interpretResponse(serverResponse, request) { + if (!serverResponse || !serverResponse.body) { + return []; + } + + const singleRequestMode = config.getConfig('twistdigital.singleRequest'); + const reqBidId = deepAccess(request, 'data.bidId'); + const {results} = serverResponse.body; + + let output = []; + + try { + results.forEach((result, i) => { + const { + creativeId, + ad, + price, + exp, + width, + height, + currency, + bidId, + nurl, + advertiserDomains, + metaData, + mediaType = BANNER + } = result; + if (!ad || !price) { + return; + } + + const response = { + requestId: (singleRequestMode && bidId) ? bidId : reqBidId, + cpm: price, + width: width, + height: height, + creativeId: creativeId, + currency: currency || CURRENCY, + netRevenue: true, + ttl: exp || TTL_SECONDS, + }; + + if (nurl) { + response.nurl = nurl; + } + + if (metaData) { + Object.assign(response, { + meta: metaData + }) + } else { + Object.assign(response, { + meta: { + advertiserDomains: advertiserDomains || [] + } + }) + } + + if (mediaType === BANNER) { + Object.assign(response, { + ad: ad, + }); + } else { + Object.assign(response, { + vastXml: ad, + mediaType: VIDEO + }); + } + output.push(response); + }); + + return output; + } catch (e) { + return []; + } +} + +function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '', gppConsent = {}) { + let syncs = []; + const {iframeEnabled, pixelEnabled} = syncOptions; + const {gdprApplies, consentString = ''} = gdprConsent; + const {gppString, applicableSections} = gppConsent; + + const cidArr = responses.filter(resp => deepAccess(resp, 'body.cid')).map(resp => resp.body.cid).filter(uniques); + let params = `?cid=${encodeURIComponent(cidArr.join(','))}&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}`; + + if (gppString && applicableSections?.length) { + params += '&gpp=' + encodeURIComponent(gppString); + params += '&gpp_sid=' + encodeURIComponent(applicableSections.join(',')); + } + + if (iframeEnabled) { + syncs.push({ + type: 'iframe', + url: `https://sync.twist.win/api/sync/iframe/${params}` + }); + } + if (pixelEnabled) { + syncs.push({ + type: 'image', + url: `https://sync.twist.win/api/sync/image/${params}` + }); + } + return syncs; +} + +/** + * @param {Bid} bid + */ +function onBidWon(bid) { + if (!bid.nurl) { + return; + } + const wonBid = { + adId: bid.adId, + creativeId: bid.creativeId, + auctionId: bid.auctionId, + transactionId: bid.transactionId, + adUnitCode: bid.adUnitCode, + cpm: bid.cpm, + currency: bid.currency, + originalCpm: bid.originalCpm, + originalCurrency: bid.originalCurrency, + netRevenue: bid.netRevenue, + mediaType: bid.mediaType, + timeToRespond: bid.timeToRespond, + status: bid.status, + }; + const qs = formatQS(wonBid); + const url = bid.nurl + (bid.nurl.indexOf('?') === -1 ? '?' : '&') + qs; + triggerPixel(url); +} + +export function hashCode(s, prefix = '_') { + const l = s.length; + let h = 0 + let i = 0; + if (l > 0) { + while (i < l) { + h = (h << 5) - h + s.charCodeAt(i++) | 0; + } + } + return prefix + h; +} + +export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { + const storageKey = `u_${key}`; + const now = Date.now(); + const data = getStorageItem(storageKey); + let uniqueId; + + if (!data || !data.value || now - data.created > expiry) { + uniqueId = `${key}_${now.toString()}`; + setStorageItem(storageKey, uniqueId); + } else { + uniqueId = data.value; + } + + return uniqueId; +} + +export function getStorageItem(key) { + try { + return tryParseJSON(storage.getDataFromLocalStorage(key)); + } catch (e) { + } + + return null; +} + +export function setStorageItem(key, value, timestamp) { + try { + const created = timestamp || Date.now(); + const data = JSON.stringify({value, created}); + storage.setDataInLocalStorage(key, data); + } catch (e) { + } +} + +export function tryParseJSON(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } +} + +export const spec = { + code: BIDDER_CODE, + version: BIDDER_VERSION, + gvlid: GVLID, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + onBidWon +}; + +registerBidder(spec); diff --git a/modules/twistDigitalBidAdapter.md b/modules/twistDigitalBidAdapter.md new file mode 100644 index 00000000000..8722608c5dd --- /dev/null +++ b/modules/twistDigitalBidAdapter.md @@ -0,0 +1,42 @@ +# Overview + +**Module Name:** Twist Digital Bidder Adapter + +**Module Type:** Bidder Adapter + +**Maintainer:** yoni@twist.win + + + + + + + + +# Description + +Module that connects to Twist Digital demand sources. + +# Test Parameters +```js +var adUnits = [ + { + code: 'test-ad', + sizes: [[300, 250]], + bids: [ + { + bidder: 'twistdigital', + params: { + cId: '562524b21b1c1f08117fc7f9', + pId: '59ac17c192832d0011283fe3', + bidFloor: 0.0001, + ext: { + param1: 'loremipsum', + param2: 'dolorsitamet' + } + } + } + ] + } +]; +``` diff --git a/test/spec/modules/twistDigitalBidAdapter_spec.js b/test/spec/modules/twistDigitalBidAdapter_spec.js new file mode 100644 index 00000000000..7d263f6d4f0 --- /dev/null +++ b/test/spec/modules/twistDigitalBidAdapter_spec.js @@ -0,0 +1,937 @@ +import {expect} from 'chai'; +import { + spec as adapter, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId, + webSessionId +} from 'modules/twistDigitalBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {version} from 'package.json'; +import {useFakeTimers} from 'sinon'; +import {BANNER, VIDEO} from '../../../src/mediaTypes'; +import {config} from '../../../src/config'; +import {deepSetValue} from 'src/utils.js'; + +export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId']; + +const SUB_DOMAIN = 'openrtb'; + +const BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '59db6b3b4ffaa70004f45cdc', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1, + 'ext': { + 'param1': 'loremipsum', + 'param2': 'dolorsitamet' + } + }, + 'placementCode': 'div-gpt-ad-1460505748561-0', + 'sizes': [[300, 250], [300, 600]], + 'bidderRequestId': '1fdb5ff1b6eaa7', + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, + 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a', + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'mediaTypes': [BANNER], + 'ortb2Imp': { + 'ext': { + tid: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + 'gpid': '1234567890' + } + } +}; + +const VIDEO_BID = { + 'bidId': '2d52001cabd527', + 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560', + 'bidderRequestId': '12a8ae9ada9c13', + ortb2Imp: { + ext: { + tid: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + } + }, + 'bidRequestsCount': 4, + 'bidderRequestsCount': 3, + 'bidderWinsCount': 1, + 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc', + 'params': { + 'subDomain': SUB_DOMAIN, + 'cId': '635509f7ff6642d368cb9837', + 'pId': '59ac17c192832d0011283fe3', + 'bidFloor': 0.1 + }, + 'sizes': [[545, 307]], + 'mediaTypes': { + 'video': { + 'playerSize': [[545, 307]], + 'context': 'instream', + 'mimes': [ + 'video/mp4', + 'application/javascript' + ], + 'protocols': [2, 3, 5, 6], + 'maxduration': 60, + 'minduration': 0, + 'startdelay': 0, + 'linearity': 1, + 'api': [2], + 'placement': 1 + } + } +} + +const BIDDER_REQUEST = { + 'gdprConsent': { + 'consentString': 'consent_string', + 'gdprApplies': true + }, + 'gppString': 'gpp_string', + 'gppSid': [7], + 'uspConsent': 'consent_string', + 'refererInfo': { + 'page': 'https://www.greatsite.com', + 'ref': 'https://www.somereferrer.com' + }, + 'ortb2': { + 'site': { + 'cat': ['IAB2'], + 'pagecat': ['IAB2-2'], + 'content': { + 'data': [{ + 'name': 'example.com', + 'ext': { + 'segtax': 7 + }, + 'segments': [ + {'id': 'segId1'}, + {'id': 'segId2'} + ] + }] + } + }, + 'regs': { + 'gpp': 'gpp_string', + 'gpp_sid': [7] + }, + 'device': { + 'sua': { + 'source': 2, + 'platform': { + 'brand': 'Android', + 'version': ['8', '0', '0'] + }, + 'browsers': [ + {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, + {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, + {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']} + ], + 'mobile': 1, + 'model': 'SM-G955U', + 'bitness': '64', + 'architecture': '' + } + }, + user: { + data: [ + { + ext: {segtax: 600, segclass: '1'}, + name: 'example.com', + segment: [{id: '243'}], + }, + ], + } + }, +}; + +const SERVER_RESPONSE = { + body: { + cid: 'testcid123', + results: [{ + 'ad': '', + 'bidId': '2d52001cabd527-response', + 'price': 0.8, + 'creativeId': '12610997325162499419', + 'exp': 30, + 'width': 300, + 'height': 250, + 'advertiserDomains': ['securepubads.g.doubleclick.net'], + 'cookies': [{ + 'src': 'https://sync.com', + 'type': 'iframe' + }, { + 'src': 'https://sync.com', + 'type': 'img' + }] + }] + } +}; + +const VIDEO_SERVER_RESPONSE = { + body: { + 'cid': '635509f7ff6642d368cb9837', + 'results': [{ + 'ad': '', + 'advertiserDomains': ['twistdigital.com'], + 'exp': 60, + 'width': 545, + 'height': 307, + 'mediaType': 'video', + 'creativeId': '12610997325162499419', + 'price': 2, + 'cookies': [] + }] + } +} + +const REQUEST = { + data: { + width: 300, + height: 250, + bidId: '2d52001cabd527' + } +}; + +function getTopWindowQueryParams() { + try { + const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true}); + return parsedUrl.search; + } catch (e) { + return ''; + } +} + +describe('TwistDigitalBidAdapter', function () { + describe('validtae spec', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + + it('exists and is a function', function () { + expect(adapter.getUserSyncs).to.exist.and.to.be.a('function'); + }); + + it('exists and is a string', function () { + expect(adapter.code).to.exist.and.to.be.a('string'); + }); + + it('exists and contains media types', function () { + expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2); + expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]); + }); + }); + + describe('validate bid requests', function () { + it('should require cId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + pId: 'pid' + } + }); + expect(isValid).to.be.false; + }); + + it('should require pId', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid' + } + }); + expect(isValid).to.be.false; + }); + + it('should validate correctly', function () { + const isValid = adapter.isBidRequestValid({ + params: { + cId: 'cid', + pId: 'pid' + } + }); + expect(isValid).to.be.true; + }); + }); + + describe('build requests', function () { + let sandbox; + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + twistdigital: { + storageAllowed: true, + } + }; + sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1000); + }); + + it('should build video request', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + config.setConfig({ + bidderTimeout: 3000 + }); + const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`, + data: { + adUnitCode: '63550ad1ff6642d368cba59dh5884270560', + bidFloor: 0.1, + bidId: '2d52001cabd527', + bidderVersion: adapter.version, + cat: ['IAB2'], + pagecat: ['IAB2-2'], + cb: 1000, + gdpr: 1, + gdprConsent: 'consent_string', + usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee', + bidderRequestId: '12a8ae9ada9c13', + gpid: '', + prebidVersion: version, + publisherId: '59ac17c192832d0011283fe3', + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + res: `${window.top.screen.width}x${window.top.screen.height}`, + schain: VIDEO_BID.schain, + sizes: ['545x307'], + sua: { + 'source': 2, + 'platform': { + 'brand': 'Android', + 'version': ['8', '0', '0'] + }, + 'browsers': [ + {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, + {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, + {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']} + ], + 'mobile': 1, + 'model': 'SM-G955U', + 'bitness': '64', + 'architecture': '' + }, + contentData: [{ + 'name': 'example.com', + 'ext': { + 'segtax': 7 + }, + 'segments': [ + {'id': 'segId1'}, + {'id': 'segId2'} + ] + }], + userData: [ + { + ext: {segtax: 600, segclass: '1'}, + name: 'example.com', + segment: [{id: '243'}], + }, + ], + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + uqs: getTopWindowQueryParams(), + isStorageAllowed: true, + webSessionId: webSessionId, + mediaTypes: { + video: { + api: [2], + context: 'instream', + linearity: 1, + maxduration: 60, + mimes: [ + 'video/mp4', + 'application/javascript' + ], + minduration: 0, + placement: 1, + playerSize: [[545, 307]], + protocols: [2, 3, 5, 6], + startdelay: 0 + } + } + } + }) + ; + }); + + it('should build banner request for each size', function () { + config.setConfig({ + bidderTimeout: 3000 + }); + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + const requests = adapter.buildRequests([BID], BIDDER_REQUEST); + expect(requests).to.have.length(1); + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: { + gdprConsent: 'consent_string', + gdpr: 1, + usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + bidderRequestId: '1fdb5ff1b6eaa7', + sizes: ['300x250', '300x600'], + sua: { + 'source': 2, + 'platform': { + 'brand': 'Android', + 'version': ['8', '0', '0'] + }, + 'browsers': [ + {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, + {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, + {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']} + ], + 'mobile': 1, + 'model': 'SM-G955U', + 'bitness': '64', + 'architecture': '' + }, + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + isStorageAllowed: true, + gpid: '1234567890', + cat: ['IAB2'], + pagecat: ['IAB2-2'], + contentData: [{ + 'name': 'example.com', + 'ext': { + 'segtax': 7 + }, + 'segments': [ + {'id': 'segId1'}, + {'id': 'segId2'} + ] + }], + userData: [ + { + ext: {segtax: 600, segclass: '1'}, + name: 'example.com', + segment: [{id: '243'}], + }, + ], + webSessionId: webSessionId + } + }); + }); + + it('should build single banner request for multiple bids', function () { + config.setConfig({ + bidderTimeout: 3000, + twistdigital: { + singleRequest: true, + chunkSize: 2 + } + }); + + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page); + + const BID2 = utils.deepClone(BID); + BID2.bidId = '2d52001cabd528'; + BID2.adUnitCode = 'div-gpt-ad-12345-1'; + BID2.sizes = [[300, 250]]; + + const REQUEST_DATA = { + gdprConsent: 'consent_string', + gdpr: 1, + usPrivacy: 'consent_string', + gppString: 'gpp_string', + gppSid: [7], + bidRequestsCount: 4, + bidderRequestsCount: 3, + bidderWinsCount: 1, + bidderTimeout: 3000, + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + bidderRequestId: '1fdb5ff1b6eaa7', + sizes: ['300x250', '300x600'], + sua: { + 'source': 2, + 'platform': { + 'brand': 'Android', + 'version': ['8', '0', '0'] + }, + 'browsers': [ + {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']}, + {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']}, + {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']} + ], + 'mobile': 1, + 'model': 'SM-G955U', + 'bitness': '64', + 'architecture': '' + }, + url: 'https%3A%2F%2Fwww.greatsite.com', + referrer: 'https://www.somereferrer.com', + cb: 1000, + bidFloor: 0.1, + bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', + publisherId: '59ac17c192832d0011283fe3', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + schain: BID.schain, + res: `${window.top.screen.width}x${window.top.screen.height}`, + mediaTypes: [BANNER], + uqs: getTopWindowQueryParams(), + 'ext.param1': 'loremipsum', + 'ext.param2': 'dolorsitamet', + isStorageAllowed: true, + gpid: '1234567890', + cat: ['IAB2'], + pagecat: ['IAB2-2'], + contentData: [{ + 'name': 'example.com', + 'ext': { + 'segtax': 7 + }, + 'segments': [ + {'id': 'segId1'}, + {'id': 'segId2'} + ] + }], + userData: [ + { + ext: {segtax: 600, segclass: '1'}, + name: 'example.com', + segment: [{id: '243'}], + }, + ], + webSessionId: webSessionId + }; + + const REQUEST_DATA2 = utils.deepClone(REQUEST_DATA); + REQUEST_DATA2.bidId = '2d52001cabd528'; + REQUEST_DATA2.adUnitCode = 'div-gpt-ad-12345-1'; + REQUEST_DATA2.sizes = ['300x250']; + + const requests = adapter.buildRequests([BID, BID2], BIDDER_REQUEST); + expect(requests).to.have.length(1); + + expect(requests[0]).to.deep.equal({ + method: 'POST', + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + data: {bids: [REQUEST_DATA, REQUEST_DATA2]} + }); + }); + + it('should return seperated requests for video and banner if singleRequest is true', function () { + config.setConfig({ + bidderTimeout: 3000, + twistdigital: { + singleRequest: true, + chunkSize: 2 + } + }); + + const requests = adapter.buildRequests([BID, VIDEO_BID], BIDDER_REQUEST); + expect(requests).to.have.length(2); + }); + + it('should chunk requests if requests exceed chunkSize and singleRequest is true', function () { + config.setConfig({ + bidderTimeout: 3000, + twistdigital: { + singleRequest: true, + chunkSize: 2 + } + }); + + const requests = adapter.buildRequests([BID, BID, BID, BID], BIDDER_REQUEST); + expect(requests).to.have.length(2); + }); + + it('should set fledge correctly if enabled', function () { + config.resetConfig(); + const bidderRequest = utils.deepClone(BIDDER_REQUEST); + bidderRequest.fledgeEnabled = true; + deepSetValue(bidderRequest, 'ortb2Imp.ext.ae', 1); + const requests = adapter.buildRequests([BID], bidderRequest); + expect(requests[0].data.fledge).to.equal(1); + }); + + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + config.resetConfig(); + sandbox.restore(); + }); + }); + + describe('getUserSyncs', function () { + it('should have valid user sync with iframeEnabled', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.twist.win/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with cid on response', function () { + const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + expect(result).to.deep.equal([{ + type: 'iframe', + url: 'https://sync.twist.win/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=' + }]); + }); + + it('should have valid user sync with pixelEnabled', function () { + const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + + expect(result).to.deep.equal([{ + 'url': 'https://sync.twist.win/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=', + 'type': 'image' + }]); + }) + }); + + describe('interpret response', function () { + it('should return empty array when there is no response', function () { + const responses = adapter.interpretResponse(null); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no ad', function () { + const responses = adapter.interpretResponse({price: 1, ad: ''}); + expect(responses).to.be.empty; + }); + + it('should return empty array when there is no price', function () { + const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + expect(responses).to.be.empty; + }); + + it('should return an array of interpreted banner responses', function () { + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 0.8, + width: 300, + height: 250, + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 30, + ad: '', + meta: { + advertiserDomains: ['securepubads.g.doubleclick.net'] + } + }); + }); + + it('should get meta from response metaData', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + serverResponse.body.results[0].metaData = { + advertiserDomains: ['twistdigital.com'], + agencyName: 'Agency Name', + }; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses[0].meta).to.deep.equal({ + advertiserDomains: ['twistdigital.com'], + agencyName: 'Agency Name' + }); + }); + + it('should return an array of interpreted video responses', function () { + const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0]).to.deep.equal({ + requestId: '2d52001cabd527', + cpm: 2, + width: 545, + height: 307, + mediaType: 'video', + creativeId: '12610997325162499419', + currency: 'USD', + netRevenue: true, + ttl: 60, + vastXml: '', + meta: { + advertiserDomains: ['twistdigital.com'] + } + }); + }); + + it('should populate requestId from response in case of singleRequest true', function () { + config.setConfig({ + twistdigital: { + singleRequest: true, + chunkSize: 2 + } + }); + + const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].requestId).to.equal('2d52001cabd527-response'); + + config.resetConfig(); + }); + + it('should take default TTL', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + delete serverResponse.body.results[0].exp; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].ttl).to.equal(300); + }); + + it('should add nurl if exists on response', function () { + const serverResponse = utils.deepClone(SERVER_RESPONSE); + serverResponse.body.results[0].nurl = 'https://test.com/win-notice?test=123'; + const responses = adapter.interpretResponse(serverResponse, REQUEST); + expect(responses).to.have.length(1); + expect(responses[0].nurl).to.equal('https://test.com/win-notice?test=123'); + }); + }); + + describe('user id system', function () { + TEST_ID_SYSTEMS.forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'lipb': + return {lipbid: id}; + case 'parrableId': + return {eid: id}; + case 'id5id': + return {uid: id}; + default: + return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({'c_id': '1'}); + const pid = extractPID({'p_id': '1'}); + const subDomain = extractSubDomain({'sub_domain': 'prebid'}); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({'cID': '1'}); + const pid = extractPID({'Pid': '2'}); + const subDomain = extractSubDomain({'subDOMAIN': 'prebid'}); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + twistdigital: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + }); + + describe('unique deal id', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + twistdigital: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + const key = 'myKey'; + let uniqueDealId; + beforeEach(() => { + uniqueDealId = getUniqueDealId(key, 0); + }) + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function (done) { + setTimeout(() => { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + done(); + }, 200) + }); + }); + + describe('storage utils', function () { + before(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + twistdigital: { + storageAllowed: true + } + }; + }); + after(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + }); + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const {value, created} = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({event: 'send'}); + const {event} = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); + + describe('validate onBidWon', function () { + beforeEach(function () { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function () { + utils.triggerPixel.restore(); + }); + + it('should call triggerPixel if nurl exists', function () { + const bid = { + adUnitCode: 'div-gpt-ad-12345-0', + adId: '2d52001cabd527', + auctionId: '1fdb5ff1b6eaa7', + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + status: 'rendered', + timeToRespond: 100, + cpm: 0.8, + originalCpm: 0.8, + creativeId: '12610997325162499419', + currency: 'USD', + originalCurrency: 'USD', + height: 250, + mediaType: 'banner', + nurl: 'https://test.com/win-notice?test=123', + netRevenue: true, + requestId: '2d52001cabd527', + ttl: 30, + width: 300 + }; + adapter.onBidWon(bid); + expect(utils.triggerPixel.called).to.be.true; + + const url = utils.triggerPixel.args[0]; + + expect(url[0]).to.be.equal('https://test.com/win-notice?test=123&adId=2d52001cabd527&creativeId=12610997325162499419&auctionId=1fdb5ff1b6eaa7&transactionId=c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf&adUnitCode=div-gpt-ad-12345-0&cpm=0.8¤cy=USD&originalCpm=0.8&originalCurrency=USD&netRevenue=true&mediaType=banner&timeToRespond=100&status=rendered'); + }); + + it('should not call triggerPixel if nurl does not exist', function () { + const bid = { + adUnitCode: 'div-gpt-ad-12345-0', + adId: '2d52001cabd527', + auctionId: '1fdb5ff1b6eaa7', + transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf', + status: 'rendered', + timeToRespond: 100, + cpm: 0.8, + originalCpm: 0.8, + creativeId: '12610997325162499419', + currency: 'USD', + originalCurrency: 'USD', + height: 250, + mediaType: 'banner', + netRevenue: true, + requestId: '2d52001cabd527', + ttl: 30, + width: 300 + }; + adapter.onBidWon(bid); + expect(utils.triggerPixel.called).to.be.false; + }); + }); +}); From 3c4ebab30c514d5f20b9ceca175e20f6cae66668 Mon Sep 17 00:00:00 2001 From: Jorge Algaba Aranda Date: Thu, 9 May 2024 16:11:31 +0200 Subject: [PATCH 111/147] Telaria bid adapter typo (#11471) --- modules/telariaBidAdapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/telariaBidAdapter.md b/modules/telariaBidAdapter.md index 6a5e24e9a5e..3a6c86ec2f6 100644 --- a/modules/telariaBidAdapter.md +++ b/modules/telariaBidAdapter.md @@ -10,7 +10,7 @@ Maintainer: github@telaria.com Connects to Telaria's exchange. -Telaria bid adapter supports insteream Video. +Telaria bid adapter supports instream Video. # Test Parameters ``` From c902d6ccf58b8979bc7502a0095df1438136745c Mon Sep 17 00:00:00 2001 From: Love Sharma Date: Thu, 9 May 2024 10:23:21 -0400 Subject: [PATCH 112/147] chore: code cleanup [PB-2828] (#11468) Co-authored-by: Love Sharma --- modules/ixBidAdapter.js | 153 +--------------------- test/spec/modules/ixBidAdapter_spec.js | 174 +------------------------ 2 files changed, 8 insertions(+), 319 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 248dbea0046..f56e2790ad6 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -18,15 +18,12 @@ import { } from '../src/utils.js'; import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; -import { EVENTS } from '../src/constants.js'; import { getStorageManager } from '../src/storageManager.js'; -import * as events from '../src/events.js'; import { find } from '../src/polyfill.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { INSTREAM, OUTSTREAM } from '../src/video.js'; import { Renderer } from '../src/Renderer.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; const BIDDER_CODE = 'ix'; const ALIAS_BIDDER_CODE = 'roundel'; @@ -49,17 +46,6 @@ const PRICE_TO_DOLLAR_FACTOR = { const IFRAME_USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html'; const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' }; const IMG_USER_SYNC_URL = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid'; -export const ERROR_CODES = { - BID_SIZE_INVALID_FORMAT: 1, - BID_SIZE_NOT_INCLUDED: 2, - PROPERTY_NOT_INCLUDED: 3, - SITE_ID_INVALID_VALUE: 4, - BID_FLOOR_INVALID_FORMAT: 5, - IX_FPD_EXCEEDS_MAX_SIZE: 6, - EXCEEDS_MAX_SIZE: 7, - PB_FPD_EXCEEDS_MAX_SIZE: 8, - VIDEO_DURATION_INVALID: 9 -}; const FIRST_PARTY_DATA = { SITE: [ 'id', 'name', 'domain', 'cat', 'sectioncat', 'pagecat', 'page', 'ref', 'search', 'mobile', @@ -110,7 +96,6 @@ const VIDEO_PARAMS_ALLOW_LIST = [ ]; const LOCAL_STORAGE_KEY = 'ixdiag'; export const LOCAL_STORAGE_FEATURE_TOGGLES_KEY = `${BIDDER_CODE}_features`; -let hasRegisteredHandler = false; export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); export const FEATURE_TOGGLES = { // Update with list of CFTs to be requested from Exchange @@ -262,8 +247,7 @@ export function bidToVideoImp(bid) { if (imp.video.minduration > imp.video.maxduration) { logError( - `IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]`, - { bidder: BIDDER_CODE, code: ERROR_CODES.VIDEO_DURATION_INVALID } + `IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]` ); return {}; } @@ -883,13 +867,6 @@ function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids r.ext.ixdiag.syncsPerBidder = config.getConfig('userSync').syncsPerBidder; } - // Get cached errors stored in LocalStorage - const cachedErrors = getCachedErrors(); - - if (!isEmpty(cachedErrors)) { - r.ext.ixdiag.err = cachedErrors; - } - // Add number of available imps to ixDiag. r.ext.ixdiag.imps = Object.keys(impressions).length; @@ -1546,104 +1523,6 @@ function createMissingBannerImp(bid, imp, newSize) { return newImp; } -/** - * @typedef {Array[message: string, err: Object]} ErrorData - * @property {string} message - The error message. - * @property {object} err - The error object. - * @property {string} err.bidder - The bidder of the error. - * @property {string} err.code - The error code. - */ - -/** - * Error Event handler that receives type and arguments in a data object. - * - * @param {ErrorData} data - */ -function storeErrorEventData(data) { - if (!storage.localStorageIsEnabled()) { - return; - } - - let currentStorage; - - try { - currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}'); - } catch (e) { - logWarn('ix can not read ixdiag from localStorage.'); - } - - const todayDate = new Date(); - - Object.keys(currentStorage).map((errorDate) => { - const date = new Date(errorDate); - - if (date.setDate(date.getDate() + 7) - todayDate < 0) { - delete currentStorage[errorDate]; - } - }); - - if (data.type === 'ERROR' && data.arguments && data.arguments[1] && data.arguments[1].bidder === BIDDER_CODE) { - const todayString = todayDate.toISOString().slice(0, 10); - - const errorCode = data.arguments[1].code; - - if (errorCode) { - currentStorage[todayString] = currentStorage[todayString] || {}; - - if (!Number(currentStorage[todayString][errorCode])) { - currentStorage[todayString][errorCode] = 0; - } - - currentStorage[todayString][errorCode]++; - }; - } - - storage.setDataInLocalStorage(LOCAL_STORAGE_KEY, JSON.stringify(currentStorage)); -} - -/** - * Event handler for storing data into local storage. It will only store data if - * local storage premissions are avaliable - */ -function localStorageHandler(data) { - if (data.type === 'ERROR' && data.arguments && data.arguments[1] && data.arguments[1].bidder === BIDDER_CODE) { - storeErrorEventData(data); - } -} - -/** - * Get ixdiag stored in LocalStorage and format to be added to request payload - * - * @returns {Object} Object with error codes and counts - */ -function getCachedErrors() { - if (!storage.localStorageIsEnabled()) { - return; - } - - const errors = {}; - let currentStorage; - - try { - currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}'); - } catch (e) { - logError('ix can not read ixdiag from localStorage.'); - return null; - } - - Object.keys(currentStorage).forEach((date) => { - Object.keys(currentStorage[date]).forEach((code) => { - if (typeof currentStorage[date][code] === 'number') { - errors[code] = errors[code] - ? errors[code] + currentStorage[date][code] - : currentStorage[date][code]; - } - }); - }); - - return errors; -} - /** * * Initialize IX Outstream Renderer @@ -1738,12 +1617,6 @@ export const spec = { * @return {boolean} True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - if (!hasRegisteredHandler) { - events.on(EVENTS.AUCTION_DEBUG, localStorageHandler); - events.on(EVENTS.AD_RENDER_FAILED, localStorageHandler); - hasRegisteredHandler = true; - } - const paramsVideoRef = deepAccess(bid, 'params.video'); const paramsSize = deepAccess(bid, 'params.size'); const mediaTypeBannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); @@ -1765,14 +1638,14 @@ export const spec = { // since there is an ix bidder level size, make sure its valid const ixSize = getFirstSize(paramsSize); if (!ixSize) { - logError('IX Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT }); + logError('IX Bid Adapter: size has invalid format.'); return false; } // check if the ix bidder level size, is present in ad unit level if (!includesSize(bid.sizes, ixSize) && !(includesSize(mediaTypeVideoPlayerSize, ixSize)) && !(includesSize(mediaTypeBannerSizes, ixSize))) { - logError('IX Bid Adapter: bid size is not included in ad unit sizes or player size.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED }); + logError('IX Bid Adapter: bid size is not included in ad unit sizes or player size.'); return false; } } @@ -1784,19 +1657,19 @@ export const spec = { if (bid.params.siteId !== undefined) { if (typeof bid.params.siteId !== 'string' && typeof bid.params.siteId !== 'number') { - logError('IX Bid Adapter: siteId must be string or number type.', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); + logError('IX Bid Adapter: siteId must be string or number type.'); return false; } if (typeof bid.params.siteId !== 'string' && isNaN(Number(bid.params.siteId))) { - logError('IX Bid Adapter: siteId must valid value', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); + logError('IX Bid Adapter: siteId must valid value'); return false; } } if (hasBidFloor || hasBidFloorCur) { if (!(hasBidFloor && hasBidFloorCur && isValidBidFloorParams(bid.params.bidFloor, bid.params.bidFloorCur))) { - logError('IX Bid Adapter: bidFloor / bidFloorCur parameter has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_FLOOR_INVALID_FORMAT }); + logError('IX Bid Adapter: bidFloor / bidFloorCur parameter has invalid format.'); return false; } } @@ -1815,7 +1688,7 @@ export const spec = { if (errorList.length) { errorList.forEach((err) => { - logError(err, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + logError(err); }); return false; } @@ -1997,18 +1870,6 @@ export const spec = { } }, - /** - * Covert bid param types for S2S - * @param {Object} params bid params - * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol - * @return {Object} params bid params - */ - transformBidParams: function (params, isOpenRtb) { - return convertTypes({ - 'siteID': 'number' - }, params); - }, - /** * Determine which user syncs should occur * @param {object} syncOptions diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 7655868ffc3..88cfb93850f 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -2,7 +2,7 @@ import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; import { expect } from 'chai'; import { newBidder } from 'src/adapters/bidderFactory.js'; -import { spec, storage, ERROR_CODES, FEATURE_TOGGLES, LOCAL_STORAGE_FEATURE_TOGGLES_KEY, REQUESTED_FEATURE_TOGGLES, combineImps, bidToVideoImp, bidToNativeImp, deduplicateImpExtFields, removeSiteIDs, addDeviceInfo } from '../../../modules/ixBidAdapter.js'; +import { spec, storage, FEATURE_TOGGLES, LOCAL_STORAGE_FEATURE_TOGGLES_KEY, REQUESTED_FEATURE_TOGGLES, combineImps, bidToVideoImp, bidToNativeImp, deduplicateImpExtFields, removeSiteIDs, addDeviceInfo } from '../../../modules/ixBidAdapter.js'; import { deepAccess, deepClone } from '../../../src/utils.js'; describe('IndexexchangeAdapter', function () { @@ -4867,178 +4867,6 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('LocalStorage error codes', () => { - let TODAY = new Date().toISOString().slice(0, 10); - const key = 'ixdiag'; - - let sandbox; - let setDataInLocalStorageStub; - let getDataFromLocalStorageStub; - let removeDataFromLocalStorageStub; - let localStorageValues = {}; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - setDataInLocalStorageStub = sandbox.stub(storage, 'setDataInLocalStorage').callsFake((key, value) => localStorageValues[key] = value) - getDataFromLocalStorageStub = sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => localStorageValues[key]) - removeDataFromLocalStorageStub = sandbox.stub(storage, 'removeDataFromLocalStorage').callsFake((key) => delete localStorageValues[key]) - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - }); - - afterEach(() => { - setDataInLocalStorageStub.restore(); - getDataFromLocalStorageStub.restore(); - removeDataFromLocalStorageStub.restore(); - localStorageValues = {}; - sandbox.restore(); - - config.setConfig({ - ortb2: {}, - ix: {}, - }) - }); - - it('should not log error in LocalStorage when there is no logError called.', () => { - const bid = DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]; - expect(spec.isBidRequestValid(bid)).to.be.true; - expect(localStorageValues[key]).to.be.undefined; - }); - - it('should log ERROR_CODES.BID_SIZE_INVALID_FORMAT in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.size = ['400', 100]; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.BID_SIZE_INVALID_FORMAT]: 1 } }); - }); - - it('should log ERROR_CODES.BID_SIZE_NOT_INCLUDED in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.size = [407, 100]; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.BID_SIZE_NOT_INCLUDED]: 1 } }); - }); - - it('should log ERROR_CODES.PROPERTY_NOT_INCLUDED in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.video = {}; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.PROPERTY_NOT_INCLUDED]: 4 } }); - }); - - it('should log ERROR_CODES.SITE_ID_INVALID_VALUE in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.siteId = false; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.SITE_ID_INVALID_VALUE]: 1 } }); - }); - - it('should log ERROR_CODES.BID_FLOOR_INVALID_FORMAT in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.bidFloor = true; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.BID_FLOOR_INVALID_FORMAT]: 1 } }); - }); - - it('should log ERROR_CODES.VIDEO_DURATION_INVALID in LocalStorage when there is logError called.', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.video.minduration = 1; - bid.params.video.maxduration = 0; - - expect(spec.isBidRequestValid(bid)).to.be.true; - spec.buildRequests([bid]); - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.VIDEO_DURATION_INVALID]: 2 } }); - }); - - it('should increment errors for errorCode', () => { - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.video = {}; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.PROPERTY_NOT_INCLUDED]: 4 } }); - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.PROPERTY_NOT_INCLUDED]: 8 } }); - }); - - it('should add new errorCode to ixdiag.', () => { - let bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.size = ['400', 100]; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { [ERROR_CODES.BID_SIZE_INVALID_FORMAT]: 1 } }); - - bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.siteId = false; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ - [TODAY]: { - [ERROR_CODES.BID_SIZE_INVALID_FORMAT]: 1, - [ERROR_CODES.SITE_ID_INVALID_VALUE]: 1 - } - }); - }); - - it('should clear errors with successful response', () => { - const ixdiag = { [TODAY]: { '1': 1, '3': 8, '4': 1 } }; - setDataInLocalStorageStub(key, JSON.stringify(ixdiag)); - - expect(JSON.parse(localStorageValues[key])).to.deep.equal(ixdiag); - - const request = DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]; - expect(spec.isBidRequestValid(request)).to.be.true; - - const data = { - id: '345', - imp: [ - { - id: '1a2b3c4e', - } - ], - ext: { - ixdiag: { - err: { - '4': 8 - } - } - } - }; - - const validBidRequest = DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0]; - - spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE }, { data, validBidRequest }); - - expect(localStorageValues[key]).to.be.undefined; - }); - - it('should clear errors after 7 day expiry errorCode', () => { - const EXPIRED_DATE = '2019-12-12'; - - const ixdiag = { [EXPIRED_DATE]: { '1': 1, '3': 8, '4': 1 }, [TODAY]: { '3': 8, '4': 1 } }; - setDataInLocalStorageStub(key, JSON.stringify(ixdiag)); - - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.size = ['400', 100]; - - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(JSON.parse(localStorageValues[key])[EXPIRED_DATE]).to.be.undefined; - expect(JSON.parse(localStorageValues[key])).to.deep.equal({ [TODAY]: { '1': 1, '3': 8, '4': 1 } }) - }); - - it('should not save error data into localstorage if consent is not given', () => { - config.setConfig({ deviceAccess: false }); - storage.localStorageIsEnabled.restore(); // let core manage device access - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.params.size = ['400', 100]; - expect(spec.isBidRequestValid(bid)).to.be.false; - expect(localStorageValues[key]).to.be.undefined; - }); - }); describe('combine imps test', function () { it('base test', function () { const imps = [ From 0a5e9de3edfb781c49adf11bbebdba391cac93ba Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 9 May 2024 18:46:59 +0000 Subject: [PATCH 113/147] Prebid 8.48.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a373144ebd..15543c5ecc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.48.0-pre", + "version": "8.48.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 28ce27dce05..b642b5dff4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.48.0-pre", + "version": "8.48.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From ef42addac923de9464a4180cd32e585e470382e9 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Thu, 9 May 2024 18:47:00 +0000 Subject: [PATCH 114/147] Increment version to 8.49.0-pre --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 15543c5ecc3..5198c143442 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.48.0", + "version": "8.49.0-pre", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index b642b5dff4d..6e668a9cad9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "8.48.0", + "version": "8.49.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From 37ab555c840803dde2ef4971ee53955afbdecea6 Mon Sep 17 00:00:00 2001 From: mkomorski Date: Fri, 10 May 2024 14:32:51 +0200 Subject: [PATCH 115/147] 9789 tmax/timeout set to value from bidderRequest (#11469) Co-authored-by: mkomorski Co-authored-by: Demetrio Girardi --- modules/advangelistsBidAdapter.js | 4 ++-- modules/axonixBidAdapter.js | 2 +- modules/bluebillywigBidAdapter.js | 2 +- modules/brightMountainMediaBidAdapter.js | 2 +- modules/lkqdBidAdapter.js | 2 +- modules/mgidXBidAdapter.js | 2 +- modules/oguryBidAdapter.js | 2 +- modules/rhythmoneBidAdapter.js | 2 +- modules/visxBidAdapter.js | 3 +-- test/spec/modules/advangelistsBidAdapter_spec.js | 6 +++--- test/spec/modules/bluebillywigBidAdapter_spec.js | 2 +- test/spec/modules/lkqdBidAdapter_spec.js | 2 +- test/spec/modules/mgidXBidAdapter_spec.js | 3 ++- test/spec/modules/oguryBidAdapter_spec.js | 1 + 14 files changed, 18 insertions(+), 17 deletions(-) diff --git a/modules/advangelistsBidAdapter.js b/modules/advangelistsBidAdapter.js index 8e5be83f166..a916e07a963 100755 --- a/modules/advangelistsBidAdapter.js +++ b/modules/advangelistsBidAdapter.js @@ -236,7 +236,7 @@ function createVideoRequestData(bid, bidderRequest) { }, 'at': 2, 'site': {}, - 'tmax': 3000, + 'tmax': Math.min(3000, bidderRequest.timeout), 'cur': ['USD'], 'id': bid.bidId, 'imp': [], @@ -322,7 +322,7 @@ function createBannerRequestData(bid, bidderRequest) { }, 'at': 2, 'site': {}, - 'tmax': 3000, + 'tmax': Math.min(3000, bidderRequest.timeout), 'cur': ['USD'], 'id': bid.bidId, 'imp': [], diff --git a/modules/axonixBidAdapter.js b/modules/axonixBidAdapter.js index 87c3aff444a..b1ccef155de 100644 --- a/modules/axonixBidAdapter.js +++ b/modules/axonixBidAdapter.js @@ -120,7 +120,7 @@ export const spec = { prebidVersion: '$prebid.version$', screenHeight: screen.height, screenWidth: screen.width, - tmax: config.getConfig('bidderTimeout'), + tmax: bidderRequest.timeout, ua: navigator.userAgent, }; diff --git a/modules/bluebillywigBidAdapter.js b/modules/bluebillywigBidAdapter.js index d4bde9b3f2c..0718f512cdd 100644 --- a/modules/bluebillywigBidAdapter.js +++ b/modules/bluebillywigBidAdapter.js @@ -278,7 +278,7 @@ export const spec = { const request = { id: bidderRequest.bidderRequestId, source: {tid: bidderRequest.ortb2?.source?.tid}, - tmax: BB_CONSTANTS.DEFAULT_TIMEOUT, + tmax: Math.min(BB_CONSTANTS.DEFAULT_TIMEOUT, bidderRequest.timeout), imp: imps, test: DEV_MODE ? 1 : 0, ext: { diff --git a/modules/brightMountainMediaBidAdapter.js b/modules/brightMountainMediaBidAdapter.js index 6db06744c24..98b97286631 100644 --- a/modules/brightMountainMediaBidAdapter.js +++ b/modules/brightMountainMediaBidAdapter.js @@ -31,7 +31,7 @@ export const spec = { site: buildSite(bidderRequest), device: buildDevice(), cur: [CURRENCY], - tmax: 1000, + tmax: Math.min(1000, bidderRequest.timeout), regs: buildRegs(bidderRequest), user: {}, source: {}, diff --git a/modules/lkqdBidAdapter.js b/modules/lkqdBidAdapter.js index 1dbe89f5a49..d4b1cdea0d1 100644 --- a/modules/lkqdBidAdapter.js +++ b/modules/lkqdBidAdapter.js @@ -67,7 +67,7 @@ export const spec = { }, test: 0, at: 2, - tmax: bid.params.timeout || config.getConfig('bidderTimeout') || 100, + tmax: bidderRequest.timeout, cur: ['USD'], regs: { ext: { diff --git a/modules/mgidXBidAdapter.js b/modules/mgidXBidAdapter.js index ac25a419de1..f073fb4c576 100644 --- a/modules/mgidXBidAdapter.js +++ b/modules/mgidXBidAdapter.js @@ -166,7 +166,7 @@ export const spec = { placements, coppa: config.getConfig('coppa') === true ? 1 : 0, ccpa: bidderRequest.uspConsent || undefined, - tmax: config.getConfig('bidderTimeout') + tmax: bidderRequest.timeout }; if (bidderRequest.gdprConsent) { diff --git a/modules/oguryBidAdapter.js b/modules/oguryBidAdapter.js index 9937391f6e7..3cf78da4e3a 100644 --- a/modules/oguryBidAdapter.js +++ b/modules/oguryBidAdapter.js @@ -81,7 +81,7 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { function buildRequests(validBidRequests, bidderRequest) { const openRtbBidRequestBanner = { id: bidderRequest.bidderRequestId, - tmax: DEFAULT_TIMEOUT, + tmax: Math.min(DEFAULT_TIMEOUT, bidderRequest.timeout), at: 1, regs: { ext: { diff --git a/modules/rhythmoneBidAdapter.js b/modules/rhythmoneBidAdapter.js index 749ab92c0dc..3ab8b79df81 100644 --- a/modules/rhythmoneBidAdapter.js +++ b/modules/rhythmoneBidAdapter.js @@ -161,7 +161,7 @@ function RhythmOneBidAdapter() { } }, at: 1, - tmax: 1000, + tmax: Math.min(1000, bidderRequest.timeout), regs: { ext: { gdpr: deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? Boolean(bidderRequest.gdprConsent.gdprApplies & 1) : false diff --git a/modules/visxBidAdapter.js b/modules/visxBidAdapter.js index a86c958392e..beffcf5da95 100644 --- a/modules/visxBidAdapter.js +++ b/modules/visxBidAdapter.js @@ -114,8 +114,7 @@ export const spec = { } } - const bidderTimeout = Number(config.getConfig('bidderTimeout')) || timeout; - const tmax = timeout ? Math.min(bidderTimeout, timeout) : bidderTimeout; + const tmax = timeout; const source = { ext: { wrapperType: 'Prebid_js', diff --git a/test/spec/modules/advangelistsBidAdapter_spec.js b/test/spec/modules/advangelistsBidAdapter_spec.js index 143d85a1ab6..57ad2d0e898 100755 --- a/test/spec/modules/advangelistsBidAdapter_spec.js +++ b/test/spec/modules/advangelistsBidAdapter_spec.js @@ -44,19 +44,19 @@ describe('advangelistsBidAdapter', function () { describe('spec.buildRequests', function () { it('should create a POST request for each bid', function () { const bidRequest = bidRequests[0]; - const requests = spec.buildRequests([ bidRequest ]); + const requests = spec.buildRequests([ bidRequest ], { timeout: 1000 }); expect(requests[0].method).to.equal('POST'); }); it('should create a POST request for each bid in video request', function () { const bidRequest = bidRequestsVid[0]; - const requests = spec.buildRequests([ bidRequest ]); + const requests = spec.buildRequests([ bidRequest ], { timeout: 1000 }); expect(requests[0].method).to.equal('POST'); }); it('should have domain in request', function () { const bidRequest = bidRequests[0]; - const requests = spec.buildRequests([ bidRequest ]); + const requests = spec.buildRequests([ bidRequest ], { timeout: 1000 }); expect(requests[0].data.site.domain).length !== 0; }); }); diff --git a/test/spec/modules/bluebillywigBidAdapter_spec.js b/test/spec/modules/bluebillywigBidAdapter_spec.js index 4b58e3507db..b6fb11c4750 100644 --- a/test/spec/modules/bluebillywigBidAdapter_spec.js +++ b/test/spec/modules/bluebillywigBidAdapter_spec.js @@ -298,7 +298,7 @@ describe('BlueBillywigAdapter', () => { expect(payload.id).to.exist; expect(payload.source).to.be.an('object'); expect(payload.source.tid).to.equal(validBidderRequest.ortb2.source.tid); - expect(payload.tmax).to.equal(BB_CONSTANTS.DEFAULT_TIMEOUT); + expect(payload.tmax).to.equal(3000); expect(payload.imp).to.be.an('array'); expect(payload.test).to.be.a('number'); expect(payload).to.have.nested.property('ext.prebid.targeting'); diff --git a/test/spec/modules/lkqdBidAdapter_spec.js b/test/spec/modules/lkqdBidAdapter_spec.js index 7fee9bf6e41..4ff69ce5e2a 100644 --- a/test/spec/modules/lkqdBidAdapter_spec.js +++ b/test/spec/modules/lkqdBidAdapter_spec.js @@ -140,7 +140,7 @@ describe('lkqdBidAdapter', () => { }); it('should not populate unspecified parameters', () => { - const requests = spec.buildRequests(bidRequests); + const requests = spec.buildRequests(bidRequests, { timeout: 1000 }); const serverRequestObject = requests[0]; expect(serverRequestObject.data.device.dnt).to.be.a('undefined'); diff --git a/test/spec/modules/mgidXBidAdapter_spec.js b/test/spec/modules/mgidXBidAdapter_spec.js index e0b1e1a84e9..9efaf94c954 100644 --- a/test/spec/modules/mgidXBidAdapter_spec.js +++ b/test/spec/modules/mgidXBidAdapter_spec.js @@ -83,7 +83,8 @@ describe('MGIDXBidAdapter', function () { }, refererInfo: { referer: 'https://test.com' - } + }, + timeout: 1000 }; describe('isBidRequestValid', function () { diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js index aad753571a8..ea923a18e57 100644 --- a/test/spec/modules/oguryBidAdapter_spec.js +++ b/test/spec/modules/oguryBidAdapter_spec.js @@ -80,6 +80,7 @@ describe('OguryBidAdapter', function () { bidderRequestId: 'mock-uuid', auctionId: bidRequests[0].auctionId, gdprConsent: {consentString: 'myConsentString', vendorData: {}, gdprApplies: true}, + timeout: 1000 }; describe('isBidRequestValid', function () { From b6159c056c5cdd4f7857679785ce2e07392acb36 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Mon, 13 May 2024 03:13:42 -0400 Subject: [PATCH 116/147] Various Adapters: Delete s2s transform bid params for adapters with no server equivalent (#11402) * Brightcom adapter: remove adapters (#10925) * Update adagioBidAdapter.js * Update adrelevantisBidAdapter.js * Update big-richmediaBidAdapter.js * Update craftBidAdapter.js * Update goldbachBidAdapter.js * Update winrBidAdapter.js * Update vibrantmediaBidAdapter.js * Update winrBidAdapter.js * Update goldbachBidAdapter.js * Update craftBidAdapter.js * Update adrelevantisBidAdapter.js * Revert "Brightcom adapter: remove adapters (#10925)" (#11404) This reverts commit 878f73773bc50f4c258b3c66f4bb41c6de926866. * Update goldbachBidAdapter.js * Update goldbachBidAdapter.js * Update adagioBidAdapter_spec.js * Update big-richmediaBidAdapter_spec.js * Update vibrantmediaBidAdapter_spec.js * Update vibrantmediaBidAdapter_spec.js --------- Co-authored-by: Alexandru --- modules/adagioBidAdapter.js | 14 -------- modules/adrelevantisBidAdapter.js | 26 +------------- modules/big-richmediaBidAdapter.js | 5 --- modules/craftBidAdapter.js | 22 +----------- modules/goldbachBidAdapter.js | 28 +-------------- modules/vibrantmediaBidAdapter.js | 11 ------ modules/winrBidAdapter.js | 36 +------------------ test/spec/modules/adagioBidAdapter_spec.js | 27 -------------- .../modules/big-richmediaBidAdapter_spec.js | 25 ------------- .../modules/vibrantmediaBidAdapter_spec.js | 19 +++------- 10 files changed, 8 insertions(+), 205 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 6e3c38e4e85..86f0b0e09e3 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -1275,20 +1275,6 @@ export const spec = { return syncs; }, - - /** - * Handle custom logic in s2s context - * - * @param {*} params - * @param {boolean} isOrtb Is an s2s context - * @param {*} adUnit - * @param {*} bidRequests - * @returns {object} updated params - */ - transformBidParams(params, isOrtb, adUnit, bidRequests) { - // We do not have a prebid server adapter. So let's return unchanged params. - return params; - } }; initAdagio(); diff --git a/modules/adrelevantisBidAdapter.js b/modules/adrelevantisBidAdapter.js index 68cd859e24e..7d18135f2e8 100644 --- a/modules/adrelevantisBidAdapter.js +++ b/modules/adrelevantisBidAdapter.js @@ -18,9 +18,7 @@ import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; import {find, includes} from '../src/polyfill.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -import {getANKeywordParam, transformBidderParamKeywords} from '../libraries/appnexusUtils/anKeywords.js'; -import {convertCamelToUnderscore} from '../libraries/appnexusUtils/anUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; +import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; import {chunk} from '../libraries/chunk/chunk.js'; /** @@ -187,28 +185,6 @@ export const spec = { } return bids; - }, - - transformBidParams: function(params, isOpenRtb) { - params = convertTypes({ - 'placementId': 'number', - 'keywords': transformBidderParamKeywords - }, params); - - if (isOpenRtb) { - params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; - if (params.usePaymentRule) { delete params.usePaymentRule; } - - Object.keys(params).forEach(paramKey => { - let convertedKey = convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - params[convertedKey] = params[paramKey]; - delete params[paramKey]; - } - }); - } - - return params; } }; diff --git a/modules/big-richmediaBidAdapter.js b/modules/big-richmediaBidAdapter.js index ecb1724c2a1..858dad2ffde 100644 --- a/modules/big-richmediaBidAdapter.js +++ b/modules/big-richmediaBidAdapter.js @@ -112,11 +112,6 @@ export const spec = { return baseAdapter.getUserSyncs(syncOptions, responses, gdprConsent); }, - transformBidParams: function (params, isOpenRtb) { - if (!baseAdapter.transformBidParams) { return params; } - return baseAdapter.transformBidParams(params, isOpenRtb); - }, - /** * Add element selector to javascript tracker to improve native viewability * @param {Bid} bid diff --git a/modules/craftBidAdapter.js b/modules/craftBidAdapter.js index 74e732d313f..c751a18cc84 100644 --- a/modules/craftBidAdapter.js +++ b/modules/craftBidAdapter.js @@ -6,9 +6,7 @@ import {getStorageManager} from '../src/storageManager.js'; import {ajax} from '../src/ajax.js'; import {hasPurpose1Consent} from '../src/utils/gpdr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; -import {getANKeywordParam, transformBidderParamKeywords} from '../libraries/appnexusUtils/anKeywords.js'; -import {convertCamelToUnderscore} from '../libraries/appnexusUtils/anUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; +import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; const BIDDER_CODE = 'craft'; const URL_BASE = 'https://gacraft.jp/prebid-v3'; @@ -101,24 +99,6 @@ export const spec = { } }, - transformBidParams: function(params, isOpenRtb) { - params = convertTypes({ - 'sitekey': 'string', - 'placementId': 'string', - 'keywords': transformBidderParamKeywords, - }, params); - if (isOpenRtb) { - Object.keys(params).forEach(paramKey => { - let convertedKey = convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - params[convertedKey] = params[paramKey]; - delete params[paramKey]; - } - }); - } - return params; - }, - onBidWon: function(bid) { ajax(bid._prebidWon, null, null, { method: 'POST', diff --git a/modules/goldbachBidAdapter.js b/modules/goldbachBidAdapter.js index 9f9913b7023..df0336c6cd4 100644 --- a/modules/goldbachBidAdapter.js +++ b/modules/goldbachBidAdapter.js @@ -24,9 +24,8 @@ import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {hasPurpose1Consent} from '../src/utils/gpdr.js'; import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; -import {getANKeywordParam, transformBidderParamKeywords} from '../libraries/appnexusUtils/anKeywords.js'; +import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; import {convertCamelToUnderscore, fill} from '../libraries/appnexusUtils/anUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; import {chunk} from '../libraries/chunk/chunk.js'; /** @@ -386,31 +385,6 @@ export const spec = { } }, - transformBidParams: function (params, isOpenRtb) { - params = convertTypes({ - 'member': 'string', - 'invCode': 'string', - 'placementId': 'number', - 'keywords': transformBidderParamKeywords, - 'publisherId': 'number' - }, params); - - if (isOpenRtb) { - params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; - if (params.usePaymentRule) { delete params.usePaymentRule; } - - Object.keys(params).forEach(paramKey => { - let convertedKey = convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - params[convertedKey] = params[paramKey]; - delete params[paramKey]; - } - }); - } - - return params; - }, - /** * Add element selector to javascript tracker to improve native viewability * @param {Bid} bid diff --git a/modules/vibrantmediaBidAdapter.js b/modules/vibrantmediaBidAdapter.js index 8809aae32bd..348d17d2395 100644 --- a/modules/vibrantmediaBidAdapter.js +++ b/modules/vibrantmediaBidAdapter.js @@ -97,17 +97,6 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: SUPPORTED_MEDIA_TYPES, - /** - * Transforms the 'raw' bid params into ones that this adapter can use, prior to creating the bid request. - * - * @param {object} bidParams the params to transform. - * - * @returns {object} the bid params. - */ - transformBidParams: function(bidParams) { - return bidParams; - }, - /** * Determines whether or not the given bid request is valid. For all bid requests passed to the buildRequests * function, each will have been passed to this function and this function will have returned true. diff --git a/modules/winrBidAdapter.js b/modules/winrBidAdapter.js index cf1158474b4..6cde0412071 100644 --- a/modules/winrBidAdapter.js +++ b/modules/winrBidAdapter.js @@ -14,9 +14,8 @@ import {BANNER} from '../src/mediaTypes.js'; import {find, includes} from '../src/polyfill.js'; import {getStorageManager} from '../src/storageManager.js'; import {hasPurpose1Consent} from '../src/utils/gpdr.js'; -import {getANKeywordParam, transformBidderParamKeywords} from '../libraries/appnexusUtils/anKeywords.js'; +import {getANKeywordParam} from '../libraries/appnexusUtils/anKeywords.js'; import {convertCamelToUnderscore} from '../libraries/appnexusUtils/anUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -312,39 +311,6 @@ export const spec = { ]; } }, - - transformBidParams: function (params, isOpenRtb) { - params = convertTypes( - { - member: 'string', - invCode: 'string', - placementId: 'number', - keywords: transformBidderParamKeywords, - publisherId: 'number', - }, - params - ); - - if (isOpenRtb) { - params.use_pmt_rule = - typeof params.usePaymentRule === 'boolean' - ? params.usePaymentRule - : false; - if (params.usePaymentRule) { - delete params.usePaymentRule; - } - - Object.keys(params).forEach((paramKey) => { - let convertedKey = convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - params[convertedKey] = params[paramKey]; - delete params[paramKey]; - } - }); - } - - return params; - }, }; function formatRequest(payload, bidderRequest) { diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 13c02cc9bae..19ccb49eea1 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -1465,33 +1465,6 @@ describe('Adagio bid adapter', () => { }); }); - describe('transformBidParams', function() { - it('Compute additional params in s2s mode', function() { - const adUnit = { - code: 'adunit-code', - params: { - organizationId: '1000' - } - }; - const bid01 = new BidRequestBuilder({ - 'mediaTypes': { - banner: { sizes: [[300, 250]] }, - video: { - context: 'outstream', - playerSize: [300, 250], - renderer: { - url: 'https://url.tld', - render: () => true - } - } - } - }).withParams().build(); - - const params = spec.transformBidParams({ param01: 'test' }, true, adUnit, [{ bidderCode: 'adagio', auctionId: bid01.auctionId, bids: [bid01] }]); - expect(params.param01).eq('test'); - }); - }); - describe('Adagio features when prebid in top.window', function() { it('should return all expected features when all expected bidder params are available', function() { sandbox.stub(window.top.document, 'getElementById').returns( diff --git a/test/spec/modules/big-richmediaBidAdapter_spec.js b/test/spec/modules/big-richmediaBidAdapter_spec.js index c3a9a8ef6c1..f37975c3bc1 100644 --- a/test/spec/modules/big-richmediaBidAdapter_spec.js +++ b/test/spec/modules/big-richmediaBidAdapter_spec.js @@ -271,31 +271,6 @@ describe('bigRichMediaAdapterTests', function () { }); }); - describe('transformBidParams', function() { - it('cast placementId to number', function() { - const adUnit = { - code: 'adunit-code', - params: { - placementId: '456' - } - }; - const bid = { - params: { - placementId: '456' - }, - sizes: [[300, 250]], - mediaTypes: { - banner: { sizes: [[300, 250]] } - } - }; - - const params = spec.transformBidParams({ placementId: '456' }, true, adUnit, [{ bidderCode: 'bigRichmedia', auctionId: bid.auctionId, bids: [bid] }]); - - expect(params.placement_id).to.exist; - expect(params.placement_id).to.be.a('number'); - }); - }); - describe('onBidWon', function() { it('Should not have any error', function() { const result = spec.onBidWon({}); diff --git a/test/spec/modules/vibrantmediaBidAdapter_spec.js b/test/spec/modules/vibrantmediaBidAdapter_spec.js index c6ce7d52fb3..cf9487ebf25 100644 --- a/test/spec/modules/vibrantmediaBidAdapter_spec.js +++ b/test/spec/modules/vibrantmediaBidAdapter_spec.js @@ -62,12 +62,6 @@ describe('VibrantMediaBidAdapter', function () { }); }); - describe('transformBidParams', function () { - it('transforms bid params correctly', function () { - expect(spec.transformBidParams(VALID_VIDEO_BID_PARAMS)).to.deep.equal(VALID_VIDEO_BID_PARAMS); - }); - }) - let bidRequest; beforeEach(function () { @@ -1077,13 +1071,9 @@ describe('VibrantMediaBidAdapter', function () { describe('Flow tests', function () { describe('For successive API calls to the public functions', function () { it('should succeed with one media type per bid', function () { - const transformedBannerBidParams = spec.transformBidParams(VALID_BANNER_BID_PARAMS); - const transformedVideoBidParams = spec.transformBidParams(VALID_VIDEO_BID_PARAMS); - const transformedNativeBidParams = spec.transformBidParams(VALID_NATIVE_BID_PARAMS); - const bannerBid = { bidder: 'vibrantmedia', - params: transformedBannerBidParams, + params: VALID_BANNER_BID_PARAMS, mediaTypes: { banner: { sizes: DEFAULT_BID_SIZES, @@ -1097,7 +1087,7 @@ describe('VibrantMediaBidAdapter', function () { }; const videoBid = { bidder: 'vibrantmedia', - params: transformedVideoBidParams, + params: VALID_VIDEO_BID_PARAMS, mediaTypes: { video: { context: OUTSTREAM, @@ -1112,7 +1102,7 @@ describe('VibrantMediaBidAdapter', function () { }; const nativeBid = { bidder: 'vibrantmedia', - params: transformedNativeBidParams, + params: VALID_NATIVE_BID_PARAMS, mediaTypes: { native: { image: { @@ -1178,10 +1168,9 @@ describe('VibrantMediaBidAdapter', function () { }); it('should succeed with multiple media types for a single bid', function () { - const bidParams = spec.transformBidParams(VALID_VIDEO_BID_PARAMS); const bid = { bidder: 'vibrantmedia', - params: bidParams, + params: VALID_VIDEO_BID_PARAMS, mediaTypes: { banner: { sizes: DEFAULT_BID_SIZES From 3a5f38618e112c059706e063329217fe83032701 Mon Sep 17 00:00:00 2001 From: Nick Llerandi Date: Mon, 13 May 2024 10:46:56 -0400 Subject: [PATCH 117/147] KRAK-4688: Adds support for PAAPI module (#34) (#11480) * adds support for paapi module * slight revision --- modules/kargoBidAdapter.js | 17 +++++++- test/spec/modules/kargoBidAdapter_spec.js | 49 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index f3b3166ccad..cafbbd982fa 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -196,6 +196,7 @@ function buildRequests(validBidRequests, bidderRequest) { function interpretResponse(response, bidRequest) { const bids = response.body; + const fledgeAuctionConfigs = []; const bidResponses = []; if (isEmpty(bids) || typeof bids !== 'object') { @@ -237,9 +238,23 @@ function interpretResponse(response, bidRequest) { } bidResponses.push(bidResponse); + + if (adUnit.auctionConfig) { + fledgeAuctionConfigs.push({ + bidId: bidID, + config: adUnit.auctionConfig + }) + } } - return bidResponses; + if (fledgeAuctionConfigs.length > 0) { + return { + bids: bidResponses, + fledgeAuctionConfigs + } + } else { + return bidResponses; + } } function getUserSyncs(syncOptions, _, gdprConsent, usPrivacy, gppConsent) { diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 7aa853ad902..ee89d6468a5 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1807,6 +1807,55 @@ describe('kargo adapter tests', function() { advertiserDomains: [ 'https://foo.com', 'https://bar.com' ] }); }); + + it('should return fledgeAuctionConfigs if provided in bid response', function () { + const auctionConfig = { + seller: 'https://kargo.com', + decisionLogicUrl: 'https://kargo.com/decision_logic.js', + interestGroupBuyers: ['https://some_buyer.com'], + perBuyerSignals: { + 'https://some_buyer.com': { a: 1 } + } + } + + const body = response.body; + for (const key in body) { + if (body.hasOwnProperty(key)) { + if (key % 2 !== 0) { // Add auctionConfig to every other object + body[key].auctionConfig = auctionConfig; + } + } + } + + let result = spec.interpretResponse(response, bidderRequest); + + // Test properties of bidResponses + result.bids.forEach(bid => { + expect(bid).to.have.property('requestId'); + expect(bid).to.have.property('cpm'); + expect(bid).to.have.property('width'); + expect(bid).to.have.property('height'); + expect(bid).to.have.property('ttl'); + expect(bid).to.have.property('creativeId'); + expect(bid.netRevenue).to.be.true; + expect(bid).to.have.property('meta').that.is.an('object'); + }); + + // Test properties of fledgeAuctionConfigs + expect(result.fledgeAuctionConfigs).to.have.lengthOf(3); + + const expectedBidIds = ['1', '3', '5']; // Expected bidIDs + result.fledgeAuctionConfigs.forEach(config => { + expect(config).to.have.property('bidId'); + expect(expectedBidIds).to.include(config.bidId); + + expect(config).to.have.property('config').that.is.an('object'); + expect(config.config).to.have.property('seller', 'https://kargo.com'); + expect(config.config).to.have.property('decisionLogicUrl', 'https://kargo.com/decision_logic.js'); + expect(config.config.interestGroupBuyers).to.be.an('array').that.includes('https://some_buyer.com'); + expect(config.config.perBuyerSignals).to.have.property('https://some_buyer.com').that.deep.equals({ a: 1 }); + }); + }); }); describe('getUserSyncs', function() { From 1604431acfcd64ceebb6b7fab7c02d55a24cb53a Mon Sep 17 00:00:00 2001 From: Mikael Lundin Date: Mon, 13 May 2024 20:32:22 +0200 Subject: [PATCH 118/147] Site Ext Data to kvs. (#11465) --- modules/adnuntiusBidAdapter.js | 17 +- test/spec/modules/adnuntiusBidAdapter_spec.js | 161 +++++++++++------- 2 files changed, 113 insertions(+), 65 deletions(-) diff --git a/modules/adnuntiusBidAdapter.js b/modules/adnuntiusBidAdapter.js index 9c8aa5dd5c4..060f87c0f9c 100644 --- a/modules/adnuntiusBidAdapter.js +++ b/modules/adnuntiusBidAdapter.js @@ -146,6 +146,15 @@ const storageTool = (function () { return segments } + const getKvsFromOrtb = function (ortb2) { + const siteData = deepAccess(ortb2, 'site.ext.data'); + if (siteData) { + return siteData + } else { + return null + } + } + return { refreshStorage: function (bidderRequest) { const ortb2 = bidderRequest.ortb2 || {}; @@ -163,18 +172,19 @@ const storageTool = (function () { }); } metaInternal.segments = getSegmentsFromOrtb(ortb2); + metaInternal.kv = getKvsFromOrtb(ortb2); }, saveToStorage: function (serverData, network) { setMetaInternal(serverData, network); }, getUrlRelatedData: function () { // getting the URL information is theoretically not network-specific - const { segments, usi, voidAuIdsArray } = metaInternal; - return { segments, usi, voidAuIdsArray }; + const { segments, kv, usi, voidAuIdsArray } = metaInternal; + return { segments, kv, usi, voidAuIdsArray }; }, getPayloadRelatedData: function (network) { // getting the payload data should be network-specific - const { segments, usi, userId, voidAuIdsArray, voidAuIds, ...payloadRelatedData } = getMetaDataFromLocalStorage(network).reduce((a, entry) => ({...a, [entry.key]: entry.value}), {}); + const { segments, kv, usi, userId, voidAuIdsArray, voidAuIds, ...payloadRelatedData } = getMetaDataFromLocalStorage(network).reduce((a, entry) => ({ ...a, [entry.key]: entry.value }), {}); return payloadRelatedData; } }; @@ -252,6 +262,7 @@ export const spec = { } const targeting = bid.params.targeting || {}; + if (urlRelatedMetaData.kv) targeting.kv = urlRelatedMetaData.kv; const adUnit = { ...targeting, auId: bid.params.auId, targetId: bid.params.targetId || bid.bidId }; const maxDeals = Math.max(0, Math.min(bid.params.maxDeals || 0, MAXIMUM_DEALS_LIMIT)); if (maxDeals > 0) { diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js index cad5e9ea1cf..c288bfb4f12 100644 --- a/test/spec/modules/adnuntiusBidAdapter_spec.js +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -1,18 +1,18 @@ // import or require modules necessary for the test, e.g.: -import {expect} from 'chai'; // may prefer 'assert' in place of 'expect' -import {misc, spec} from 'modules/adnuntiusBidAdapter.js'; -import {newBidder} from 'src/adapters/bidderFactory.js'; -import {config} from 'src/config.js'; +import { expect } from 'chai'; // may prefer 'assert' in place of 'expect' +import { misc, spec } from 'modules/adnuntiusBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; -import {getStorageManager} from 'src/storageManager.js'; -import {getGlobal} from '../../../src/prebidGlobal'; +import { getStorageManager } from 'src/storageManager.js'; +import { getGlobal } from '../../../src/prebidGlobal'; -describe('adnuntiusBidAdapter', function() { +describe('adnuntiusBidAdapter', function () { const URL = 'https://ads.adnuntius.delivery/i?tzo='; const EURO_URL = 'https://europe.delivery.adnuntius.com/i?tzo='; const usi = utils.generateUUID() - const meta = [{key: 'valueless'}, {value: 'keyless'}, {key: 'voidAuIds'}, {key: 'voidAuIds', value: [{auId: '11118b6bc', exp: misc.getUnixTimestamp()}, {exp: misc.getUnixTimestamp(1)}]}, {key: 'valid-withnetwork', value: 'also-valid-network', network: 'the-network', exp: misc.getUnixTimestamp(1)}, {key: 'valid', value: 'also-valid', exp: misc.getUnixTimestamp(1)}, {key: 'expired', value: 'fwefew', exp: misc.getUnixTimestamp()}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp(), network: 'adnuntius'}, {key: 'usi', value: usi, exp: misc.getUnixTimestamp(100), network: 'adnuntius'}, {key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp()}] + const meta = [{ key: 'valueless' }, { value: 'keyless' }, { key: 'voidAuIds' }, { key: 'voidAuIds', value: [{ auId: '11118b6bc', exp: misc.getUnixTimestamp() }, { exp: misc.getUnixTimestamp(1) }] }, { key: 'valid-withnetwork', value: 'also-valid-network', network: 'the-network', exp: misc.getUnixTimestamp(1) }, { key: 'valid', value: 'also-valid', exp: misc.getUnixTimestamp(1) }, { key: 'expired', value: 'fwefew', exp: misc.getUnixTimestamp() }, { key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp(), network: 'adnuntius' }, { key: 'usi', value: usi, exp: misc.getUnixTimestamp(100), network: 'adnuntius' }, { key: 'usi', value: 'should be skipped because timestamp', exp: misc.getUnixTimestamp() }] let storage; // need this to make the restore work correctly -- something to do with stubbing static prototype methods @@ -24,7 +24,7 @@ describe('adnuntiusBidAdapter', function() { storageAllowed: true } }; - storage = getStorageManager({bidderCode: 'adnuntius'}); + storage = getStorageManager({ bidderCode: 'adnuntius' }); }); beforeEach(() => { @@ -35,7 +35,7 @@ describe('adnuntiusBidAdapter', function() { getGlobal().bidderSettings = {}; }); - afterEach(function() { + afterEach(function () { config.resetConfig(); if (stub1.restore) { @@ -453,20 +453,20 @@ describe('adnuntiusBidAdapter', function() { } } - describe('inherited functions', function() { - it('exists and is a function', function() { + 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() { + 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() { + describe('buildRequests', function () { + it('Test requests', function () { stub1 = sinon.stub(URLSearchParams.prototype, 'has').callsFake(() => { return true; }); @@ -485,7 +485,7 @@ describe('adnuntiusBidAdapter', function() { expect(request[0].data).to.equal('{"adUnits":[{"auId":"000000000008b6bc","targetId":"123","maxDeals":1,"dimensions":[[640,480],[600,400]]},{"auId":"0000000000000551","targetId":"adn-0000000000000551","dimensions":[[1640,1480],[1600,1400]]}]}'); }); - it('Test requests with no local storage', function() { + it('Test requests with no local storage', function () { storage.setDataInLocalStorage('adn.metaData', JSON.stringify([{}])); const request = spec.buildRequests(bidderRequests, {}); expect(request.length).to.equal(1); @@ -504,8 +504,8 @@ describe('adnuntiusBidAdapter', function() { expect(request2[0].url).to.equal(ENDPOINT_URL_BASE); }); - it('Test request changes for voided au ids', function() { - storage.setDataInLocalStorage('adn.metaData', JSON.stringify([{key: 'voidAuIds', value: [{auId: '11118b6bc', exp: misc.getUnixTimestamp(1)}, {auId: '0000000000000023', exp: misc.getUnixTimestamp(1)}]}])); + it('Test request changes for voided au ids', function () { + storage.setDataInLocalStorage('adn.metaData', JSON.stringify([{ key: 'voidAuIds', value: [{ auId: '11118b6bc', exp: misc.getUnixTimestamp(1) }, { auId: '0000000000000023', exp: misc.getUnixTimestamp(1) }] }])); const bRequests = bidderRequests.concat([{ bidId: 'adn-11118b6bc', bidder: 'adnuntius', @@ -556,7 +556,7 @@ describe('adnuntiusBidAdapter', function() { expect(request[0].data).to.equal('{"adUnits":[{"auId":"000000000008b6bc","targetId":"123","maxDeals":1,"dimensions":[[640,480],[600,400]]},{"auId":"0000000000000551","targetId":"adn-0000000000000551","dimensions":[[1640,1480],[1600,1400]]},{"auId":"13","targetId":"adn-13","dimensions":[[164,140],[10,1400]]}]}'); }); - it('Test Video requests', function() { + it('Test Video requests', function () { const request = spec.buildRequests(videoBidderRequest, {}); expect(request.length).to.equal(1); expect(request[0]).to.have.property('bid'); @@ -566,12 +566,12 @@ describe('adnuntiusBidAdapter', function() { expect(request[0].url).to.equal(ENDPOINT_URL_VIDEO); }); - it('should pass segments if available in config', function() { + it('should pass segments if available in config', function () { const ortb2 = { user: { data: [{ name: 'adnuntius', - segment: [{id: 'segment1'}, {id: 'segment2'}, {invalidSegment: 'invalid'}, {id: 123}, {id: ['3332']}] + segment: [{ id: 'segment1' }, { id: 'segment2' }, { invalidSegment: 'invalid' }, { id: 123 }, { id: ['3332'] }] }, { name: 'other', @@ -580,18 +580,55 @@ describe('adnuntiusBidAdapter', function() { } }; - const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, {ortb2})); + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_SEGMENTS); }); - it('should skip segments in config if not either id or array of strings', function() { + it('should pass site data ext as key values to ad server', function () { + const ortb2 = { + site: { + ext: { + data: { + '12345': 'true', + '45678': 'true' + } + } + } + }; + + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('url') + const data = JSON.parse(request[0].data); + expect(data.adUnits[0].kv).to.have.property('12345'); + expect(data.adUnits[0].kv['12345']).to.equal('true'); + expect(data.adUnits[0].kv).to.have.property('45678'); + expect(data.adUnits[0].kv['45678']).to.equal('true'); + }); + + it('should skip passing site data ext if missing', function () { + const ortb2 = { + site: { + ext: { + } + } + }; + + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('url') + const data = JSON.parse(request[0].data); + expect(data.adUnits[0]).to.not.have.property('kv'); + }); + + it('should skip segments in config if not either id or array of strings', function () { const ortb2 = { user: { data: [{ name: 'adnuntius', - segment: [{id: 'segment1'}, {id: 'segment2'}, {id: 'segment3'}] + segment: [{ id: 'segment1' }, { id: 'segment2' }, { id: 'segment3' }] }, { name: 'other', @@ -602,34 +639,34 @@ describe('adnuntiusBidAdapter', function() { } }; - const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, {ortb2})); + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_SEGMENTS); }); }); - describe('user privacy', function() { - it('should send GDPR Consent data if gdprApplies', function() { - let request = spec.buildRequests(bidderRequests, {gdprConsent: {gdprApplies: true, consentString: 'consentString'}}); + describe('user privacy', function () { + it('should send GDPR Consent data if gdprApplies', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: true, consentString: 'consentString' } }); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_CONSENT); }); - it('should not send GDPR Consent data if gdprApplies equals undefined', function() { - let request = spec.buildRequests(bidderRequests, {gdprConsent: {gdprApplies: undefined, consentString: 'consentString'}}); + it('should not send GDPR Consent data if gdprApplies equals undefined', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: undefined, consentString: 'consentString' } }); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL); }); - it('should pass segments if available in config', function() { + it('should pass segments if available in config', function () { const ortb2 = { user: { data: [{ name: 'adnuntius', - segment: [{id: 'segment1'}, {id: 'segment2'}] + segment: [{ id: 'segment1' }, { id: 'segment2' }] }, { name: 'other', @@ -638,18 +675,18 @@ describe('adnuntiusBidAdapter', function() { } } - const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, {ortb2})); + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_SEGMENTS); }); - it('should skip segments in config if not either id or array of strings', function() { + it('should skip segments in config if not either id or array of strings', function () { const ortb2 = { user: { data: [{ name: 'adnuntius', - segment: [{id: 'segment1'}, {id: 'segment2'}, {id: 'segment3'}] + segment: [{ id: 'segment1' }, { id: 'segment2' }, { id: 'segment3' }] }, { name: 'other', @@ -660,20 +697,20 @@ describe('adnuntiusBidAdapter', function() { } }; - const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, {ortb2})); + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_SEGMENTS); }); - it('should user user ID if present in ortb2.user.id field', function() { + it('should user user ID if present in ortb2.user.id field', function () { const ortb2 = { user: { id: usi } }; - const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, {ortb2})); + const request = config.runWithBidder('adnuntius', () => spec.buildRequests(bidderRequests, { ortb2 })); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL); @@ -721,24 +758,24 @@ describe('adnuntiusBidAdapter', function() { }); }); - describe('user privacy', function() { - it('should send GDPR Consent data if gdprApplies', function() { - let request = spec.buildRequests(bidderRequests, {gdprConsent: {gdprApplies: true, consentString: 'consentString'}}); + describe('user privacy', function () { + it('should send GDPR Consent data if gdprApplies', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: true, consentString: 'consentString' } }); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL_CONSENT); }); - it('should not send GDPR Consent data if gdprApplies equals undefined', function() { - let request = spec.buildRequests(bidderRequests, {gdprConsent: {gdprApplies: undefined, consentString: 'consentString'}}); + it('should not send GDPR Consent data if gdprApplies equals undefined', function () { + let request = spec.buildRequests(bidderRequests, { gdprConsent: { gdprApplies: undefined, consentString: 'consentString' } }); expect(request.length).to.equal(1); expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL); }); }); - describe('use cookie', function() { - it('should send noCookie in url if set to false.', function() { + describe('use cookie', function () { + it('should send noCookie in url if set to false.', function () { config.setBidderConfig({ bidders: ['adnuntius'], config: { @@ -753,8 +790,8 @@ describe('adnuntiusBidAdapter', function() { }); }); - describe('validate auId', function() { - it('should fail when auId is not hexadecimal', function() { + describe('validate auId', function () { + it('should fail when auId is not hexadecimal', function () { const invalidRequest = { bidId: 'adn-000000000008b6bc', bidder: 'adnuntius', @@ -766,7 +803,7 @@ describe('adnuntiusBidAdapter', function() { expect(valid).to.equal(false); }); - it('should pass when auId is hexadecimal', function() { + it('should pass when auId is hexadecimal', function () { const invalidRequest = { bidId: 'adn-000000000008b6bc', bidder: 'adnuntius', @@ -779,8 +816,8 @@ describe('adnuntiusBidAdapter', function() { }); }); - describe('request deals', function() { - it('Should set max deals.', function() { + describe('request deals', function () { + it('Should set max deals.', function () { config.setBidderConfig({ bidders: ['adnuntius'] }); @@ -797,7 +834,7 @@ describe('adnuntiusBidAdapter', function() { expect(bidderRequests[1].params).to.not.have.property('maxBids'); expect(data.adUnits[1].maxDeals).to.equal(undefined); }); - it('Should allow a maximum of 5 deals.', function() { + it('Should allow a maximum of 5 deals.', function () { config.setBidderConfig({ bidders: ['adnuntius'], }); @@ -820,7 +857,7 @@ describe('adnuntiusBidAdapter', function() { expect(data.adUnits.length).to.equal(1); expect(data.adUnits[0].maxDeals).to.equal(5); }); - it('Should allow a minumum of 0 deals.', function() { + it('Should allow a minumum of 0 deals.', function () { config.setBidderConfig({ bidders: ['adnuntius'], }); @@ -843,7 +880,7 @@ describe('adnuntiusBidAdapter', function() { expect(data.adUnits.length).to.equal(1); expect(data.adUnits[0].maxDeals).to.equal(undefined); }); - it('Should set max deals using bidder config.', function() { + it('Should set max deals using bidder config.', function () { config.setBidderConfig({ bidders: ['adnuntius'], config: { @@ -856,7 +893,7 @@ describe('adnuntiusBidAdapter', function() { expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL + '&ds=2'); }); - it('Should allow a maximum of 5 deals when using bidder config.', function() { + it('Should allow a maximum of 5 deals when using bidder config.', function () { config.setBidderConfig({ bidders: ['adnuntius'], config: { @@ -869,7 +906,7 @@ describe('adnuntiusBidAdapter', function() { expect(request[0]).to.have.property('url') expect(request[0].url).to.equal(ENDPOINT_URL + '&ds=5'); }); - it('Should allow a minimum of 0 deals when using bidder config.', function() { + it('Should allow a minimum of 0 deals when using bidder config.', function () { config.setBidderConfig({ bidders: ['adnuntius'], config: { @@ -885,8 +922,8 @@ describe('adnuntiusBidAdapter', function() { }); }); - describe('interpretResponse', function() { - it('should return valid response when passed valid server response', function() { + describe('interpretResponse', function () { + it('should return valid response when passed valid server response', function () { config.setBidderConfig({ bidders: ['adnuntius'], config: { @@ -960,7 +997,7 @@ describe('adnuntiusBidAdapter', function() { expect(randomApiEntry.exp).to.be.greaterThan(misc.getUnixTimestamp(90)); }); - it('should not process valid response when passed alt bidder that is an adndeal', function() { + it('should not process valid response when passed alt bidder that is an adndeal', function () { const altBidder = { bid: [ { @@ -978,7 +1015,7 @@ describe('adnuntiusBidAdapter', function() { serverResponse.body.adUnits[0].deals = deals; }); - it('should return valid response when passed alt bidder', function() { + it('should return valid response when passed alt bidder', function () { const altBidder = { bid: [ { @@ -1015,8 +1052,8 @@ describe('adnuntiusBidAdapter', function() { }); }); - describe('interpretVideoResponse', function() { - it('should return valid response when passed valid server response', function() { + describe('interpretVideoResponse', function () { + it('should return valid response when passed valid server response', function () { const interpretedResponse = spec.interpretResponse(serverVideoResponse, videoBidRequest); const ad = serverVideoResponse.body.adUnits[0].ads[0] const deal = serverVideoResponse.body.adUnits[0].deals[0] From 48c884c7ded1ac420b8bd125df4477cc8aa246de Mon Sep 17 00:00:00 2001 From: Chris Huie Date: Tue, 14 May 2024 11:19:30 -0600 Subject: [PATCH 119/147] Remove Email (#11484) --- modules/waardexBidAdapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/waardexBidAdapter.md b/modules/waardexBidAdapter.md index 6978281d40e..165321c2057 100644 --- a/modules/waardexBidAdapter.md +++ b/modules/waardexBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: Waardex Bid Adapter Module Type: Bidder Adapter -Maintainer: info@prebid.org +Maintainer: ``` # Description From ddb66fd245265214e6333c4807046f4facc11517 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 14 May 2024 19:31:26 +0200 Subject: [PATCH 120/147] AdagioBidAdapter: validate `plcmt` video param () (#11487) --- modules/adagioBidAdapter.js | 7 ++++++- test/spec/modules/adagioBidAdapter_spec.js | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 86f0b0e09e3..ac2e578de5c 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -64,7 +64,11 @@ export const ORTB_VIDEO_PARAMS = { 'w': (value) => isInteger(value), 'h': (value) => isInteger(value), 'startdelay': (value) => isInteger(value), - 'placement': (value) => isInteger(value), + 'placement': (value) => { + logWarn(LOG_PREFIX, 'The OpenRTB video param `placement` is deprecated and should not be used anymore.'); + return isInteger(value) + }, + 'plcmt': (value) => isInteger(value), 'linearity': (value) => isInteger(value), 'skip': (value) => [1, 0].includes(value), 'skipmin': (value) => isInteger(value), @@ -964,6 +968,7 @@ export const spec = { autoFillParams(bid); + // Note: `bid.params.placement` is not related to the video param `placement`. if (!(bid.params.organizationId && bid.params.site && bid.params.placement)) { logWarn(`${LOG_PREFIX} at least one required param is missing.`); // internal.enqueue(debugData()); diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 19ccb49eea1..b11c0ab4a8e 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -493,7 +493,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: 3, + plcmt: 4, protocols: [8] } }).build(); @@ -508,7 +508,7 @@ describe('Adagio bid adapter', () => { skipafter: 4, minduration: 10, maxduration: 30, - placement: 3, + plcmt: 4, protocols: [8], w: 300, h: 250 From 0612325a0db1991a62aa92304959ee0cb6e3092f Mon Sep 17 00:00:00 2001 From: Ilia Medvedev Date: Wed, 15 May 2024 01:03:05 +0400 Subject: [PATCH 121/147] AdsYield Bid Adapter: move to limelight (#11483) --- modules/admixerBidAdapter.js | 1 - modules/limelightDigitalBidAdapter.js | 2 +- test/spec/modules/admixerBidAdapter_spec.js | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/modules/admixerBidAdapter.js b/modules/admixerBidAdapter.js index f5f0b5bf665..de7b941d614 100644 --- a/modules/admixerBidAdapter.js +++ b/modules/admixerBidAdapter.js @@ -10,7 +10,6 @@ const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.2.aspx'; const ALIASES = [ {code: 'go2net', endpoint: 'https://ads.go2net.com.ua/prebid.1.2.aspx'}, 'adblender', - {code: 'adsyield', endpoint: 'https://ads.adsyield.com/prebid.1.2.aspx'}, {code: 'futureads', endpoint: 'https://ads.futureads.io/prebid.1.2.aspx'}, {code: 'smn', endpoint: 'https://ads.smn.rs/prebid.1.2.aspx'}, {code: 'admixeradx', endpoint: 'https://inv-nets.admixer.net/adxprebid.1.2.aspx'}, diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index c816f800fda..6c589f536c2 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -32,7 +32,7 @@ function isBidResponseValid(bid) { export const spec = { code: BIDDER_CODE, - aliases: ['pll', 'iionads', 'apester'], + aliases: ['pll', 'iionads', 'apester', 'adsyield'], supportedMediaTypes: [BANNER, VIDEO], /** diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index 85538efc957..e254d2f2ff7 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -175,12 +175,6 @@ describe('AdmixerAdapter', function () { expect(request.url).to.equal('https://inv-nets.admixer.net/prebid.1.2.aspx'); expect(request.method).to.equal('POST'); }); - it('build request for adsyield', function () { - const requestParams = requestParamsFor('adsyield'); - const request = spec.buildRequests(requestParams.validRequest, requestParams.bidderRequest); - expect(request.url).to.equal('https://ads.adsyield.com/prebid.1.2.aspx'); - expect(request.method).to.equal('POST'); - }); it('build request for futureads', function () { const requestParams = requestParamsFor('futureads'); const request = spec.buildRequests(requestParams.validRequest, requestParams.bidderRequest); From f47540b629f265c2ad5214162c46c1df851a25ac Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Wed, 15 May 2024 14:07:24 +0300 Subject: [PATCH 122/147] Vidazoo Bid Adapter : rector gpid value assignment (#11491) * Refactor gpid value assignment in vidazooBidAdapter. * Refactor gpid value assignment in vidazooBidAdapter. --- modules/vidazooBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index ea1555e5327..c5e35c6b138 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -83,7 +83,7 @@ function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout const ptrace = getCacheOpt(); const isStorageAllowed = bidderSettings.get(BIDDER_CODE, 'storageAllowed'); - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid') || deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', ''); const cat = deepAccess(bidderRequest, 'ortb2.site.cat', []); const pagecat = deepAccess(bidderRequest, 'ortb2.site.pagecat', []); const contentData = deepAccess(bidderRequest, 'ortb2.site.content.data', []); From 7a507b7601153d14731d574a9d45e6cc3f814166 Mon Sep 17 00:00:00 2001 From: Saar Amrani Date: Wed, 15 May 2024 14:15:44 +0300 Subject: [PATCH 123/147] Refactor gpid extraction logic. (#11492) --- modules/kueezRtbBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kueezRtbBidAdapter.js b/modules/kueezRtbBidAdapter.js index 264592cd7d6..ba33f3ade9a 100644 --- a/modules/kueezRtbBidAdapter.js +++ b/modules/kueezRtbBidAdapter.js @@ -65,7 +65,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) { const pId = extractPID(params); const subDomain = extractSubDomain(params); - const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid', deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', '')); + const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid') || deepAccess(bid, 'ortb2Imp.ext.data.pbadslot', ''); if (isFn(bid.getFloor)) { const floorInfo = bid.getFloor({ From 85cee26c5f9723cac86c73493dfa952939f0663d Mon Sep 17 00:00:00 2001 From: sangarbe Date: Wed, 15 May 2024 14:13:54 +0200 Subject: [PATCH 124/147] Seedtag Bid Adapter : allows sending bcat and badv ortb2 params in request payload (#11490) * sends bcat and badv ortb2 params in request payload * adds tests for bcat and badv --- modules/seedtagBidAdapter.js | 8 +++++ test/spec/modules/seedtagBidAdapter_spec.js | 36 +++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index e17ff1301a3..284e62e70fe 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -324,6 +324,14 @@ export const spec = { payload.user.eids = validBidRequests[0].userIdAsEids } + if (bidderRequest.ortb2?.bcat) { + payload.bcat = bidderRequest.ortb2?.bcat + } + + if (bidderRequest.ortb2?.badv) { + payload.badv = bidderRequest.ortb2?.badv + } + const payloadString = JSON.stringify(payload); return { diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 2012c78d239..ed3e2c9be0b 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -590,6 +590,42 @@ describe('Seedtag Adapter', function () { expect(data.user.eids).to.deep.equal(userIdAsEids); }) }); + + describe('Blocking params', function () { + it('should add bcat param to payload when bidderRequest has ortb2 bcat info', function () { + const blockedCategories = ['IAB1', 'IAB2'] + var ortb2 = { + bcat: blockedCategories + } + bidderRequest['ortb2'] = ortb2 + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.bcat).to.deep.equal(blockedCategories); + }); + + it('should add badv param to payload when bidderRequest has ortb2 badv info', function () { + const blockedAdvertisers = ['blocked.com'] + var ortb2 = { + badv: blockedAdvertisers + } + bidderRequest['ortb2'] = ortb2 + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.badv).to.deep.equal(blockedAdvertisers); + }); + + it('should not add bcat and badv params to payload when bidderRequest does not have ortb2 badv and bcat info', function () { + var ortb2 = {} + bidderRequest['ortb2'] = ortb2 + + const request = spec.buildRequests(validBidRequests, bidderRequest); + const data = JSON.parse(request.data); + expect(data.bcat).to.be.undefined; + expect(data.badv).to.be.undefined; + }); + }); }) describe('interpret response method', function () { it('should return a void array, when the server response are not correct.', function () { From 542694585269e3796d65205283783915a8cf9f70 Mon Sep 17 00:00:00 2001 From: rcheptanariu <35690143+rcheptanariu@users.noreply.github.com> Date: Wed, 15 May 2024 15:31:45 +0300 Subject: [PATCH 125/147] Invibes Bid Adapter : reading page referer and cookie handlid (#11477) * InvibesBidAdapter - added cookie and referer read * InvibesBidAdapter - unit tests * InvibesBidAdapter - tab fix * InvibesBidAdapter - null checks * InvibesBidAdapter - fix { after if --- modules/invibesBidAdapter.js | 16 ++++++-- test/spec/modules/invibesBidAdapter_spec.js | 44 +++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/modules/invibesBidAdapter.js b/modules/invibesBidAdapter.js index 2c37c0edad9..7ba2b8225b0 100644 --- a/modules/invibesBidAdapter.js +++ b/modules/invibesBidAdapter.js @@ -14,7 +14,7 @@ const CONSTANTS = { SYNC_ENDPOINT: 'https://k.r66net.com/GetUserSync', TIME_TO_LIVE: 300, DEFAULT_CURRENCY: 'EUR', - PREBID_VERSION: 11, + PREBID_VERSION: 12, METHOD: 'GET', INVIBES_VENDOR_ID: 436, USERID_PROVIDERS: ['pubcid', 'pubProvidedId', 'uid2', 'zeotapIdPlus', 'id5id'], @@ -40,7 +40,7 @@ export const spec = { buildRequests: buildRequest, /** * @param {*} responseObj - * @param {requestParams} bidRequests + * @param {*} requestParams * @return {Bid[]} An array of bids which */ interpretResponse: function (responseObj, requestParams) { @@ -131,7 +131,6 @@ function buildRequest(bidRequests, bidderRequest) { window.invibes.placementIds.push(bidRequest.params.placementId); - _placementIds.push(bidRequest.params.placementId); _placementIds.push(bidRequest.params.placementId); _adUnitCodes.push(bidRequest.adUnitCode); _domainId = _domainId || bidRequest.params.domainId; @@ -180,9 +179,18 @@ function buildRequest(bidRequests, bidderRequest) { isLocalStorageEnabled: storage.hasLocalStorage(), preventPageViewEvent: preventPageViewEvent, isPlacementRefresh: isPlacementRefresh, - isInfiniteScrollPage: isInfiniteScrollPage, + isInfiniteScrollPage: isInfiniteScrollPage }; + if (bidderRequest.refererInfo && bidderRequest.refererInfo.ref) { + data.pageReferrer = bidderRequest.refererInfo.ref.substring(0, 300); + } + + let hid = invibes.getCookie('handIid'); + if (hid) { + data.handIid = hid; + } + let lid = readFromLocalStorage('ivbsdid'); if (!lid) { let str = invibes.getCookie('ivbsdid'); diff --git a/test/spec/modules/invibesBidAdapter_spec.js b/test/spec/modules/invibesBidAdapter_spec.js index 056255c7738..ba2d8f5255a 100644 --- a/test/spec/modules/invibesBidAdapter_spec.js +++ b/test/spec/modules/invibesBidAdapter_spec.js @@ -560,6 +560,50 @@ describe('invibesBidAdapter:', function () { expect(request.data.lId).to.exist; }); + it('does not send handIid when it doesnt exist in cookie', function () { + top.window.invibes.optIn = 1; + top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false]; + global.document.cookie = ''; + let bidderRequest = { + gdprConsent: { + vendorData: { + vendorConsents: { + 436: true + } + } + }, + refererInfo: { + page: 'https://randomWeb.com?someFakePara=fakeValue&secondParam=secondValue' + } + }; + SetBidderAccess(); + + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.handIid).to.not.exist; + }); + + it('sends handIid when comes on cookie', function () { + top.window.invibes.optIn = 1; + top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false]; + global.document.cookie = 'handIid=abcdefghijkk'; + let bidderRequest = { + gdprConsent: { + vendorData: { + vendorConsents: { + 436: true + } + } + }, + refererInfo: { + page: 'https://randomWeb.com?someFakePara=fakeValue&secondParam=secondValue' + } + }; + SetBidderAccess(); + + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.handIid).to.equal('abcdefghijkk'); + }); + it('should send purpose 1', function () { let bidderRequest = { gdprConsent: { From dd398f171c77b72801798fd1b92bd7ea9bf8c03e Mon Sep 17 00:00:00 2001 From: Dejan Grbavcic Date: Thu, 16 May 2024 12:48:05 +0200 Subject: [PATCH 126/147] Brid Bid Adapter: switching to plcmt (#11502) * TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo bid adapter * TargetVideo Bid Adapter: Add GDPR/USP support * TargetVideo Bid Adapter: Add GDPR/USP support tests * TargetVideo Bid Adapter: Updating margin rule * Add Brid bid adapter * Brid adapter requested changes * BridBidAdapter: switching to plcmt --- modules/bridBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/bridBidAdapter.js b/modules/bridBidAdapter.js index e784ea517ac..f3fe1541886 100644 --- a/modules/bridBidAdapter.js +++ b/modules/bridBidAdapter.js @@ -15,7 +15,7 @@ const ENDPOINT_URL = 'https://pbs.prebrid.tv/openrtb2/auction'; const GVLID = 934; const TIME_TO_LIVE = 300; const VIDEO_PARAMS = [ - 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement', + 'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'plcmt', 'playbackmethod', 'protocols', 'startdelay' ]; From 2c55a6a080c1981d74e85bb7e0d9709a620f97ec Mon Sep 17 00:00:00 2001 From: prebidtappx <77485538+prebidtappx@users.noreply.github.com> Date: Thu, 16 May 2024 12:59:09 +0200 Subject: [PATCH 127/147] Tappx Bid Adapter : change to plcmt (#11504) * Tappx Refactor: Optimizing and adding more checkers and tests * Fix: fixed site referrer for iframes using external sites error #13231 * Adapt new placement params --------- Co-authored-by: Jordi Arnau Co-authored-by: Felipe N --- modules/tappxBidAdapter.js | 6 +++--- modules/tappxBidAdapter.md | 2 +- test/spec/modules/tappxBidAdapter_spec.js | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/tappxBidAdapter.js b/modules/tappxBidAdapter.js index f0c275acfb6..b2939bffedf 100644 --- a/modules/tappxBidAdapter.js +++ b/modules/tappxBidAdapter.js @@ -5,8 +5,8 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; -import {parseDomain} from '../src/refererDetection.js'; -import {getGlobal} from '../src/prebidGlobal.js'; +import { parseDomain } from '../src/refererDetection.js'; +import { getGlobal } from '../src/prebidGlobal.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -39,7 +39,7 @@ const VIDEO_CUSTOM_PARAMS = { 'h': DATA_TYPES.NUMBER, 'battr': DATA_TYPES.ARRAY, 'linearity': DATA_TYPES.NUMBER, - 'placement': DATA_TYPES.NUMBER, + 'plcmt': DATA_TYPES.NUMBER, 'minbitrate': DATA_TYPES.NUMBER, 'maxbitrate': DATA_TYPES.NUMBER, 'skip': DATA_TYPES.NUMBER diff --git a/modules/tappxBidAdapter.md b/modules/tappxBidAdapter.md index 55f18531f28..e0d1816cf6a 100644 --- a/modules/tappxBidAdapter.md +++ b/modules/tappxBidAdapter.md @@ -80,7 +80,7 @@ Ads sizes available: [300,250], [320,50], [320,480], [480,320], [728,90], [768,1 protocols: [ 2, 3 ], // Optional battr: [ 13, 14 ], // Optional linearity: 1, // Optional - placement: 2, // Optional + plcmt: 2, // Optional minbitrate: 10, // Optional maxbitrate: 10 // Optional }, diff --git a/test/spec/modules/tappxBidAdapter_spec.js b/test/spec/modules/tappxBidAdapter_spec.js index 46fac8de1e2..1dd3f1b3c50 100644 --- a/test/spec/modules/tappxBidAdapter_spec.js +++ b/test/spec/modules/tappxBidAdapter_spec.js @@ -124,8 +124,8 @@ const c_CONSENTSTRING = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; const c_VALIDBIDREQUESTS = [{'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com\/rtb\/v2\/', 'tappxkey': 'pub-1234-android-1234', 'endpoint': 'ZZ1234PBJS', 'bidfloor': 0.005, 'test': 1}, 'userId': {'haloId': '0000x179MZAzMqUWsFonu7Drm3eDDBMYtj5SPoWQnl89Upk3WTlCvEnKI9SshX0p6eFJ7otPYix179MZAzMqUWsFonu7Drm3eDDBMYtj5SPoWQnl89Upk3WTlCvEnKI9SshX0p6e', 'id5id': {'uid': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_rEXbz6UYtYEJelYrDaZOLkh8WcF9J0ZHmEHFKZEBlLXsgP6xqXU3BCj4Ay0Z6fw_jSOaHxMHwd-voRHqFA4Q9NwAxFcVLyPWnNGZ9VbcSAPos1wupq7Xu3MIm-Bw_0vxjhZdWNy4chM9x3i', 'ext': {'linkType': 0}}, 'intentIqId': 'GIF89a\u0000\u0000\u0000\u0000�\u0000\u0000���\u0000\u0000\u0000?�\u0000\u0000\u0000\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000A\u0000\u0000;', 'lotamePanoramaId': 'xTtLUY7GwqX2MMqSHo9RQ2YUOIBFhlASOR43I9KjvgtcrxIys3RxME96M02LTjWR', 'parrableId': {'eid': '02.YoqC9lWZh8.C8QTSiJTNgI6Pp0KCM5zZgEgwVMSsVP5W51X8cmiUHQESq9WRKB4nreqZJwsWIcNKlORhG4u25Wm6lmDOBmQ0B8hv0KP6uVQ97aouuH52zaz2ctVQTORUKkErPRPcaCJ7dKFcrNoF2i6WOR0S5Nk'}, 'pubcid': 'b1254-152f-12F5-5698-dI1eljK6C7WA', 'pubProvidedId': [{'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}, {'source': '3rdpartyprovided.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 3, 'ext': {'stype': 'sha256email'}}]}]}, 'userIdAsEids': [{'source': 'audigent.com', 'uids': [{'id': '0000fgclxw05ycn0608xiyi90bwpa0c0evvlif0hv1x0i0ku88il0ntek0o0qskvir0trr70u0wqxiix0zq3u1012pa5j315ogh1618nmsj91bmt41c1elzfjf1hl5r1i1kkc2jl', 'atype': 1}]}, {'source': 'id5-sync.com', 'uids': [{'id': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_qpoXJUngedfpNva812If1fHEqHHkamLC89txVxk1i9WGqeQrTX97HFCgv9QDa1M_bkHUBsAWFm-D5r1rYrsfMFFiyqwCAEzqNbvsUZXOYCAQSjPcLxR4of22w-U9_JDRThCGRDV3Fmvc38E', 'atype': 1, 'ext': {'linkType': 0}}]}], 'ortb2Imp': {'ext': {'data': {'adserver': {'name': 'gam', 'adslot': '/19968336/header-bid-tag-0'}, 'pbadslot': '/19968336/header-bid-tag-0'}}}, 'mediaTypes': {'banner': {'sizes': [[320, 480], [320, 50]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '71c0d86b-4b47-4aff-a6da-1af0b1712439', 'sizes': [[320, 480], [320, 50]], 'bidId': '264d7969b125a5', 'bidderRequestId': '1c674c14a3889c', 'auctionId': '13a8a3a9-ed3a-4101-9435-4699ee77bb62', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}]; const c_VALIDBIDAPPREQUESTS = [{'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com\/rtb\/v2\/', 'tappxkey': 'pub-1234-android-1234', 'endpoint': 'ZZ1234PBJS', 'bidfloor': 0.005, 'test': 1, 'app': {'name': 'Tappx Test', 'bundle': 'com.test.tappx', 'domain': 'tappx.com', 'publisher': { 'name': 'Tappx', 'domain': 'tappx.com' }}}, 'userId': {'haloId': '0000fgclxw05ycn0608xiyi90bwpa0c0evvlif0hv1x0i0ku88il0ntek0o0qskvir0trr70u0wqxiix0zq3u1012pa5j315ogh1618nmsj91bmt41c1elzfjf1hl5r1i1kkc2jl', 'id5id': {'uid': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_qpoXJUngedfpNva812If1fHEqHHkamLC89txVxk1i9WGqeQrTX97HFCgv9QDa1M_bkHUBsAWFm-D5r1rYrsfMFFiyqwCAEzqNbvsUZXOYCAQSjPcLxR4of22w-U9_JDRThCGRDV3Fmvc38E', 'ext': {'linkType': 0}}, 'intentIqId': 'GIF89a\u0001\u0000\u0001\u0000�\u0000\u0000���\u0000\u0000\u0000!�\u0004\u0001\u0000\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;', 'lotamePanoramaId': '8003916b61a95b185690ec103bdf4945a70213e01818a5e5d8690b542730755a', 'parrableId': {'eid': '01.1617088921.7faa68d9570a50ea8e4f359e9b99ca4b7509e948a6175b3e5b0b8cbaf5b62424104ccfb0191ca79366de8368ed267b89a68e236df5f41f96f238e4301659e9023fec05e46399fb1ad0a0'}, 'pubcid': 'b7143795-852f-42f0-8864-5ecbea1ade4e', 'pubProvidedId': [{'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}, {'source': '3rdpartyprovided.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 3, 'ext': {'stype': 'sha256email'}}]}]}, 'userIdAsEids': [{'source': 'audigent.com', 'uids': [{'id': '0000fgclxw05ycn0608xiyi90bwpa0c0evvlif0hv1x0i0ku88il0ntek0o0qskvir0trr70u0wqxiix0zq3u1012pa5j315ogh1618nmsj91bmt41c1elzfjf1hl5r1i1kkc2jl', 'atype': 1}]}, {'source': 'id5-sync.com', 'uids': [{'id': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_qpoXJUngedfpNva812If1fHEqHHkamLC89txVxk1i9WGqeQrTX97HFCgv9QDa1M_bkHUBsAWFm-D5r1rYrsfMFFiyqwCAEzqNbvsUZXOYCAQSjPcLxR4of22w-U9_JDRThCGRDV3Fmvc38E', 'atype': 1, 'ext': {'linkType': 0}}]}, {'source': 'intentiq.com', 'uids': [{'id': 'GIF89a\u0001\u0000\u0001\u0000�\u0000\u0000���\u0000\u0000\u0000!�\u0004\u0001\u0000\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;', 'atype': 1}]}, {'source': 'crwdcntrl.net', 'uids': [{'id': '8003916b61a95b185690ec103bdf4945a70213e01818a5e5d8690b542730755a', 'atype': 1}]}, {'source': 'parrable.com', 'uids': [{'id': '01.1617088921.7faa68d9570a50ea8e4f359e9b99ca4b7509e948a6175b3e5b0b8cbaf5b62424104ccfb0191ca79366de8368ed267b89a68e236df5f41f96f238e4301659e9023fec05e46399fb1ad0a0', 'atype': 1}]}, {'source': 'pubcid.org', 'uids': [{'id': 'b7143795-852f-42f0-8864-5ecbea1ade4e', 'atype': 1}]}, {'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}, {'source': '3rdpartyprovided.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 3, 'ext': {'stype': 'sha256email'}}]}], 'ortb2Imp': {'ext': {'data': {'adserver': {'name': 'gam', 'adslot': '/19968336/header-bid-tag-0'}, 'pbadslot': '/19968336/header-bid-tag-0'}}}, 'mediaTypes': {'banner': {'sizes': [[320, 480], [320, 50]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '71c0d86b-4b47-4aff-a6da-1af0b1712439', 'sizes': [[320, 480], [320, 50]], 'bidId': '264d7969b125a5', 'bidderRequestId': '1c674c14a3889c', 'auctionId': '13a8a3a9-ed3a-4101-9435-4699ee77bb62', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}]; const c_BIDDERREQUEST_B = {'bidderCode': 'tappx', 'auctionId': '13a8a3a9-ed3a-4101-9435-4699ee77bb62', 'bidderRequestId': '1c674c14a3889c', 'bids': [{'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com\/rtb\/v2\/', 'tappxkey': 'pub-1234-android-1234', 'endpoint': 'ZZ1234PBJS', 'bidfloor': 0.005, 'test': 1}, 'userId': {'haloId': '0000fgclxw05ycn0608xiyi90bwpa0c0evvlif0hv1x0i0ku88il0ntek0o0qskvir0trr70u0wqxiix0zq3u1012pa5j315ogh1618nmsj91bmt41c1elzfjf1hl5r1i1kkc2jl', 'id5id': {'uid': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_qpoXJUngedfpNva812If1fHEqHHkamLC89txVxk1i9WGqeQrTX97HFCgv9QDa1M_bkHUBsAWFm-D5r1rYrsfMFFiyqwCAEzqNbvsUZXOYCAQSjPcLxR4of22w-U9_JDRThCGRDV3Fmvc38E', 'ext': {'linkType': 0}}, 'intentIqId': 'GIF89a\u0000\u0000\u0000\u0000�\u0000\u0000���\u0000\u0000\u0000?�\u0000\u0000\u0000\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000A\u0000\u0000;', 'lotamePanoramaId': '8003916b61a95b185690ec103bdf4945a70213e01818a5e5d8690b542730755a', 'parrableId': {'eid': '01.1617088921.7faa68d9570a50ea8e4f359e9b99ca4b7509e948a6175b3e5b0b8cbaf5b62424104ccfb0191ca79366de8368ed267b89a68e236df5f41f96f238e4301659e9023fec05e46399fb1ad0a0'}, 'pubcid': 'b7143795-852f-42f0-8864-5ecbea1ade4e', 'pubProvidedId': [{'source': 'domain.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 1, 'ext': {'stype': 'ppuid'}}]}, {'source': '3rdpartyprovided.com', 'uids': [{'id': 'value read from cookie or local storage', 'atype': 3, 'ext': {'stype': 'sha256email'}}]}]}, 'userIdAsEids': [{'source': 'audigent.com', 'uids': [{'id': '0000fgclxw05ycn0608xiyi90bwpa0c0evvlif0hv1x0i0ku88il0ntek0o0qskvir0trr70u0wqxiix0zq3u1012pa5j315ogh1618nmsj91bmt41c1elzfjf1hl5r1i1kkc2jl', 'atype': 1}]}, {'source': 'id5-sync.com', 'uids': [{'id': 'ID5@iu-PJX_OQ0d6FJjKS8kYfUpHriD_qpoXJUngedfpNva812If1fHEqHHkamLC89txVxk1i9WGqeQrTX97HFCgv9QDa1M_bkHUBsAWFm-D5r1rYrsfMFFiyqwCAEzqNbvsUZXOYCAQSjPcLxR4of22w-U9_JDRThCGRDV3Fmvc38E', 'atype': 1, 'ext': {'linkType': 0}}]}], 'ortb2Imp': {'ext': {'data': {'adserver': {'name': 'gam', 'adslot': '/19968336/header-bid-tag-0'}, 'pbadslot': '/19968336/header-bid-tag-0'}}}, 'mediaTypes': {'banner': {'sizes': [[320, 480], [320, 50]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '71c0d86b-4b47-4aff-a6da-1af0b1712439', 'sizes': [[320, 480], [320, 50]], 'bidId': '264d7969b125a5', 'bidderRequestId': '1c674c14a3889c', 'auctionId': '13a8a3a9-ed3a-4101-9435-4699ee77bb62', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}], 'auctionStart': 1617088922120, 'timeout': 700, 'refererInfo': {'page': 'http://localhost:9999/integrationExamples/gpt/gdpr_hello_world.html?pbjs_debug=true', 'reachedTop': true, 'isAmp': false, 'numIframes': 0, 'stack': ['http://localhost:9999/integrationExamples/gpt/gdpr_hello_world.html?pbjs_debug=true'], 'canonicalUrl': null}, 'gdprConsent': {'consentString': c_CONSENTSTRING, 'vendorData': {'metadata': 'BO-JeiTPABAOkAAABAENABA', 'gdprApplies': true, 'hasGlobalScope': false, 'cookieVersion': 1, 'created': '2020-12-09T09:22:09.900Z', 'lastUpdated': '2021-01-14T15:44:03.600Z', 'cmpId': 0, 'cmpVersion': 1, 'consentScreen': 0, 'consentLanguage': 'EN', 'vendorListVersion': 1, 'maxVendorId': 0, 'purposeConsents': {}, 'vendorConsents': {}}, 'gdprApplies': true, 'apiVersion': 1}, 'uspConsent': '1YCC', 'start': 1611308859099}; -const c_BIDDERREQUEST_V = {'method': 'POST', 'url': 'https://testing.ssp.tappx.com/rtb/v2//VZ12TESTCTV?type_cnn=prebidjs&v=0.1.10329', 'data': '{"site":{"name":"localhost","bundle":"localhost","domain":"localhost"},"user":{"ext":{}},"id":"0fecfa84-c541-49f8-8c45-76b90fddc30e","test":1,"at":1,"tmax":1000,"bidder":"tappx","imp":[{"video":{"mimes":["video/mp4","application/javascript"],"minduration":3,"maxduration":30,"startdelay":5,"playbackmethod":[1,3],"api":[1,2],"protocols":[2,3],"battr":[13,14],"linearity":1,"placement":2,"minbitrate":10,"maxbitrate":10,"w":320,"h":250},"id":"2398241a5a860b","tagid":"localhost_typeAdBanVid_windows","secure":1,"bidfloor":0.005,"ext":{"bidder":{"tappxkey":"pub-1234-desktop-1234","endpoint":"vz34906po","host":"https://vz34906po.pub.tappx.com/rtb/","bidfloor":0.005}}}],"device":{"os":"windows","ip":"peer","ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","h":864,"w":1536,"dnt":0,"language":"en","make":"Google Inc."},"params":{"host":"tappx.com","bidfloor":0.005},"regs":{"gdpr":0,"ext":{}}}', 'bids': {'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com/rtb/v2/', 'tappxkey': 'pub-1234-desktop-1234', 'endpoint': 'VZ12TESTCTV', 'bidfloor': 0.005, 'test': true}, 'crumbs': {'pubcid': 'dccfe922-3823-4676-b7b2-e5ed8743154e'}, 'ortb2Imp': {'ext': {'data': {'pbadslot': 'video-ad-div'}}}, 'renderer': {'options': {'text': 'Tappx Outstream Video'}}, 'mediaTypes': {'video': {'mimes': ['video/mp4', 'application/javascript'], 'minduration': 3, 'maxduration': 30, 'startdelay': 5, 'playbackmethod': [1, 3], 'api': [1, 2], 'protocols': [2, 3], 'battr': [13, 14], 'linearity': 1, 'placement': 2, 'minbitrate': 10, 'maxbitrate': 10, 'w': 320, 'h': 250}}, 'adUnitCode': 'video-ad-div', 'transactionId': 'ed41c805-d14c-49c3-954d-26b98b2aa2c2', 'sizes': [[320, 250]], 'bidId': '28f49c71b13f2f', 'bidderRequestId': '1401710496dc7', 'auctionId': 'e807363f-3095-43a8-a4a6-f44196cb7318', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}} -const c_BIDDERREQUEST_VOutstream = {'method': 'POST', 'url': 'https://testing.ssp.tappx.com/rtb/v2//VZ12TESTCTV?type_cnn=prebidjs&v=0.1.10329', 'data': '{"site":{"name":"localhost","bundle":"localhost","domain":"localhost"},"user":{"ext":{}},"id":"0fecfa84-c541-49f8-8c45-76b90fddc30e","test":1,"at":1,"tmax":1000,"bidder":"tappx","imp":[{"video":{"context": "outstream","playerSize":[640, 480],"mimes":["video/mp4","application/javascript"],"minduration":3,"maxduration":30,"startdelay":5,"playbackmethod":[1,3],"api":[1,2],"protocols":[2,3],"battr":[13,14],"linearity":1,"placement":2,"minbitrate":10,"maxbitrate":10,"w":320,"h":250},"id":"2398241a5a860b","tagid":"localhost_typeAdBanVid_windows","secure":1,"bidfloor":0.005,"ext":{"bidder":{"tappxkey":"pub-1234-desktop-1234","endpoint":"vz34906po","host":"https://vz34906po.pub.tappx.com/rtb/","bidfloor":0.005}}}],"device":{"os":"windows","ip":"peer","ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","h":864,"w":1536,"dnt":0,"language":"en","make":"Google Inc."},"params":{"host":"tappx.com","bidfloor":0.005},"regs":{"gdpr":0,"ext":{}}}', 'bids': {'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com/rtb/v2/', 'tappxkey': 'pub-1234-desktop-1234', 'endpoint': 'VZ12TESTCTV', 'bidfloor': 0.005, 'test': true}, 'crumbs': {'pubcid': 'dccfe922-3823-4676-b7b2-e5ed8743154e'}, 'ortb2Imp': {'ext': {'data': {'pbadslot': 'video-ad-div'}}}, 'renderer': {'options': {'text': 'Tappx Outstream Video'}}, 'mediaTypes': {'video': {'mimes': ['video/mp4', 'application/javascript'], 'minduration': 3, 'maxduration': 30, 'startdelay': 5, 'playbackmethod': [1, 3], 'api': [1, 2], 'protocols': [2, 3], 'battr': [13, 14], 'linearity': 1, 'placement': 2, 'minbitrate': 10, 'maxbitrate': 10, 'w': 320, 'h': 250}}, 'adUnitCode': 'video-ad-div', 'transactionId': 'ed41c805-d14c-49c3-954d-26b98b2aa2c2', 'sizes': [[320, 250]], 'bidId': '28f49c71b13f2f', 'bidderRequestId': '1401710496dc7', 'auctionId': 'e807363f-3095-43a8-a4a6-f44196cb7318', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}} +const c_BIDDERREQUEST_V = {'method': 'POST', 'url': 'https://testing.ssp.tappx.com/rtb/v2//VZ12TESTCTV?type_cnn=prebidjs&v=0.1.10329', 'data': '{"site":{"name":"localhost","bundle":"localhost","domain":"localhost"},"user":{"ext":{}},"id":"0fecfa84-c541-49f8-8c45-76b90fddc30e","test":1,"at":1,"tmax":1000,"bidder":"tappx","imp":[{"video":{"mimes":["video/mp4","application/javascript"],"minduration":3,"maxduration":30,"startdelay":5,"playbackmethod":[1,3],"api":[1,2],"protocols":[2,3],"battr":[13,14],"linearity":1,"plcmt":2,"minbitrate":10,"maxbitrate":10,"w":320,"h":250},"id":"2398241a5a860b","tagid":"localhost_typeAdBanVid_windows","secure":1,"bidfloor":0.005,"ext":{"bidder":{"tappxkey":"pub-1234-desktop-1234","endpoint":"vz34906po","host":"https://vz34906po.pub.tappx.com/rtb/","bidfloor":0.005}}}],"device":{"os":"windows","ip":"peer","ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","h":864,"w":1536,"dnt":0,"language":"en","make":"Google Inc."},"params":{"host":"tappx.com","bidfloor":0.005},"regs":{"gdpr":0,"ext":{}}}', 'bids': {'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com/rtb/v2/', 'tappxkey': 'pub-1234-desktop-1234', 'endpoint': 'VZ12TESTCTV', 'bidfloor': 0.005, 'test': true}, 'crumbs': {'pubcid': 'dccfe922-3823-4676-b7b2-e5ed8743154e'}, 'ortb2Imp': {'ext': {'data': {'pbadslot': 'video-ad-div'}}}, 'renderer': {'options': {'text': 'Tappx Outstream Video'}}, 'mediaTypes': {'video': {'mimes': ['video/mp4', 'application/javascript'], 'minduration': 3, 'maxduration': 30, 'startdelay': 5, 'playbackmethod': [1, 3], 'api': [1, 2], 'protocols': [2, 3], 'battr': [13, 14], 'linearity': 1, 'plcmt': 2, 'minbitrate': 10, 'maxbitrate': 10, 'w': 320, 'h': 250}}, 'adUnitCode': 'video-ad-div', 'transactionId': 'ed41c805-d14c-49c3-954d-26b98b2aa2c2', 'sizes': [[320, 250]], 'bidId': '28f49c71b13f2f', 'bidderRequestId': '1401710496dc7', 'auctionId': 'e807363f-3095-43a8-a4a6-f44196cb7318', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}} +const c_BIDDERREQUEST_VOutstream = {'method': 'POST', 'url': 'https://testing.ssp.tappx.com/rtb/v2//VZ12TESTCTV?type_cnn=prebidjs&v=0.1.10329', 'data': '{"site":{"name":"localhost","bundle":"localhost","domain":"localhost"},"user":{"ext":{}},"id":"0fecfa84-c541-49f8-8c45-76b90fddc30e","test":1,"at":1,"tmax":1000,"bidder":"tappx","imp":[{"video":{"context": "outstream","playerSize":[640, 480],"mimes":["video/mp4","application/javascript"],"minduration":3,"maxduration":30,"startdelay":5,"playbackmethod":[1,3],"api":[1,2],"protocols":[2,3],"battr":[13,14],"linearity":1,"plcmt":2,"minbitrate":10,"maxbitrate":10,"w":320,"h":250},"id":"2398241a5a860b","tagid":"localhost_typeAdBanVid_windows","secure":1,"bidfloor":0.005,"ext":{"bidder":{"tappxkey":"pub-1234-desktop-1234","endpoint":"vz34906po","host":"https://vz34906po.pub.tappx.com/rtb/","bidfloor":0.005}}}],"device":{"os":"windows","ip":"peer","ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","h":864,"w":1536,"dnt":0,"language":"en","make":"Google Inc."},"params":{"host":"tappx.com","bidfloor":0.005},"regs":{"gdpr":0,"ext":{}}}', 'bids': {'bidder': 'tappx', 'params': {'host': 'testing.ssp.tappx.com/rtb/v2/', 'tappxkey': 'pub-1234-desktop-1234', 'endpoint': 'VZ12TESTCTV', 'bidfloor': 0.005, 'test': true}, 'crumbs': {'pubcid': 'dccfe922-3823-4676-b7b2-e5ed8743154e'}, 'ortb2Imp': {'ext': {'data': {'pbadslot': 'video-ad-div'}}}, 'renderer': {'options': {'text': 'Tappx Outstream Video'}}, 'mediaTypes': {'video': {'mimes': ['video/mp4', 'application/javascript'], 'minduration': 3, 'maxduration': 30, 'startdelay': 5, 'playbackmethod': [1, 3], 'api': [1, 2], 'protocols': [2, 3], 'battr': [13, 14], 'linearity': 1, 'plcmt': 2, 'minbitrate': 10, 'maxbitrate': 10, 'w': 320, 'h': 250}}, 'adUnitCode': 'video-ad-div', 'transactionId': 'ed41c805-d14c-49c3-954d-26b98b2aa2c2', 'sizes': [[320, 250]], 'bidId': '28f49c71b13f2f', 'bidderRequestId': '1401710496dc7', 'auctionId': 'e807363f-3095-43a8-a4a6-f44196cb7318', 'src': 'client', 'bidRequestsCount': 1, 'bidderRequestsCount': 1, 'bidderWinsCount': 0}} describe('Tappx bid adapter', function () { /** @@ -323,14 +323,14 @@ describe('Tappx bid adapter', function () { * INTERPRET RESPONSE TESTS */ describe('interpretResponse', function () { - it('receive banner reponse with single placement', function () { + it('receive banner reponse with single plcmt', function () { const bids = spec.interpretResponse(c_SERVERRESPONSE_B, c_BIDDERREQUEST_B); const bid = bids[0]; expect(bid.cpm).to.exist; expect(bid.ad).to.match(/^ +``` + +# Protected Audience API (FLEDGE) + +In order to enable PAAPI auctions follow the instructions below: + +1. Add the fledgeForGpt and paapi modules to your prebid bundle. +2. Add the following configuration for the module +``` +pbjs.que.push(function() { + pbjs.setConfig({ + fledgeForGpt: { + enabled: true, + bidders: ['medianet'], + defaultForSlots: 1 + } + }); +}); +``` +For a detailed guide to enabling PAAPI auctions follow Prebid's documentation on [fledgeForGpt](https://docs.prebid.org/dev-docs/modules/fledgeForGpt.html) diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index 4a221e97444..cc1a15fd733 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -174,6 +174,37 @@ let VALID_BID_REQUEST = [{ }, 'bidRequestsCount': 1 }], + // Protected Audience API Request + VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP = [{ + 'bidder': 'medianet', + 'params': { + 'crid': 'crid', + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]], + } + }, + 'bidId': '28f8f8130a583e', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'ortb2Imp': { + 'ext': { + 'tid': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'ae': 1 + } + }, + 'bidRequestsCount': 1 + }], + VALID_BID_REQUEST_WITH_USERID = [{ 'bidder': 'medianet', 'params': { @@ -875,6 +906,75 @@ let VALID_BID_REQUEST = [{ }], 'tmax': config.getConfig('bidderTimeout') }, + // Protected Audience API Valid Payload + VALID_PAYLOAD_PAAPI = { + 'site': { + 'domain': 'media.net', + 'page': 'http://media.net/prebidtest', + 'ref': 'http://media.net/prebidtest', + 'topMostLocation': 'http://media.net/topmost', + 'isTop': true + }, + 'ext': { + 'customer_id': 'customer_id', + 'prebid_version': $$PREBID_GLOBAL$$.version, + 'gdpr_applies': false, + 'usp_applies': false, + 'coppa_applies': false, + 'screen': { + 'w': 1000, + 'h': 1000 + }, + }, + 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'imp': [ + { + 'id': '28f8f8130a583e', + 'transactionId': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'ext': { + 'ae': 1, + 'dfp_id': 'div-gpt-ad-1460505748561-0', + 'display_count': 1, + 'coordinates': { + 'top_left': { + 'x': 50, + 'y': 50 + }, + 'bottom_right': { + 'x': 100, + 'y': 100 + } + }, + 'viewability': 1, + 'visibility': 1 + }, + 'all': { + 'cid': 'customer_id', + 'crid': 'crid', + 'site': { + 'domain': 'media.net', + 'isTop': true, + 'page': 'http://media.net/prebidtest', + 'ref': 'http://media.net/prebidtest' + } + }, + 'ortb2Imp': { + 'ext': { + 'tid': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'ae': 1 + } + }, + 'banner': [ + { + 'w': 300, + 'h': 250 + } + ], + 'tagid': 'crid' + } + ], + 'tmax': 3000 + }, VALID_VIDEO_BID_REQUEST = [{ 'bidder': 'medianet', @@ -1104,6 +1204,126 @@ let VALID_BID_REQUEST = [{ } } }, + // Protected Audience API Response + SERVER_RESPONSE_PAAPI = { + body: { + 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidList': [{ + 'no_bid': false, + 'requestId': '28f8f8130a583e', + 'ad': 'ad', + 'width': 300, + 'height': 250, + 'creativeId': 'crid', + 'netRevenue': true, + 'cpm': 0.1 + }], + 'ext': { + 'paApiAuctionConfigs': [ + { + 'bidId': '28f8f8130a583e', + 'config': { + 'seller': 'https://hbx.test.media.net', + 'decisionLogicUrl': 'https://hbx.test.media.net/decision-logic.js', + 'interestGroupBuyers': ['https://buyer.test.media.net'], + 'auctionSignals': { + 'logging_params': { + 'cid': 'customer_id', + 'crid': 'crid', + 'bid_uuid': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'browser_id': 2, + 'dfpid': 'div-gpt-ad-1460505748561-0' + }, + 'pvidLookup': { + 'https://buyer.test.media.net': { + 'pvid': '172', + 'seat': 'quantcast-qc1' + } + }, + 'bidFlr': 0.0 + }, + 'sellerTimout': 1000, + 'sellerSignals': { + 'callbackURL': 'https://test.com/paapi/v1/abcd' + }, + 'perBuyerSignals': { + 'https://buyer.test.media.net': [ 'test_buyer_signals' ] + }, + 'perBuyerTimeouts': { + '*': 200 + } + } + } + ], + 'csUrl': [{ + 'type': 'iframe', + 'url': 'http://contextual.media.net/checksync.php?&vsSync=1' + }] + } + } + }, + // Protected Audience API OpenRTB Response + SERVER_RESPONSE_PAAPI_ORTB = { + body: { + 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidList': [{ + 'no_bid': false, + 'requestId': '28f8f8130a583e', + 'ad': 'ad', + 'width': 300, + 'height': 250, + 'creativeId': 'crid', + 'netRevenue': true, + 'cpm': 0.1 + }], + 'ext': { + 'igi': [{ + 'igs': [ + { + 'impid': '28f8f8130a583e', + 'bidId': '28f8f8130a583e', + 'config': { + 'seller': 'https://hbx.test.media.net', + 'decisionLogicUrl': 'https://hbx.test.media.net/decision-logic.js', + 'interestGroupBuyers': ['https://buyer.test.media.net'], + 'auctionSignals': { + 'logging_params': { + 'cid': 'customer_id', + 'crid': 'crid', + 'bid_uuid': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'browser_id': 2, + 'dfpid': 'div-gpt-ad-1460505748561-0' + }, + 'pvidLookup': { + 'https://buyer.test.media.net': { + 'pvid': '172', + 'seat': 'quantcast-qc1' + } + }, + 'bidFlr': 0.0 + }, + 'sellerTimout': 1000, + 'sellerSignals': { + 'callbackURL': 'https://test.com/paapi/v1/abcd' + }, + 'perBuyerSignals': { + 'https://buyer.test.media.net': [ 'test_buyer_signals' ] + }, + 'perBuyerTimeouts': { + '*': 200 + } + } + } + ], + }], + 'csUrl': [{ + 'type': 'iframe', + 'url': 'http://contextual.media.net/checksync.php?&vsSync=1' + }] + } + } + }, + SERVER_VIDEO_OUTSTREAM_RESPONSE_VALID_BID = { body: { 'id': 'd90ca32f-3877-424a-b2f2-6a68988df57a', @@ -1547,6 +1767,19 @@ describe('Media.net bid adapter', function () { expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_WITH_USERID); }); + it('should have valid payload when PAAPI is enabled', function () { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, fledgeEnabled: true}); + expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_PAAPI); + }); + + it('should send whatever is set in ortb2imp.ext.ae in all bid requests when PAAPI is enabled', function () { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, fledgeEnabled: true}); + let data = JSON.parse(bidReq.data); + expect(data).to.deep.equal(VALID_PAYLOAD_PAAPI); + expect(data.imp[0].ext).to.have.property('ae'); + expect(data.imp[0].ext.ae).to.equal(1); + }); + describe('build requests: when page meta-data is available', () => { beforeEach(() => { spec.clearMnData(); @@ -1721,6 +1954,32 @@ describe('Media.net bid adapter', function () { let bids = spec.interpretResponse(SERVER_RESPONSE_EMPTY_BIDLIST, []); expect(bids).to.deep.equal(validBids); }); + + it('should return fledgeAuctionConfigs if PAAPI response is received', function() { + let response = spec.interpretResponse(SERVER_RESPONSE_PAAPI, []); + expect(response).to.have.property('bids'); + expect(response).to.have.property('fledgeAuctionConfigs'); + expect(response.fledgeAuctionConfigs[0]).to.deep.equal(SERVER_RESPONSE_PAAPI.body.ext.paApiAuctionConfigs[0]); + }); + + it('should return fledgeAuctionConfigs if openRTB PAAPI response received', function () { + let response = spec.interpretResponse(SERVER_RESPONSE_PAAPI_ORTB, []); + expect(response).to.have.property('bids'); + expect(response).to.have.property('fledgeAuctionConfigs'); + expect(response.fledgeAuctionConfigs[0]).to.deep.equal(SERVER_RESPONSE_PAAPI_ORTB.body.ext.igi[0].igs[0]) + }); + + it('should have the correlation between fledgeAuctionConfigs[0].bidId and bidreq.imp[0].id', function() { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, fledgeEnabled: true}); + let bidRes = spec.interpretResponse(SERVER_RESPONSE_PAAPI, []); + expect(bidRes.fledgeAuctionConfigs[0].bidId).to.equal(JSON.parse(bidReq.data).imp[0].id) + }); + + it('should have the correlation between fledgeAuctionConfigs[0].bidId and bidreq.imp[0].id for openRTB response', function() { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP, {...VALID_AUCTIONDATA, fledgeEnabled: true}); + let bidRes = spec.interpretResponse(SERVER_RESPONSE_PAAPI_ORTB, []); + expect(bidRes.fledgeAuctionConfigs[0].bidId).to.equal(JSON.parse(bidReq.data).imp[0].id) + }); }); describe('onTimeout', function () { From b4d6a8280416a42a9a81c48986e7ef231b7396f0 Mon Sep 17 00:00:00 2001 From: asurovenko-zeta <80847074+asurovenko-zeta@users.noreply.github.com> Date: Tue, 21 May 2024 17:55:54 +0200 Subject: [PATCH 145/147] ZetaGlobalSsp Analytics Adapter: refactoring (#11479) * ZetaGlobalSsp Analytics Adapter: refactoring * test * improve test * - * BidTimeout event * bidTimeoutHandler * - * ortb2 to only device --------- Co-authored-by: Surovenko Alexey Co-authored-by: Alexey Surovenko --- modules/zeta_global_sspAnalyticsAdapter.js | 151 ++++++------------ .../zeta_global_sspAnalyticsAdapter_spec.js | 116 ++++++++------ 2 files changed, 116 insertions(+), 151 deletions(-) diff --git a/modules/zeta_global_sspAnalyticsAdapter.js b/modules/zeta_global_sspAnalyticsAdapter.js index f0933d2f62f..2ba119b4d35 100644 --- a/modules/zeta_global_sspAnalyticsAdapter.js +++ b/modules/zeta_global_sspAnalyticsAdapter.js @@ -1,7 +1,7 @@ -import {logInfo, logError} from '../src/utils.js'; -import { ajax } from '../src/ajax.js'; +import {logError} from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; import adapterManager from '../src/adapterManager.js'; -import { EVENTS } from '../src/constants.js'; +import {EVENTS} from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; @@ -10,13 +10,9 @@ const ADAPTER_CODE = 'zeta_global_ssp'; const BASE_URL = 'https://ssp.disqus.com/prebid/event'; const LOG_PREFIX = 'ZetaGlobalSsp-Analytics: '; -const cache = { - auctions: {} -}; - /// /////////// VARIABLES //////////////////////////////////// -let publisherId; // int +let zetaParams; /// /////////// HELPER FUNCTIONS ///////////////////////////// @@ -28,154 +24,96 @@ function sendEvent(eventType, event) { ); } -function getZetaParams(event) { - if (event.adUnits) { - for (const i in event.adUnits) { - const unit = event.adUnits[i]; - if (unit.bids) { - for (const j in unit.bids) { - const bid = unit.bids[j]; - if (bid.bidder === ADAPTER_CODE && bid.params) { - return bid.params; - } - } - } - } - } - return null; -} - /// /////////// ADAPTER EVENT HANDLER FUNCTIONS ////////////// function adRenderSucceededHandler(args) { - let eventType = EVENTS.AD_RENDER_SUCCEEDED - logInfo(LOG_PREFIX + 'handle ' + eventType + ' event'); - const event = { - adId: args.adId, + zetaParams: zetaParams, + domain: args.doc?.location?.host, + page: args.doc?.location?.host + args.doc?.location?.pathname, bid: { adId: args.bid?.adId, - auctionId: args.bid?.auctionId, - adUnitCode: args.bid?.adUnitCode, - bidId: args.bid?.bidId, requestId: args.bid?.requestId, - bidderCode: args.bid?.bidderCode, - mediaTypes: args.bid?.mediaTypes, - sizes: args.bid?.sizes, - adserverTargeting: args.bid?.adserverTargeting, - cpm: args.bid?.cpm, + auctionId: args.bid?.auctionId, creativeId: args.bid?.creativeId, + bidder: args.bid?.bidderCode, mediaType: args.bid?.mediaType, - renderer: args.bid?.renderer, size: args.bid?.size, + adomain: args.bid?.adserverTargeting?.hb_adomain, timeToRespond: args.bid?.timeToRespond, - params: args.bid?.params - }, - doc: { - location: args.doc?.location + cpm: args.bid?.cpm } } - - // set zetaParams from cache - if (event.bid && event.bid.auctionId) { - const zetaParams = cache.auctions[event.bid.auctionId]; - if (zetaParams) { - event.bid.params = [ zetaParams ]; - } - } - - sendEvent(eventType, event); + sendEvent(EVENTS.AD_RENDER_SUCCEEDED, event); } function auctionEndHandler(args) { - let eventType = EVENTS.AUCTION_END; - logInfo(LOG_PREFIX + 'handle ' + eventType + ' event'); - const event = { - auctionId: args.auctionId, - adUnits: args.adUnits, + zetaParams: zetaParams, bidderRequests: args.bidderRequests?.map(br => ({ bidderCode: br?.bidderCode, - refererInfo: br?.refererInfo, + domain: br?.refererInfo?.domain, + page: br?.refererInfo?.page, bids: br?.bids?.map(b => ({ - adUnitCode: b?.adUnitCode, - auctionId: b?.auctionId, bidId: b?.bidId, - requestId: b?.requestId, - bidderCode: b?.bidderCode, - mediaTypes: b?.mediaTypes, - sizes: b?.sizes, + auctionId: b?.auctionId, bidder: b?.bidder, - params: b?.params + mediaType: b?.mediaTypes?.video ? 'VIDEO' : (b?.mediaTypes?.banner ? 'BANNER' : undefined), + size: b?.sizes?.filter(s => s && s.length === 2).filter(s => Number.isInteger(s[0]) && Number.isInteger(s[1])).map(s => s[0] + 'x' + s[1]).find(s => s) })) })), bidsReceived: args.bidsReceived?.map(br => ({ adId: br?.adId, - adserverTargeting: { - hb_adomain: br?.adserverTargeting?.hb_adomain - }, - cpm: br?.cpm, + requestId: br?.requestId, creativeId: br?.creativeId, + bidder: br?.bidder, mediaType: br?.mediaType, - renderer: br?.renderer, size: br?.size, + adomain: br?.adserverTargeting?.hb_adomain, timeToRespond: br?.timeToRespond, - adUnitCode: br?.adUnitCode, - auctionId: br?.auctionId, - bidId: br?.bidId, - requestId: br?.requestId, - bidderCode: br?.bidderCode, - mediaTypes: br?.mediaTypes, - sizes: br?.sizes, - bidder: br?.bidder, - params: br?.params + cpm: br?.cpm })) } + sendEvent(EVENTS.AUCTION_END, event); +} - // save zetaParams to cache - const zetaParams = getZetaParams(event); - if (zetaParams && event.auctionId) { - cache.auctions[event.auctionId] = zetaParams; +function bidTimeoutHandler(args) { + const event = { + zetaParams: zetaParams, + timeouts: args.map(t => ({ + bidId: t?.bidId, + auctionId: t?.auctionId, + bidder: t?.bidder, + mediaType: t?.mediaTypes?.video ? 'VIDEO' : (t?.mediaTypes?.banner ? 'BANNER' : undefined), + size: t?.sizes?.filter(s => s && s.length === 2).filter(s => Number.isInteger(s[0]) && Number.isInteger(s[1])).map(s => s[0] + 'x' + s[1]).find(s => s), + timeout: t?.timeout, + device: t?.ortb2?.device + })) } - - sendEvent(eventType, event); + sendEvent(EVENTS.BID_TIMEOUT, event); } /// /////////// ADAPTER DEFINITION /////////////////////////// -let baseAdapter = adapter({ analyticsType: 'endpoint' }); +let baseAdapter = adapter({analyticsType: 'endpoint'}); let zetaAdapter = Object.assign({}, baseAdapter, { enableAnalytics(config = {}) { - let error = false; - - if (typeof config.options === 'object') { - if (config.options.sid) { - publisherId = Number(config.options.sid); - } + if (config.options && config.options.sid) { + zetaParams = config.options; + baseAdapter.enableAnalytics.call(this, config); } else { logError(LOG_PREFIX + 'Config not found'); - error = true; - } - - if (!publisherId) { - logError(LOG_PREFIX + 'Missing sid (publisher id)'); - error = true; - } - - if (error) { logError(LOG_PREFIX + 'Analytics is disabled due to error(s)'); - } else { - baseAdapter.enableAnalytics.call(this, config); } }, disableAnalytics() { - publisherId = undefined; + zetaParams = undefined; baseAdapter.disableAnalytics.apply(this, arguments); }, - track({ eventType, args }) { + track({eventType, args}) { switch (eventType) { case EVENTS.AD_RENDER_SUCCEEDED: adRenderSucceededHandler(args); @@ -183,6 +121,9 @@ let zetaAdapter = Object.assign({}, baseAdapter, { case EVENTS.AUCTION_END: auctionEndHandler(args); break; + case EVENTS.BID_TIMEOUT: + bidTimeoutHandler(args); + break; } } }); diff --git a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js index fa4b50d7693..604bc780d6b 100644 --- a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ import zetaAnalyticsAdapter from 'modules/zeta_global_sspAnalyticsAdapter.js'; import {config} from 'src/config'; -import { EVENTS } from 'src/constants.js'; +import {EVENTS} from 'src/constants.js'; import {server} from '../../mocks/xhr.js'; import {logError} from '../../../src/utils'; @@ -113,6 +113,8 @@ const SAMPLE_EVENTS = { 'auctionStart': 1638441234544, 'timeout': 400, 'refererInfo': { + 'page': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', + 'domain': 'test-zeta-ssp.net:63342', 'referer': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', 'reachedTop': true, 'isAmp': false, @@ -172,6 +174,8 @@ const SAMPLE_EVENTS = { 'auctionStart': 1638441234544, 'timeout': 400, 'refererInfo': { + 'page': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', + 'domain': 'test-zeta-ssp.net:63342', 'referer': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', 'reachedTop': true, 'isAmp': false, @@ -280,7 +284,7 @@ const SAMPLE_EVENTS = { 'location': { 'href': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', 'protocol': 'http:', - 'host': 'localhost:63342', + 'host': 'test-zeta-ssp.net', 'hostname': 'localhost', 'port': '63342', 'pathname': '/zeta-ssp/ssp/_dev/examples/page_banner.html', @@ -322,12 +326,6 @@ const SAMPLE_EVENTS = { 'bidder': 'zeta_global_ssp', 'adUnitCode': '/19968336/header-bid-tag-0', 'timeToRespond': 123, - 'pbLg': '2.00', - 'pbMg': '2.20', - 'pbHg': '2.25', - 'pbAg': '2.25', - 'pbDg': '2.25', - 'pbCg': '', 'size': '480x320', 'adserverTargeting': { 'hb_bidder': 'zeta_global_ssp', @@ -349,11 +347,11 @@ const SAMPLE_EVENTS = { } } -describe('Zeta Global SSP Analytics Adapter', function() { +describe('Zeta Global SSP Analytics Adapter', function () { let sandbox; let requests; - beforeEach(function() { + beforeEach(function () { sandbox = sinon.sandbox.create(); requests = server.requests; sandbox.stub(events, 'getEvents').returns([]); @@ -372,11 +370,15 @@ describe('Zeta Global SSP Analytics Adapter', function() { expect(utils.logError.called).to.equal(true); }); - describe('handle events', function() { - beforeEach(function() { + describe('handle events', function () { + beforeEach(function () { zetaAnalyticsAdapter.enableAnalytics({ options: { - sid: 111 + sid: 111, + tags: { + position: 'top', + shortname: 'name' + } } }); }); @@ -385,21 +387,7 @@ describe('Zeta Global SSP Analytics Adapter', function() { zetaAnalyticsAdapter.disableAnalytics(); }); - it('Move ZetaParams through analytics events', function() { - this.timeout(3000); - - events.emit(EVENTS.AUCTION_END, SAMPLE_EVENTS.AUCTION_END); - events.emit(EVENTS.AD_RENDER_SUCCEEDED, SAMPLE_EVENTS.AD_RENDER_SUCCEEDED); - - expect(requests.length).to.equal(2); - const auctionEnd = JSON.parse(requests[0].requestBody); - const auctionSucceeded = JSON.parse(requests[1].requestBody); - - expect(auctionSucceeded.bid.params[0]).to.be.deep.equal(SAMPLE_EVENTS.AUCTION_END.adUnits[0].bids[0].params); - expect(SAMPLE_EVENTS.AUCTION_END.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp'); - }); - - it('Keep only needed fields', function() { + it('Handle events', function () { this.timeout(3000); events.emit(EVENTS.AUCTION_END, SAMPLE_EVENTS.AUCTION_END); @@ -409,24 +397,60 @@ describe('Zeta Global SSP Analytics Adapter', function() { const auctionEnd = JSON.parse(requests[0].requestBody); const auctionSucceeded = JSON.parse(requests[1].requestBody); - expect(auctionEnd.adUnitCodes).to.be.undefined; - expect(auctionEnd.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp'); - expect(auctionEnd.auctionEnd).to.be.undefined; - expect(auctionEnd.auctionId).to.be.equal('75e394d9'); - expect(auctionEnd.bidderRequests[0].bidderCode).to.be.equal('zeta_global_ssp'); - expect(auctionEnd.bidderRequests[0].bids[0].bidId).to.be.equal('206be9a13236af'); - expect(auctionEnd.bidderRequests[0].bids[0].adUnitCode).to.be.equal('/19968336/header-bid-tag-0'); - expect(auctionEnd.bidsReceived[0].bidderCode).to.be.equal('zeta_global_ssp'); - expect(auctionEnd.bidsReceived[0].adserverTargeting.hb_adomain).to.be.equal('example.adomain'); - expect(auctionEnd.bidsReceived[0].auctionId).to.be.equal('75e394d9'); - - expect(auctionSucceeded.adId).to.be.equal('5759bb3ef7be1e8'); - expect(auctionSucceeded.bid.auctionId).to.be.equal('75e394d9'); - expect(auctionSucceeded.bid.requestId).to.be.equal('206be9a13236af'); - expect(auctionSucceeded.bid.bidderCode).to.be.equal('zeta_global_ssp'); - expect(auctionSucceeded.bid.creativeId).to.be.equal('456456456'); - expect(auctionSucceeded.bid.size).to.be.equal('480x320'); - expect(auctionSucceeded.doc.location.hostname).to.be.equal('localhost'); + expect(auctionEnd).to.be.deep.equal({ + zetaParams: {sid: 111, tags: {position: 'top', shortname: 'name'}}, + bidderRequests: [{ + bidderCode: 'zeta_global_ssp', + domain: 'test-zeta-ssp.net:63342', + page: 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', + bids: [{ + bidId: '206be9a13236af', + auctionId: '75e394d9', + bidder: 'zeta_global_ssp', + mediaType: 'BANNER', + size: '300x250' + }] + }, { + bidderCode: 'appnexus', + domain: 'test-zeta-ssp.net:63342', + page: 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', + bids: [{ + bidId: '41badc0e164c758', + auctionId: '75e394d9', + bidder: 'appnexus', + mediaType: 'BANNER', + size: '300x250' + }] + }], + bidsReceived: [{ + adId: '5759bb3ef7be1e8', + requestId: '206be9a13236af', + creativeId: '456456456', + bidder: 'zeta_global_ssp', + mediaType: 'banner', + size: '480x320', + adomain: 'example.adomain', + timeToRespond: 123, + cpm: 2.258302852806723 + }] + }); + expect(auctionSucceeded).to.be.deep.equal({ + zetaParams: {sid: 111, tags: {position: 'top', shortname: 'name'}}, + domain: 'test-zeta-ssp.net', + page: 'test-zeta-ssp.net/zeta-ssp/ssp/_dev/examples/page_banner.html', + bid: { + adId: '5759bb3ef7be1e8', + requestId: '206be9a13236af', + auctionId: '75e394d9', + creativeId: '456456456', + bidder: 'zeta_global_ssp', + mediaType: 'banner', + size: '480x320', + adomain: 'example.adomain', + timeToRespond: 123, + cpm: 2.258302852806723 + } + }); }); }); }); From 39787dc1c67c4ccbe2c2aaf0b4be69102e7b2c69 Mon Sep 17 00:00:00 2001 From: xwang202 <57196235+xwang202@users.noreply.github.com> Date: Wed, 22 May 2024 00:09:21 +0800 Subject: [PATCH 146/147] FreeWheel Bid Adapter: remove .innerText for PrebidJS 9.0 (#11532) * freewheel add schain in the request * FreeWheel-SSP-Adapter: remove the innerText for 9.0 release * update test --- modules/freewheel-sspBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index e11aa3f8fb7..0ac848bf62a 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -76,7 +76,7 @@ function getPricing(xmlNode) { var priceNode = pricingExtNode.querySelector('Price'); princingData = { currency: priceNode.getAttribute('currency'), - price: priceNode.textContent || priceNode.innerText + price: priceNode.textContent }; } else { logWarn('PREBID - ' + BIDDER_CODE + ': No bid received or missing pricing extension.'); @@ -110,7 +110,7 @@ function getAdvertiserDomain(xmlNode) { // Currently we only return one Domain if (brandExtNode) { var domainNode = brandExtNode.querySelector('Domain'); - domain.push(domainNode.textContent || domainNode.innerText); + domain.push(domainNode.textContent); } else { logWarn('PREBID - ' + BIDDER_CODE + ': No bid received or missing StickyBrand extension.'); } From 8590378e9e46c0f159bd38f26723fa3f8b4823e0 Mon Sep 17 00:00:00 2001 From: balajimediafuse <87535823+balajimediafuse@users.noreply.github.com> Date: Tue, 21 May 2024 22:03:07 +0530 Subject: [PATCH 147/147] Mediafuse Bid Adapter : remove transformBidParams function (#11534) * removed transformBidParams function * fix lint issues --------- Co-authored-by: Chris Huie --- modules/mediafuseBidAdapter.js | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/modules/mediafuseBidAdapter.js b/modules/mediafuseBidAdapter.js index 5e31f60d3b5..d969314f406 100644 --- a/modules/mediafuseBidAdapter.js +++ b/modules/mediafuseBidAdapter.js @@ -29,11 +29,9 @@ import {convertOrtbRequestToProprietaryNative} from '../src/native.js'; import {APPNEXUS_CATEGORY_MAPPING} from '../libraries/categoryTranslationMapping/index.js'; import { getANKewyordParamFromMaps, - getANKeywordParam, - transformBidderParamKeywords + getANKeywordParam } from '../libraries/appnexusUtils/anKeywords.js'; import {convertCamelToUnderscore, fill} from '../libraries/appnexusUtils/anUtils.js'; -import {convertTypes} from '../libraries/transformParamsUtils/convertTypes.js'; import {chunk} from '../libraries/chunk/chunk.js'; /** @@ -351,31 +349,6 @@ export const spec = { } }, - transformBidParams: function (params, isOpenRtb) { - params = convertTypes({ - 'member': 'string', - 'invCode': 'string', - 'placementId': 'number', - 'keywords': transformBidderParamKeywords, - 'publisherId': 'number' - }, params); - - if (isOpenRtb) { - params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; - if (params.usePaymentRule) { delete params.usePaymentRule; } - - Object.keys(params).forEach(paramKey => { - let convertedKey = convertCamelToUnderscore(paramKey); - if (convertedKey !== paramKey) { - params[convertedKey] = params[paramKey]; - delete params[paramKey]; - } - }); - } - - return params; - }, - /** * Add element selector to javascript tracker to improve native viewability * @param {Bid} bid