prebid.js 7.27.0 → 7.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/.github/workflows/issue_tracker.yml +1 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.js +1 -1
  7. package/dist/adhashBidAdapter.js +1 -1
  8. package/dist/adrelevantisBidAdapter.js +1 -1
  9. package/dist/adtrgtmeBidAdapter.js +1 -1
  10. package/dist/adxcgBidAdapter.js +1 -1
  11. package/dist/ajaBidAdapter.js +1 -1
  12. package/dist/amxBidAdapter.js +1 -1
  13. package/dist/amxIdSystem.js +1 -1
  14. package/dist/appierAnalyticsAdapter.js +1 -1
  15. package/dist/appnexusBidAdapter.js +1 -1
  16. package/dist/asoBidAdapter.js +1 -1
  17. package/dist/axonixBidAdapter.js +1 -1
  18. package/dist/bidglassBidAdapter.js +1 -1
  19. package/dist/big-richmediaBidAdapter.js +1 -1
  20. package/dist/bridgewellBidAdapter.js +1 -1
  21. package/dist/brightMountainMediaBidAdapter.js +1 -1
  22. package/dist/carodaBidAdapter.js +1 -1
  23. package/dist/chtnwBidAdapter.js +1 -1
  24. package/dist/concertBidAdapter.js +1 -1
  25. package/dist/connectadBidAdapter.js +1 -1
  26. package/dist/consumableBidAdapter.js +1 -1
  27. package/dist/conversantBidAdapter.js +1 -1
  28. package/dist/craftBidAdapter.js +1 -1
  29. package/dist/criteoBidAdapter.js +1 -1
  30. package/dist/discoveryBidAdapter.js +1 -1
  31. package/dist/dspxBidAdapter.js +1 -1
  32. package/dist/eplanningBidAdapter.js +1 -1
  33. package/dist/finativeBidAdapter.js +1 -1
  34. package/dist/glimpseBidAdapter.js +1 -1
  35. package/dist/gmosspBidAdapter.js +1 -1
  36. package/dist/goldbachBidAdapter.js +1 -1
  37. package/dist/gridBidAdapter.js +1 -1
  38. package/dist/gridNMBidAdapter.js +1 -1
  39. package/dist/gumgumBidAdapter.js +1 -1
  40. package/dist/h12mediaBidAdapter.js +1 -1
  41. package/dist/id5IdSystem.js +1 -1
  42. package/dist/improvedigitalBidAdapter.js +1 -1
  43. package/dist/inmarBidAdapter.js +1 -1
  44. package/dist/insticatorBidAdapter.js +1 -1
  45. package/dist/ixBidAdapter.js +1 -1
  46. package/dist/justpremiumBidAdapter.js +1 -1
  47. package/dist/kargoBidAdapter.js +1 -1
  48. package/dist/konduitAnalyticsAdapter.js +1 -1
  49. package/dist/kueezBidAdapter.js +1 -1
  50. package/dist/kueezRtbBidAdapter.js +1 -1
  51. package/dist/lassoBidAdapter.js +1 -1
  52. package/dist/lifestreetBidAdapter.js +1 -1
  53. package/dist/liveIntentIdSystem.js +1 -1
  54. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  55. package/dist/logicadBidAdapter.js +1 -1
  56. package/dist/loglyliftBidAdapter.js +1 -1
  57. package/dist/magniteAnalyticsAdapter.js +1 -1
  58. package/dist/malltvAnalyticsAdapter.js +1 -1
  59. package/dist/marsmediaBidAdapter.js +1 -1
  60. package/dist/mediafuseBidAdapter.js +1 -1
  61. package/dist/mediagoBidAdapter.js +1 -1
  62. package/dist/mediasquareBidAdapter.js +1 -1
  63. package/dist/mgidBidAdapter.js +1 -1
  64. package/dist/minutemediaBidAdapter.js +1 -1
  65. package/dist/nexx360BidAdapter.js +1 -1
  66. package/dist/not-for-prod/prebid.js +118 -118
  67. package/dist/oguryBidAdapter.js +1 -1
  68. package/dist/onetagBidAdapter.js +1 -1
  69. package/dist/ooloAnalyticsAdapter.js +1 -1
  70. package/dist/outbrainBidAdapter.js +1 -1
  71. package/dist/parrableIdSystem.js +1 -1
  72. package/dist/pixfutureBidAdapter.js +1 -1
  73. package/dist/prebid-core.js +2 -2
  74. package/dist/publinkIdSystem.js +1 -1
  75. package/dist/pubmaticBidAdapter.js +1 -1
  76. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  77. package/dist/pxyzBidAdapter.js +1 -1
  78. package/dist/quantcastBidAdapter.js +1 -1
  79. package/dist/readpeakBidAdapter.js +1 -1
  80. package/dist/relaidoBidAdapter.js +1 -1
  81. package/dist/rhythmoneBidAdapter.js +1 -1
  82. package/dist/riseBidAdapter.js +1 -1
  83. package/dist/rubiconAnalyticsAdapter.js +1 -1
  84. package/dist/rubiconBidAdapter.js +1 -1
  85. package/dist/seedingAllianceBidAdapter.js +1 -1
  86. package/dist/seedtagBidAdapter.js +1 -1
  87. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  88. package/dist/sharethroughBidAdapter.js +1 -1
  89. package/dist/shinezBidAdapter.js +1 -1
  90. package/dist/smaatoBidAdapter.js +1 -1
  91. package/dist/smartadserverBidAdapter.js +1 -1
  92. package/dist/smartxBidAdapter.js +1 -1
  93. package/dist/smilewantedBidAdapter.js +1 -1
  94. package/dist/sonobiBidAdapter.js +1 -1
  95. package/dist/sovrnAnalyticsAdapter.js +1 -1
  96. package/dist/sovrnBidAdapter.js +1 -1
  97. package/dist/sspBCBidAdapter.js +1 -1
  98. package/dist/sublimeBidAdapter.js +1 -1
  99. package/dist/synacormediaBidAdapter.js +1 -1
  100. package/dist/taboolaBidAdapter.js +1 -1
  101. package/dist/targetVideoBidAdapter.js +1 -1
  102. package/dist/teadsBidAdapter.js +1 -1
  103. package/dist/trionBidAdapter.js +1 -1
  104. package/dist/tripleliftBidAdapter.js +1 -1
  105. package/dist/ttdBidAdapter.js +1 -1
  106. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  107. package/dist/underdogmediaBidAdapter.js +1 -1
  108. package/dist/undertoneBidAdapter.js +1 -1
  109. package/dist/vidazooBidAdapter.js +1 -1
  110. package/dist/videobyteBidAdapter.js +1 -1
  111. package/dist/visxBidAdapter.js +1 -1
  112. package/dist/vuukleBidAdapter.js +1 -1
  113. package/dist/widespaceBidAdapter.js +1 -1
  114. package/dist/winrBidAdapter.js +1 -1
  115. package/dist/yahoosspBidAdapter.js +1 -1
  116. package/dist/yieldmoBidAdapter.js +1 -1
  117. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  118. package/libraries/ortb2.5StrictTranslator/dsl.js +54 -0
  119. package/libraries/ortb2.5StrictTranslator/spec.js +81 -0
  120. package/libraries/ortb2.5StrictTranslator/translator.js +37 -0
  121. package/libraries/ortb2.5Translator/translator.js +82 -0
  122. package/modules/33acrossIdSystem.js +3 -0
  123. package/modules/adhashBidAdapter.js +115 -30
  124. package/modules/adhashBidAdapter.md +1 -3
  125. package/modules/discoveryBidAdapter.js +3 -0
  126. package/modules/kargoBidAdapter.js +1 -1
  127. package/modules/lassoBidAdapter.js +8 -4
  128. package/modules/liveIntentIdSystem.js +1 -2
  129. package/modules/mediagoBidAdapter.js +2 -1
  130. package/modules/openxBidAdapter.md +15 -14
  131. package/modules/taboolaBidAdapter.js +20 -7
  132. package/modules/vidazooBidAdapter.js +20 -7
  133. package/package.json +2 -2
  134. package/src/auction.js +11 -1
  135. package/src/constants.json +2 -1
  136. package/test/helpers/refererDetectionHelper.js +88 -0
  137. package/test/spec/auctionmanager_spec.js +33 -1
  138. package/test/spec/modules/33acrossIdSystem_spec.js +4 -1
  139. package/test/spec/modules/adhashBidAdapter_spec.js +65 -11
  140. package/test/spec/modules/taboolaBidAdapter_spec.js +39 -0
  141. package/test/spec/modules/ttdBidAdapter_spec.js +36 -9
  142. package/test/spec/modules/vidazooBidAdapter_spec.js +134 -3
  143. package/test/spec/ortb2.5StrictTranslator/dsl_spec.js +137 -0
  144. package/test/spec/ortb2.5StrictTranslator/spec_spec.js +358 -0
  145. package/test/spec/ortb2.5StrictTranslator/translator_spec.js +16 -0
  146. package/test/spec/ortb2.5Translator/translator_spec.js +64 -0
  147. package/test/spec/refererDetection_spec.js +1 -88
@@ -15,23 +15,24 @@ Publishers are welcome to test the other adapter and give feedback. Please note
15
15
  # Bid Parameters
16
16
  ## Banner
17
17
 
18
- | Name | Scope | Type | Description | Example
19
- | ---- | ----- | ---- | ----------- | -------
20
- | `delDomain` or `platform` | required | String | OpenX delivery domain or platform id provided by your OpenX representative. | "PUBLISHER-d.openx.net" or "555not5a-real-plat-form-id0123456789"
21
- | `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122"
22
- | `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}`
23
- | `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50 <br/><br/> **WARNING:**<br/> Misuse of this parameter can impact revenue | 1.50
24
- | `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user. <br/><br/> **WARNING:**<br/> Request-level setting. May impact revenue. | true
25
- | `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true
18
+ | Name | Scope | Type | Description | Example |
19
+ |---------------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|
20
+ | `delDomain` ~~or `platform`~~** | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" |
21
+ | `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" |
22
+ | `customParams` | optional | Object | User-defined targeting key-value pairs. customParams applies to a specific unit. | `{key1: "v1", key2: ["v2","v3"]}` |
23
+ | `customFloor` | optional | Number | Minimum price in USD. customFloor applies to a specific unit. For example, use the following value to set a $1.50 floor: 1.50 <br/><br/> **WARNING:**<br/> Misuse of this parameter can impact revenue<br/><br/>Note: OpenX suggests using the [Price Floor Module](https://docs.prebid.org/dev-docs/modules/floors.html) instead of customFloor. The Price Floor Module is prioritized over customFloor if both are present. | 1.50 |
24
+ | `doNotTrack` | optional | Boolean | Prevents advertiser from using data for this user. <br/><br/> **WARNING:**<br/> Request-level setting. May impact revenue. | true |
25
+ | `coppa` | optional | Boolean | Enables Child's Online Privacy Protection Act (COPPA) regulations. | true |
26
26
 
27
- ## Video
27
+ ** platform is deprecated. Please use delDomain instead. If you have any questions please contact your representative.
28
28
 
29
- | Name | Scope | Type | Description | Example
30
- | ---- | ----- | ---- | ----------- | -------
31
- | `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122"
32
- | `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net"
33
- | `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }`
29
+ ## Video
34
30
 
31
+ | Name | Scope | Type | Description | Example |
32
+ |-------------|----------|--------------------|--------------------------------------------------------------|----------------------------------------------------------------|
33
+ | `unit` | required | String | OpenX ad unit ID provided by your OpenX representative. | "1611023122" |
34
+ | `delDomain` | required | String | OpenX delivery domain provided by your OpenX representative. | "PUBLISHER-d.openx.net" |
35
+ | `openrtb` | optional | OpenRTB Impression | An OpenRtb Impression with Video subtype properties | `{ imp: [{ video: {mimes: ['video/x-ms-wmv, video/mp4']} }] }` |
35
36
 
36
37
  # Example
37
38
  ```javascript
@@ -170,15 +170,28 @@ function getSiteProperties({publisherId, bcat = []}, refererInfo) {
170
170
 
171
171
  function getImps(validBidRequests) {
172
172
  return validBidRequests.map((bid, id) => {
173
- const {tagId, bidfloor = null, bidfloorcur = CURRENCY} = bid.params;
174
-
175
- return {
173
+ const {tagId} = bid.params;
174
+ const imp = {
176
175
  id: id + 1,
177
176
  banner: getBanners(bid),
178
- tagid: tagId,
179
- bidfloor,
180
- bidfloorcur,
181
- };
177
+ tagid: tagId
178
+ }
179
+ if (typeof bid.getFloor === 'function') {
180
+ const floorInfo = bid.getFloor({
181
+ currency: CURRENCY,
182
+ mediaType: BANNER,
183
+ size: '*'
184
+ });
185
+ if (typeof floorInfo === 'object' && floorInfo.currency === CURRENCY && !isNaN(parseFloat(floorInfo.floor))) {
186
+ imp.bidfloor = parseFloat(floorInfo.floor);
187
+ imp.bidfloorcur = CURRENCY;
188
+ }
189
+ } else {
190
+ const {bidfloor = null, bidfloorcur = CURRENCY} = bid.params;
191
+ imp.bidfloor = bidfloor;
192
+ imp.bidfloorcur = bidfloorcur;
193
+ }
194
+ return imp;
182
195
  });
183
196
  }
184
197
 
@@ -1,6 +1,6 @@
1
1
  import { _each, deepAccess, parseSizesInput, parseUrl, uniques, isFn } from '../src/utils.js';
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
- import { BANNER } from '../src/mediaTypes.js';
3
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
4
4
  import { getStorageManager } from '../src/storageManager.js';
5
5
  import { bidderSettings } from '../src/bidderSettings.js';
6
6
 
@@ -59,7 +59,7 @@ function isBidRequestValid(bid) {
59
59
  }
60
60
 
61
61
  function buildRequest(bid, topWindowUrl, sizes, bidderRequest) {
62
- const { params, bidId, userId, adUnitCode, schain } = bid;
62
+ const { params, bidId, userId, adUnitCode, schain, mediaTypes } = bid;
63
63
  const { ext } = params;
64
64
  let { bidFloor } = params;
65
65
  const hashUrl = hashCode(topWindowUrl);
@@ -105,6 +105,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) {
105
105
  prebidVersion: '$prebid.version$',
106
106
  res: `${screen.width}x${screen.height}`,
107
107
  schain: schain,
108
+ mediaTypes: mediaTypes,
108
109
  ptrace: ptrace,
109
110
  isStorageAllowed: isStorageAllowed,
110
111
  gpid: gpid,
@@ -188,11 +189,12 @@ function interpretResponse(serverResponse, request) {
188
189
 
189
190
  try {
190
191
  results.forEach(result => {
191
- const { creativeId, ad, price, exp, width, height, currency, advertiserDomains } = result;
192
+ const { creativeId, ad, price, exp, width, height, currency, advertiserDomains, mediaType = BANNER } = result;
192
193
  if (!ad || !price) {
193
194
  return;
194
195
  }
195
- output.push({
196
+
197
+ const response = {
196
198
  requestId: bidId,
197
199
  cpm: price,
198
200
  width: width,
@@ -201,11 +203,22 @@ function interpretResponse(serverResponse, request) {
201
203
  currency: currency || CURRENCY,
202
204
  netRevenue: true,
203
205
  ttl: exp || TTL_SECONDS,
204
- ad: ad,
205
206
  meta: {
206
207
  advertiserDomains: advertiserDomains || []
207
208
  }
208
- })
209
+ };
210
+
211
+ if (mediaType === BANNER) {
212
+ Object.assign(response, {
213
+ ad: ad,
214
+ });
215
+ } else {
216
+ Object.assign(response, {
217
+ vastXml: ad,
218
+ mediaType: VIDEO
219
+ });
220
+ }
221
+ output.push(response);
209
222
  });
210
223
  return output;
211
224
  } catch (e) {
@@ -322,7 +335,7 @@ export const spec = {
322
335
  code: BIDDER_CODE,
323
336
  version: BIDDER_VERSION,
324
337
  gvlid: GVLID,
325
- supportedMediaTypes: [BANNER],
338
+ supportedMediaTypes: [BANNER, VIDEO],
326
339
  isBidRequestValid,
327
340
  buildRequests,
328
341
  interpretResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "7.27.0",
3
+ "version": "7.28.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -130,7 +130,7 @@
130
130
  "express": "^4.15.4",
131
131
  "fun-hooks": "^0.9.9",
132
132
  "just-clone": "^1.0.2",
133
- "live-connect-js": "2.4.0"
133
+ "live-connect-js": "3.0.1"
134
134
  },
135
135
  "optionalDependencies": {
136
136
  "fsevents": "^2.3.2"
package/src/auction.js CHANGED
@@ -828,6 +828,16 @@ export const getAdvertiserDomain = () => {
828
828
  }
829
829
  }
830
830
 
831
+ /**
832
+ * This function returns a function to get the primary category id from bid response meta
833
+ * @returns {function}
834
+ */
835
+ export const getPrimaryCatId = () => {
836
+ return (bid) => {
837
+ return (bid.meta && bid.meta.primaryCatId) ? bid.meta.primaryCatId : '';
838
+ }
839
+ }
840
+
831
841
  // factory for key value objs
832
842
  function createKeyVal(key, value) {
833
843
  return {
@@ -853,6 +863,7 @@ function defaultAdserverTargeting() {
853
863
  createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
854
864
  createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'),
855
865
  createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()),
866
+ createKeyVal(TARGETING_KEYS.ACAT, getPrimaryCatId()),
856
867
  ]
857
868
  }
858
869
 
@@ -865,7 +876,6 @@ function defaultAdserverTargeting() {
865
876
  export function getStandardBidderSettings(mediaType, bidderCode) {
866
877
  const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
867
878
  const standardSettings = Object.assign({}, bidderSettings.settingsFor(null));
868
-
869
879
  if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
870
880
  standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting();
871
881
  }
@@ -76,7 +76,8 @@
76
76
  "UUID": "hb_uuid",
77
77
  "CACHE_ID": "hb_cache_id",
78
78
  "CACHE_HOST": "hb_cache_host",
79
- "ADOMAIN": "hb_adomain"
79
+ "ADOMAIN": "hb_adomain",
80
+ "ACAT": "hb_acat"
80
81
  },
81
82
  "DEFAULT_TARGETING_KEYS": {
82
83
  "BIDDER": "hb_bidder",
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Build a walkable linked list of window-like objects for testing.
3
+ *
4
+ * @param {Array} urls Array of URL strings starting from the top window.
5
+ * @param {string} [topReferrer]
6
+ * @param {string} [canonicalUrl]
7
+ * @param {boolean} [ancestorOrigins]
8
+ * @returns {Object}
9
+ */
10
+ export function buildWindowTree(urls, topReferrer = null, canonicalUrl = null, ancestorOrigins = false) {
11
+ /**
12
+ * Find the origin from a given fully-qualified URL.
13
+ *
14
+ * @param {string} url The fully qualified URL
15
+ * @returns {string|null}
16
+ */
17
+ function getOrigin(url) {
18
+ const originRegex = new RegExp('^(https?://[^/]+/?)');
19
+
20
+ const result = originRegex.exec(url);
21
+
22
+ if (result && result[0]) {
23
+ return result[0];
24
+ }
25
+
26
+ return null;
27
+ }
28
+
29
+ const inaccessibles = [];
30
+
31
+ let previousWindow, topWindow;
32
+ const topOrigin = getOrigin(urls[0]);
33
+
34
+ const windowList = urls.map((url, index) => {
35
+ const thisOrigin = getOrigin(url),
36
+ sameOriginAsPrevious = index === 0 ? true : (getOrigin(urls[index - 1]) === thisOrigin),
37
+ sameOriginAsTop = thisOrigin === topOrigin;
38
+
39
+ const win = {
40
+ location: {
41
+ href: url,
42
+ },
43
+ document: {
44
+ referrer: index === 0 ? topReferrer : urls[index - 1]
45
+ }
46
+ };
47
+
48
+ if (topWindow == null) {
49
+ topWindow = win;
50
+ win.document.querySelector = function (selector) {
51
+ if (selector === 'link[rel=\'canonical\']') {
52
+ return {
53
+ href: canonicalUrl
54
+ };
55
+ }
56
+ return null;
57
+ };
58
+ }
59
+
60
+ if (sameOriginAsPrevious) {
61
+ win.parent = previousWindow;
62
+ } else {
63
+ win.parent = inaccessibles[inaccessibles.length - 1];
64
+ }
65
+ if (ancestorOrigins) {
66
+ win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin);
67
+ }
68
+ win.top = sameOriginAsTop ? topWindow : inaccessibles[0];
69
+
70
+ const inWin = {parent: inaccessibles[inaccessibles.length - 1], top: inaccessibles[0]};
71
+ if (index === 0) {
72
+ inWin.top = inWin;
73
+ }
74
+ ['document', 'location'].forEach((prop) => {
75
+ Object.defineProperty(inWin, prop, {
76
+ get: function () {
77
+ throw new Error('cross-origin access');
78
+ }
79
+ });
80
+ });
81
+ inaccessibles.push(inWin);
82
+ previousWindow = win;
83
+
84
+ return win;
85
+ });
86
+
87
+ return windowList[windowList.length - 1];
88
+ }
@@ -186,7 +186,8 @@ describe('auctionmanager.js', function () {
186
186
  source: 'client',
187
187
  mediaType: 'banner',
188
188
  meta: {
189
- advertiserDomains: ['adomain']
189
+ advertiserDomains: ['adomain'],
190
+ primaryCatId: 'IAB-test'
190
191
  }
191
192
  };
192
193
 
@@ -200,6 +201,7 @@ describe('auctionmanager.js', function () {
200
201
  expected[ CONSTANTS.TARGETING_KEYS.SOURCE ] = bid.source;
201
202
  expected[ CONSTANTS.TARGETING_KEYS.FORMAT ] = bid.mediaType;
202
203
  expected[ CONSTANTS.TARGETING_KEYS.ADOMAIN ] = bid.meta.advertiserDomains[0];
204
+ expected[ CONSTANTS.TARGETING_KEYS.ACAT ] = bid.meta.primaryCatId;
203
205
  if (bid.mediaType === 'video') {
204
206
  expected[ CONSTANTS.TARGETING_KEYS.UUID ] = bid.videoCacheKey;
205
207
  expected[ CONSTANTS.TARGETING_KEYS.CACHE_ID ] = bid.videoCacheKey;
@@ -290,6 +292,12 @@ describe('auctionmanager.js', function () {
290
292
  val: function (bidResponse) {
291
293
  return bidResponse.meta.advertiserDomains[0];
292
294
  }
295
+ },
296
+ {
297
+ key: CONSTANTS.TARGETING_KEYS.ACAT,
298
+ val: function (bidResponse) {
299
+ return bidResponse.meta.primaryCatId;
300
+ }
293
301
  }
294
302
  ]
295
303
 
@@ -367,6 +375,12 @@ describe('auctionmanager.js', function () {
367
375
  val: function (bidResponse) {
368
376
  return bidResponse.meta.advertiserDomains[0];
369
377
  }
378
+ },
379
+ {
380
+ key: CONSTANTS.TARGETING_KEYS.ACAT,
381
+ val: function (bidResponse) {
382
+ return bidResponse.meta.primaryCatId;
383
+ }
370
384
  }
371
385
  ]
372
386
 
@@ -455,6 +469,24 @@ describe('auctionmanager.js', function () {
455
469
  assert.deepEqual(response, expected);
456
470
  });
457
471
 
472
+ it('Should set targeting as expecting when pbs is enabled', function () {
473
+ config.setConfig({
474
+ s2sConfig: {
475
+ accountId: '1',
476
+ enabled: true,
477
+ defaultVendor: 'appnexus',
478
+ bidders: ['appnexus'],
479
+ timeout: 1000,
480
+ adapter: 'prebidServer'
481
+ }
482
+ });
483
+
484
+ $$PREBID_GLOBAL$$.bidderSettings = {};
485
+ let expected = getDefaultExpected(bid);
486
+ let response = getKeyValueTargetingPairs(bid.bidderCode, bid);
487
+ assert.deepEqual(response, expected);
488
+ });
489
+
458
490
  it('Custom bidCpmAdjustment for one bidder and inherit standard but doesn\'t use standard bidCpmAdjustment', function () {
459
491
  $$PREBID_GLOBAL$$.bidderSettings =
460
492
  {
@@ -43,7 +43,10 @@ describe('33acrossIdSystem', () => {
43
43
 
44
44
  expect(request.method).to.equal('GET');
45
45
  expect(request.withCredentials).to.be.true;
46
- expect(request.url).to.contain('https://lexicon.33across.com/v1/envelope?pid=12345');
46
+
47
+ const regExp = new RegExp('https://lexicon.33across.com/v1/envelope\\?pid=12345&gdpr=\\d&src=pbjs&ver=$prebid.version$');
48
+
49
+ expect(request.url).to.match(regExp);
47
50
  expect(completeCallback.calledOnceWithExactly('foo')).to.be.true;
48
51
  });
49
52
 
@@ -60,6 +60,12 @@ describe('adhashBidAdapter', function () {
60
60
  bid.params.platformURL = 'https://';
61
61
  expect(spec.isBidRequestValid(bid)).to.equal(false);
62
62
  });
63
+
64
+ it('should return false when bidderURL is present but not https://', function () {
65
+ const bid = { ...validBid };
66
+ bid.params.bidderURL = 'http://example.com/';
67
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
68
+ });
63
69
  });
64
70
 
65
71
  describe('buildRequests', function () {
@@ -73,11 +79,11 @@ describe('adhashBidAdapter', function () {
73
79
  it('should build the request correctly', function () {
74
80
  const result = spec.buildRequests(
75
81
  [ bidRequest ],
76
- { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { referer: 'http://example.com/' } }
82
+ { gdprConsent: { gdprApplies: true, consentString: 'example' }, refererInfo: { topmostLocation: 'https://example.com/path.html' } }
77
83
  );
78
84
  expect(result.length).to.equal(1);
79
85
  expect(result[0].method).to.equal('POST');
80
- expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb');
86
+ expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb');
81
87
  expect(result[0].bidRequest).to.equal(bidRequest);
82
88
  expect(result[0].data).to.have.property('timezone');
83
89
  expect(result[0].data).to.have.property('location');
@@ -93,7 +99,7 @@ describe('adhashBidAdapter', function () {
93
99
  const result = spec.buildRequests([ bidRequest ], { gdprConsent: { gdprApplies: true, consentString: 'example' } });
94
100
  expect(result.length).to.equal(1);
95
101
  expect(result[0].method).to.equal('POST');
96
- expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=1.0&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb');
102
+ expect(result[0].url).to.equal('https://bidder.adhash.com/rtb?version=3.2&prebid=true&publisher=0xc3b09b27e9c6ef73957901aa729b9e69e5bbfbfb');
97
103
  expect(result[0].bidRequest).to.equal(bidRequest);
98
104
  expect(result[0].data).to.have.property('timezone');
99
105
  expect(result[0].data).to.have.property('location');
@@ -127,9 +133,15 @@ describe('adhashBidAdapter', function () {
127
133
  creatives: [{ costEUR: 1.234 }],
128
134
  advertiserDomains: 'adhash.com',
129
135
  badWords: [
130
- ['onqjbeq1', 'full', 1],
131
- ['onqjbeq2', 'partial', 1],
136
+ ['onqjbeq', 'full', 1],
137
+ ['onqjbeqo', 'partial', 1],
132
138
  ['tbbqjbeq', 'full', -1],
139
+ ['fgnegf', 'starts', 1],
140
+ ['raqf', 'ends', 1],
141
+ ['kkk[no]lll', 'regexp', 1],
142
+ ['дума', 'full', 1],
143
+ ['старт', 'starts', 1],
144
+ ['край', 'ends', 1],
133
145
  ],
134
146
  maxScore: 2
135
147
  }
@@ -155,42 +167,84 @@ describe('adhashBidAdapter', function () {
155
167
 
156
168
  it('should return empty array when there are bad words (full)', function () {
157
169
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
158
- return 'example text badWord1 badWord1 example badWord1 text' + ' word'.repeat(493);
170
+ return 'example text badword badword example badword text' + ' word'.repeat(993);
171
+ });
172
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
173
+ });
174
+
175
+ it('should return empty array when there are bad words (full cyrillic)', function () {
176
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
177
+ return 'example text дума дума example дума text' + ' текст'.repeat(993);
159
178
  });
160
179
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
161
180
  });
162
181
 
163
182
  it('should return empty array when there are bad words (partial)', function () {
164
183
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
165
- return 'example text partialBadWord2 badword2 example BadWord2text' + ' word'.repeat(494);
184
+ return 'example text partialbadwordb badwordb example badwordbtext' + ' word'.repeat(994);
185
+ });
186
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
187
+ });
188
+
189
+ it('should return empty array when there are bad words (starts)', function () {
190
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
191
+ return 'example text startsWith starts text startsAgain' + ' word'.repeat(994);
192
+ });
193
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
194
+ });
195
+
196
+ it('should return empty array when there are bad words (starts cyrillic)', function () {
197
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
198
+ return 'example text стартТекст старт text стартТекст' + ' дума'.repeat(994);
199
+ });
200
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
201
+ });
202
+
203
+ it('should return empty array when there are bad words (ends)', function () {
204
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
205
+ return 'example text wordEnds ends text anotherends' + ' word'.repeat(994);
206
+ });
207
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
208
+ });
209
+
210
+ it('should return empty array when there are bad words (ends cyrillic)', function () {
211
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
212
+ return 'example text ДругКрай край text ощеединкрай' + ' дума'.repeat(994);
213
+ });
214
+ expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
215
+ });
216
+
217
+ it('should return empty array when there are bad words (regexp)', function () {
218
+ bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
219
+ return 'example text xxxayyy zzxxxAyyyzz text xxxbyyy' + ' word'.repeat(994);
166
220
  });
167
221
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(0);
168
222
  });
169
223
 
170
224
  it('should return non-empty array when there are not enough bad words (full)', function () {
171
225
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
172
- return 'example text badWord1 badWord1 example text' + ' word'.repeat(494);
226
+ return 'example text badword badword example text' + ' word'.repeat(994);
173
227
  });
174
228
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(1);
175
229
  });
176
230
 
177
231
  it('should return non-empty array when there are not enough bad words (partial)', function () {
178
232
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
179
- return 'example text partialBadWord2 example' + ' word'.repeat(496);
233
+ return 'example text partialbadwordb example' + ' word'.repeat(996);
180
234
  });
181
235
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(1);
182
236
  });
183
237
 
184
238
  it('should return non-empty array when there are no-bad word matches', function () {
185
239
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
186
- return 'example text partialBadWord1 example text' + ' word'.repeat(495);
240
+ return 'example text partialbadword example text' + ' word'.repeat(995);
187
241
  });
188
242
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(1);
189
243
  });
190
244
 
191
245
  it('should return non-empty array when there are bad words and good words', function () {
192
246
  bodyStub = sinon.stub(window.top.document.body, 'innerText').get(function() {
193
- return 'example text badWord1 badWord1 example badWord1 goodWord goodWord ' + ' word'.repeat(492);
247
+ return 'example text badword badword example badword goodWord goodWord ' + ' word'.repeat(992);
194
248
  });
195
249
  expect(spec.interpretResponse(serverResponse, request).length).to.equal(1);
196
250
  });
@@ -167,6 +167,45 @@ describe('Taboola Adapter', function () {
167
167
  expect(resData.imp[0].bidfloorcur).to.deep.equal('EUR');
168
168
  });
169
169
 
170
+ it('should pass bid floor', function () {
171
+ const bidRequest = {
172
+ ...defaultBidRequest,
173
+ params: {...commonBidRequest.params},
174
+ getFloor: function() {
175
+ return {
176
+ currency: 'USD',
177
+ floor: 2.7,
178
+ }
179
+ }
180
+ };
181
+ const res = spec.buildRequests([bidRequest], commonBidderRequest);
182
+ const resData = JSON.parse(res.data);
183
+ expect(resData.imp[0].bidfloor).to.deep.equal(2.7);
184
+ expect(resData.imp[0].bidfloorcur).to.deep.equal('USD');
185
+ });
186
+
187
+ it('should pass bid floor even if they is a bid floor param', function () {
188
+ const optionalParams = {
189
+ bidfloor: 0.25,
190
+ bidfloorcur: 'EUR'
191
+ };
192
+
193
+ const bidRequest = {
194
+ ...defaultBidRequest,
195
+ params: {...commonBidRequest.params, ...optionalParams},
196
+ getFloor: function() {
197
+ return {
198
+ currency: 'USD',
199
+ floor: 2.7,
200
+ }
201
+ }
202
+ };
203
+ const res = spec.buildRequests([bidRequest], commonBidderRequest);
204
+ const resData = JSON.parse(res.data);
205
+ expect(resData.imp[0].bidfloor).to.deep.equal(2.7);
206
+ expect(resData.imp[0].bidfloorcur).to.deep.equal('USD');
207
+ });
208
+
170
209
  it('should pass bidder timeout', function () {
171
210
  const bidderRequest = {
172
211
  ...commonBidderRequest,
@@ -2,6 +2,9 @@ import { expect } from 'chai';
2
2
  import { spec } from 'modules/ttdBidAdapter';
3
3
  import { deepClone } from 'src/utils.js';
4
4
  import { config } from 'src/config';
5
+ import { detectReferer } from 'src/refererDetection.js';
6
+
7
+ import { buildWindowTree } from '../../helpers/refererDetectionHelper';
5
8
 
6
9
  describe('ttdBidAdapter', function () {
7
10
  function testBuildRequests(bidRequests, bidderRequestBase) {
@@ -200,20 +203,15 @@ describe('ttdBidAdapter', function () {
200
203
  'bidRequestsCount': 1
201
204
  }];
202
205
 
206
+ const testWindow = buildWindowTree(['https://www.example.com/test', 'https://www.example.com/other/page', 'https://www.example.com/third/page'], 'https://othersite.com/', 'https://example.com/canonical/page');
207
+ const baseBidderRequestReferer = detectReferer(testWindow)();
203
208
  const baseBidderRequest = {
204
209
  'bidderCode': 'ttd',
205
210
  'auctionId': 'e7b34fa3-8654-424e-8c49-03e509e53d8c',
206
211
  'bidderRequestId': '18084284054531',
207
212
  'auctionStart': 1540945362095,
208
213
  'timeout': 3000,
209
- 'refererInfo': {
210
- 'page': 'https://www.example.com/test',
211
- 'reachedTop': true,
212
- 'numIframes': 0,
213
- 'stack': [
214
- 'https://www.example.com/test'
215
- ]
216
- },
214
+ 'refererInfo': baseBidderRequestReferer,
217
215
  'start': 1540945362099,
218
216
  'doneCbCallCount': 0
219
217
  };
@@ -291,6 +289,11 @@ describe('ttdBidAdapter', function () {
291
289
  expect(requestBody.site.page).to.equal('https://www.example.com/test');
292
290
  });
293
291
 
292
+ it('ensure top most location is used', function () {
293
+ const requestBody = testBuildRequests(baseBannerBidRequests, baseBidderRequest).data;
294
+ expect(requestBody.site.page).to.equal('https://www.example.com/test');
295
+ });
296
+
294
297
  it('sets the banner pos correctly if sent', function () {
295
298
  let clonedBannerRequests = deepClone(baseBannerBidRequests);
296
299
  clonedBannerRequests[0].mediaTypes.banner.pos = 1;
@@ -318,11 +321,35 @@ describe('ttdBidAdapter', function () {
318
321
  }
319
322
  }
320
323
  };
321
- const requestBody = testBuildRequests(baseBannerBidRequests, {...baseBidderRequest, ortb2}).data;
324
+ const baseBidderRequestWithoutRefererDomain = {
325
+ ...baseBidderRequest,
326
+ refererInfo: {
327
+ ...baseBannerBidRequests.referer,
328
+ domain: null
329
+ }
330
+ }
331
+ const requestBody = testBuildRequests(
332
+ baseBannerBidRequests, {...baseBidderRequestWithoutRefererDomain, ortb2}
333
+ ).data;
322
334
  config.resetConfig();
323
335
  expect(requestBody.site.publisher).to.deep.equal({domain: 'https://foo.bar', id: '13144370'});
324
336
  });
325
337
 
338
+ it('referer domain overrides first party site data publisher domain', function () {
339
+ const ortb2 = {
340
+ site: {
341
+ publisher: {
342
+ domain: 'https://foo.bar',
343
+ }
344
+ }
345
+ };
346
+ const requestBody = testBuildRequests(
347
+ baseBannerBidRequests, {...baseBidderRequest, ortb2}
348
+ ).data;
349
+ config.resetConfig();
350
+ expect(requestBody.site.publisher.domain).to.equal(baseBidderRequest.refererInfo.domain);
351
+ });
352
+
326
353
  it('sets keywords properly if sent', function () {
327
354
  const ortb2 = {
328
355
  site: {