prebid.js 7.12.0 → 7.13.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 (200) hide show
  1. package/.github/PULL_REQUEST_TEMPLATE.md +16 -10
  2. package/.github/codeql/codeql-config.yml +4 -0
  3. package/.github/workflows/codeql-analysis.yml +73 -0
  4. package/dist/33acrossBidAdapter.js +1 -1
  5. package/dist/acuityAdsBidAdapter.js +1 -0
  6. package/dist/adagioBidAdapter.js +1 -1
  7. package/dist/adbookpspBidAdapter.js +1 -1
  8. package/dist/adgenerationBidAdapter.js +1 -1
  9. package/dist/adrelevantisBidAdapter.js +1 -1
  10. package/dist/adtrgtmeBidAdapter.js +1 -1
  11. package/dist/adxcgBidAdapter.js +1 -1
  12. package/dist/adyoulikeBidAdapter.js +1 -1
  13. package/dist/ajaBidAdapter.js +1 -1
  14. package/dist/amxBidAdapter.js +1 -1
  15. package/dist/amxIdSystem.js +1 -1
  16. package/dist/aolBidAdapter.js +1 -1
  17. package/dist/appierAnalyticsAdapter.js +1 -1
  18. package/dist/appnexusBidAdapter.js +1 -1
  19. package/dist/asoBidAdapter.js +1 -1
  20. package/dist/audiencerunBidAdapter.js +1 -1
  21. package/dist/axonixBidAdapter.js +1 -1
  22. package/dist/beopBidAdapter.js +1 -1
  23. package/dist/bidglassBidAdapter.js +1 -1
  24. package/dist/big-richmediaBidAdapter.js +1 -1
  25. package/dist/bluebillywigBidAdapter.js +1 -1
  26. package/dist/brandmetricsRtdProvider.js +1 -1
  27. package/dist/bridgewellBidAdapter.js +1 -1
  28. package/dist/brightMountainMediaBidAdapter.js +1 -1
  29. package/dist/browsiRtdProvider.js +1 -1
  30. package/dist/cleanioRtdProvider.js +1 -1
  31. package/dist/concertBidAdapter.js +1 -1
  32. package/dist/connectadBidAdapter.js +1 -1
  33. package/dist/consentManagement.js +1 -1
  34. package/dist/consentManagementUsp.js +1 -1
  35. package/dist/consumableBidAdapter.js +1 -1
  36. package/dist/conversantBidAdapter.js +1 -1
  37. package/dist/craftBidAdapter.js +1 -1
  38. package/dist/criteoBidAdapter.js +1 -1
  39. package/dist/currency.js +1 -1
  40. package/dist/debugging-standalone.js +1 -1
  41. package/dist/dspxBidAdapter.js +1 -1
  42. package/dist/enrichmentFpdModule.js +1 -1
  43. package/dist/eplanningBidAdapter.js +1 -1
  44. package/dist/finativeBidAdapter.js +1 -1
  45. package/dist/glimpseBidAdapter.js +1 -1
  46. package/dist/gmosspBidAdapter.js +1 -1
  47. package/dist/goldbachBidAdapter.js +1 -1
  48. package/dist/gridBidAdapter.js +1 -1
  49. package/dist/gridNMBidAdapter.js +1 -1
  50. package/dist/gumgumBidAdapter.js +1 -1
  51. package/dist/h12mediaBidAdapter.js +1 -1
  52. package/dist/id5IdSystem.js +1 -1
  53. package/dist/imRtdProvider.js +1 -1
  54. package/dist/impactifyBidAdapter.js +1 -1
  55. package/dist/improvedigitalBidAdapter.js +1 -1
  56. package/dist/inmarBidAdapter.js +1 -1
  57. package/dist/insticatorBidAdapter.js +1 -1
  58. package/dist/ixBidAdapter.js +1 -1
  59. package/dist/jixieBidAdapter.js +1 -1
  60. package/dist/justpremiumBidAdapter.js +1 -1
  61. package/dist/konduitAnalyticsAdapter.js +1 -1
  62. package/dist/kueezBidAdapter.js +1 -1
  63. package/dist/lassoBidAdapter.js +1 -1
  64. package/dist/lifestreetBidAdapter.js +1 -0
  65. package/dist/limelightDigitalBidAdapter.js +1 -1
  66. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  67. package/dist/logicadBidAdapter.js +1 -1
  68. package/dist/loglyliftBidAdapter.js +1 -1
  69. package/dist/mabidderBidAdapter.js +1 -0
  70. package/dist/malltvAnalyticsAdapter.js +1 -1
  71. package/dist/marsmediaBidAdapter.js +1 -1
  72. package/dist/mediafuseBidAdapter.js +1 -1
  73. package/dist/mediakeysBidAdapter.js +1 -1
  74. package/dist/mediasquareBidAdapter.js +1 -1
  75. package/dist/mgidBidAdapter.js +1 -1
  76. package/dist/minutemediaBidAdapter.js +1 -1
  77. package/dist/not-for-prod/prebid.js +132 -127
  78. package/dist/oguryBidAdapter.js +1 -1
  79. package/dist/oneKeyIdSystem.js +1 -0
  80. package/dist/oneKeyRtdProvider.js +1 -0
  81. package/dist/onetagBidAdapter.js +1 -1
  82. package/dist/ooloAnalyticsAdapter.js +1 -1
  83. package/dist/outbrainBidAdapter.js +1 -1
  84. package/dist/parrableIdSystem.js +1 -1
  85. package/dist/permutiveRtdProvider.js +1 -1
  86. package/dist/pixfutureBidAdapter.js +1 -1
  87. package/dist/prebid-core.js +2 -2
  88. package/dist/publinkIdSystem.js +1 -1
  89. package/dist/pubmaticBidAdapter.js +1 -1
  90. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  91. package/dist/pxyzBidAdapter.js +1 -1
  92. package/dist/quantcastBidAdapter.js +1 -1
  93. package/dist/readpeakBidAdapter.js +1 -1
  94. package/dist/relaidoBidAdapter.js +1 -1
  95. package/dist/rhythmoneBidAdapter.js +1 -1
  96. package/dist/riseBidAdapter.js +1 -1
  97. package/dist/rtbhouseBidAdapter.js +1 -1
  98. package/dist/rubiconAnalyticsAdapter.js +1 -1
  99. package/dist/rubiconBidAdapter.js +1 -1
  100. package/dist/seedingAllianceBidAdapter.js +1 -1
  101. package/dist/seedtagBidAdapter.js +1 -1
  102. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  103. package/dist/sharethroughBidAdapter.js +1 -1
  104. package/dist/shinezBidAdapter.js +1 -1
  105. package/dist/smaatoBidAdapter.js +1 -1
  106. package/dist/smartadserverBidAdapter.js +1 -1
  107. package/dist/smartxBidAdapter.js +1 -1
  108. package/dist/smilewantedBidAdapter.js +1 -1
  109. package/dist/sonobiBidAdapter.js +1 -1
  110. package/dist/sovrnAnalyticsAdapter.js +1 -1
  111. package/dist/sovrnBidAdapter.js +1 -1
  112. package/dist/sspBCBidAdapter.js +1 -1
  113. package/dist/sublimeBidAdapter.js +1 -1
  114. package/dist/synacormediaBidAdapter.js +1 -1
  115. package/dist/targetVideoBidAdapter.js +1 -1
  116. package/dist/teadsBidAdapter.js +1 -1
  117. package/dist/trionBidAdapter.js +1 -1
  118. package/dist/tripleliftBidAdapter.js +1 -1
  119. package/dist/trustpidSystem.js +1 -1
  120. package/dist/ttdBidAdapter.js +1 -1
  121. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  122. package/dist/underdogmediaBidAdapter.js +1 -1
  123. package/dist/undertoneBidAdapter.js +1 -1
  124. package/dist/userId.js +1 -1
  125. package/dist/vidazooBidAdapter.js +1 -1
  126. package/dist/videobyteBidAdapter.js +1 -1
  127. package/dist/viewability.js +1 -1
  128. package/dist/visxBidAdapter.js +1 -1
  129. package/dist/vuukleBidAdapter.js +1 -1
  130. package/dist/widespaceBidAdapter.js +1 -1
  131. package/dist/winrBidAdapter.js +1 -1
  132. package/dist/yahoosspBidAdapter.js +1 -1
  133. package/dist/yieldmoBidAdapter.js +1 -1
  134. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  135. package/modules/.submodules.json +2 -0
  136. package/modules/acuityAdsBidAdapter.js +207 -0
  137. package/modules/acuityAdsBidAdapter.md +79 -0
  138. package/modules/adgenerationBidAdapter.js +2 -2
  139. package/modules/adriverBidAdapter.js +1 -1
  140. package/modules/appnexusBidAdapter.js +13 -93
  141. package/modules/beopBidAdapter.js +4 -4
  142. package/modules/browsiRtdProvider.js +1 -1
  143. package/modules/consentManagement.js +1 -1
  144. package/modules/consentManagementUsp.js +1 -1
  145. package/modules/consumableBidAdapter.js +23 -1
  146. package/modules/currency.js +1 -0
  147. package/modules/datawrkzBidAdapter.js +13 -13
  148. package/modules/enrichmentFpdModule.js +11 -0
  149. package/modules/id5IdSystem.js +2 -2
  150. package/modules/imRtdProvider.js +20 -7
  151. package/modules/imRtdProvider.md +3 -1
  152. package/modules/insticatorBidAdapter.js +1 -1
  153. package/modules/ixBidAdapter.js +8 -22
  154. package/modules/ixBidAdapter.md +1 -19
  155. package/modules/lifestreetBidAdapter.js +143 -0
  156. package/modules/limelightDigitalBidAdapter.js +2 -1
  157. package/modules/mabidderBidAdapter.js +60 -0
  158. package/modules/mabidderBidAdapter.md +31 -0
  159. package/modules/oneKeyIdSystem.js +78 -0
  160. package/modules/oneKeyIdSystem.md +109 -0
  161. package/modules/oneKeyRtdProvider.js +98 -0
  162. package/modules/oneKeyRtdProvider.md +127 -0
  163. package/modules/permutiveRtdProvider.js +55 -8
  164. package/modules/pubmaticBidAdapter.js +14 -0
  165. package/modules/rtbhouseBidAdapter.js +24 -0
  166. package/modules/seedtagBidAdapter.md +25 -56
  167. package/modules/tripleliftBidAdapter.js +20 -1
  168. package/modules/trustpidSystem.js +6 -42
  169. package/modules/trustpidSystem.md +10 -10
  170. package/modules/userId/eids.js +26 -0
  171. package/modules/userId/userId.md +2 -2
  172. package/modules/viewability.js +14 -14
  173. package/modules/yahoosspBidAdapter.js +1 -1
  174. package/package.json +1 -1
  175. package/src/auction.js +2 -1
  176. package/src/native.js +22 -3
  177. package/src/sizeMapping.js +4 -6
  178. package/src/utils/promise.js +3 -1
  179. package/src/utils.js +27 -0
  180. package/src/video.js +5 -4
  181. package/test/pages/instream.html +2 -2
  182. package/test/spec/modules/acuityAdsBidAdapter_spec.js +398 -0
  183. package/test/spec/modules/appnexusBidAdapter_spec.js +1 -0
  184. package/test/spec/modules/beopBidAdapter_spec.js +11 -0
  185. package/test/spec/modules/big-richmediaBidAdapter_spec.js +1 -0
  186. package/test/spec/modules/consumableBidAdapter_spec.js +19 -0
  187. package/test/spec/modules/currency_spec.js +22 -0
  188. package/test/spec/modules/enrichmentFpdModule_spec.js +14 -0
  189. package/test/spec/modules/imRtdProvider_spec.js +10 -5
  190. package/test/spec/modules/ixBidAdapter_spec.js +6 -19
  191. package/test/spec/modules/lifestreetBidAdapter_spec.js +232 -0
  192. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +59 -7
  193. package/test/spec/modules/mabidderBidAdapter_spec.js +125 -0
  194. package/test/spec/modules/oneKeyIdSystem_spec.js +107 -0
  195. package/test/spec/modules/oneKeyRtdProvider_spec.js +152 -0
  196. package/test/spec/modules/permutiveRtdProvider_spec.js +152 -2
  197. package/test/spec/modules/pubmaticBidAdapter_spec.js +16 -0
  198. package/test/spec/modules/tripleliftBidAdapter_spec.js +18 -0
  199. package/test/spec/modules/trustpidSystem_spec.js +27 -45
  200. package/test/spec/native_spec.js +17 -2
package/src/utils.js CHANGED
@@ -1381,3 +1381,30 @@ export function setScriptAttributes(script, attributes) {
1381
1381
  }
1382
1382
  }
1383
1383
  }
1384
+
1385
+ /**
1386
+ * Encode a string for inclusion in HTML.
1387
+ * See https://pragmaticwebsecurity.com/articles/spasecurity/json-stringify-xss.html and
1388
+ * https://codeql.github.com/codeql-query-help/javascript/js-bad-code-sanitization/
1389
+ * @return {string}
1390
+ */
1391
+ export const escapeUnsafeChars = (() => {
1392
+ const escapes = {
1393
+ '<': '\\u003C',
1394
+ '>': '\\u003E',
1395
+ '/': '\\u002F',
1396
+ '\\': '\\\\',
1397
+ '\b': '\\b',
1398
+ '\f': '\\f',
1399
+ '\n': '\\n',
1400
+ '\r': '\\r',
1401
+ '\t': '\\t',
1402
+ '\0': '\\0',
1403
+ '\u2028': '\\u2028',
1404
+ '\u2029': '\\u2029'
1405
+ };
1406
+
1407
+ return function(str) {
1408
+ return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029\\]/g, x => escapes[x])
1409
+ }
1410
+ })();
package/src/video.js CHANGED
@@ -35,15 +35,16 @@ export const hasNonVideoBidder = adUnit =>
35
35
  export function isValidVideoBid(bid, {index = auctionManager.index} = {}) {
36
36
  const videoMediaType = deepAccess(index.getMediaTypes(bid), 'video');
37
37
  const context = videoMediaType && deepAccess(videoMediaType, 'context');
38
+ const useCacheKey = videoMediaType && deepAccess(videoMediaType, 'useCacheKey');
38
39
  const adUnit = index.getAdUnit(bid);
39
40
 
40
41
  // if context not defined assume default 'instream' for video bids
41
42
  // instream bids require a vast url or vast xml content
42
- return checkVideoBidSetup(bid, adUnit, videoMediaType, context);
43
+ return checkVideoBidSetup(bid, adUnit, videoMediaType, context, useCacheKey);
43
44
  }
44
45
 
45
- export const checkVideoBidSetup = hook('sync', function(bid, adUnit, videoMediaType, context) {
46
- if (videoMediaType && context !== OUTSTREAM) {
46
+ export const checkVideoBidSetup = hook('sync', function(bid, adUnit, videoMediaType, context, useCacheKey) {
47
+ if (videoMediaType && (useCacheKey || context !== OUTSTREAM)) {
47
48
  // xml-only video bids require a prebid cache url
48
49
  if (!config.getConfig('cache.url') && bid.vastXml && !bid.vastUrl) {
49
50
  logError(`
@@ -57,7 +58,7 @@ export const checkVideoBidSetup = hook('sync', function(bid, adUnit, videoMediaT
57
58
  }
58
59
 
59
60
  // outstream bids require a renderer on the bid or pub-defined on adunit
60
- if (context === OUTSTREAM) {
61
+ if (context === OUTSTREAM && !useCacheKey) {
61
62
  return !!(bid.renderer || (adUnit && adUnit.renderer) || videoMediaType.renderer);
62
63
  }
63
64
 
@@ -8,8 +8,8 @@
8
8
  <title>Prebid.js video adUnit example</title>
9
9
 
10
10
  <!-- videojs -->
11
- <link rel="stylesheet" href="http://vjs.zencdn.net/5.9.2/video-js.css">
12
- <script type="text/javascript" src="http://vjs.zencdn.net/5.9.2/video.js"></script>
11
+ <link rel="stylesheet" href="https://vjs.zencdn.net/5.9.2/video-js.css">
12
+ <script type="text/javascript" src="https://vjs.zencdn.net/5.9.2/video.js"></script>
13
13
 
14
14
  <!-- videojs-vast-vpaid -->
15
15
  <link href="https://cdnjs.cloudflare.com/ajax/libs/videojs-vast-vpaid/2.0.2/videojs.vast.vpaid.min.css" rel="stylesheet">
@@ -0,0 +1,398 @@
1
+ import { expect } from 'chai';
2
+ import { spec } from '../../../modules/acuityAdsBidAdapter';
3
+ import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js';
4
+ import { getUniqueIdentifierStr } from '../../../src/utils.js';
5
+
6
+ const bidder = 'acuityads'
7
+
8
+ describe('AcuityAdsBidAdapter', function () {
9
+ const bids = [
10
+ {
11
+ bidId: getUniqueIdentifierStr(),
12
+ bidder: bidder,
13
+ mediaTypes: {
14
+ [BANNER]: {
15
+ sizes: [[300, 250]]
16
+ }
17
+ },
18
+ params: {
19
+ placementId: 'testBanner',
20
+ }
21
+ },
22
+ {
23
+ bidId: getUniqueIdentifierStr(),
24
+ bidder: bidder,
25
+ mediaTypes: {
26
+ [VIDEO]: {
27
+ playerSize: [[300, 300]],
28
+ minduration: 5,
29
+ maxduration: 60
30
+ }
31
+ },
32
+ params: {
33
+ placementId: 'testVideo',
34
+ }
35
+ },
36
+ {
37
+ bidId: getUniqueIdentifierStr(),
38
+ bidder: bidder,
39
+ mediaTypes: {
40
+ [NATIVE]: {
41
+ native: {
42
+ title: {
43
+ required: true
44
+ },
45
+ body: {
46
+ required: true
47
+ },
48
+ icon: {
49
+ required: true,
50
+ size: [64, 64]
51
+ }
52
+ }
53
+ }
54
+ },
55
+ params: {
56
+ placementId: 'testNative',
57
+ }
58
+ }
59
+ ];
60
+
61
+ const invalidBid = {
62
+ bidId: getUniqueIdentifierStr(),
63
+ bidder: bidder,
64
+ mediaTypes: {
65
+ [BANNER]: {
66
+ sizes: [[300, 250]]
67
+ }
68
+ },
69
+ params: {
70
+
71
+ }
72
+ }
73
+
74
+ const bidderRequest = {
75
+ uspConsent: '1---',
76
+ gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
77
+ refererInfo: {
78
+ referer: 'https://test.com'
79
+ }
80
+ };
81
+
82
+ describe('isBidRequestValid', function () {
83
+ it('Should return true if there are bidId, params and key parameters present', function () {
84
+ expect(spec.isBidRequestValid(bids[0])).to.be.true;
85
+ });
86
+ it('Should return false if at least one of parameters is not present', function () {
87
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
88
+ });
89
+ });
90
+
91
+ describe('buildRequests', function () {
92
+ let serverRequest = spec.buildRequests(bids, bidderRequest);
93
+
94
+ it('Creates a ServerRequest object with method, URL and data', function () {
95
+ expect(serverRequest).to.exist;
96
+ expect(serverRequest.method).to.exist;
97
+ expect(serverRequest.url).to.exist;
98
+ expect(serverRequest.data).to.exist;
99
+ });
100
+
101
+ it('Returns POST method', function () {
102
+ expect(serverRequest.method).to.equal('POST');
103
+ });
104
+
105
+ it('Returns valid URL', function () {
106
+ expect(serverRequest.url).to.equal('https://prebid.admanmedia.com/pbjs');
107
+ });
108
+
109
+ it('Returns general data valid', function () {
110
+ let data = serverRequest.data;
111
+ expect(data).to.be.an('object');
112
+ expect(data).to.have.all.keys('deviceWidth',
113
+ 'deviceHeight',
114
+ 'language',
115
+ 'secure',
116
+ 'host',
117
+ 'page',
118
+ 'placements',
119
+ 'coppa',
120
+ 'ccpa',
121
+ 'gdpr',
122
+ 'tmax'
123
+ );
124
+ expect(data.deviceWidth).to.be.a('number');
125
+ expect(data.deviceHeight).to.be.a('number');
126
+ expect(data.language).to.be.a('string');
127
+ expect(data.secure).to.be.within(0, 1);
128
+ expect(data.host).to.be.a('string');
129
+ expect(data.page).to.be.a('string');
130
+ expect(data.coppa).to.be.a('number');
131
+ expect(data.gdpr).to.be.a('string');
132
+ expect(data.ccpa).to.be.a('string');
133
+ expect(data.tmax).to.be.a('number');
134
+ expect(data.placements).to.have.lengthOf(3);
135
+ });
136
+
137
+ it('Returns valid placements', function () {
138
+ const { placements } = serverRequest.data;
139
+ for (let i = 0, len = placements.length; i < len; i++) {
140
+ const placement = placements[i];
141
+ expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']);
142
+ expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]);
143
+ expect(placement.bidId).to.be.a('string');
144
+ expect(placement.schain).to.be.an('object');
145
+ expect(placement.bidfloor).to.exist.and.to.equal(0);
146
+ expect(placement.type).to.exist.and.to.equal('publisher');
147
+
148
+ if (placement.adFormat === BANNER) {
149
+ expect(placement.sizes).to.be.an('array');
150
+ }
151
+ switch (placement.adFormat) {
152
+ case BANNER:
153
+ expect(placement.sizes).to.be.an('array');
154
+ break;
155
+ case VIDEO:
156
+ expect(placement.playerSize).to.be.an('array');
157
+ expect(placement.minduration).to.be.an('number');
158
+ expect(placement.maxduration).to.be.an('number');
159
+ break;
160
+ case NATIVE:
161
+ expect(placement.native).to.be.an('object');
162
+ break;
163
+ }
164
+ }
165
+ });
166
+
167
+ it('Returns data with gdprConsent and without uspConsent', function () {
168
+ delete bidderRequest.uspConsent;
169
+ serverRequest = spec.buildRequests(bids, bidderRequest);
170
+ let data = serverRequest.data;
171
+ expect(data.gdpr).to.exist;
172
+ expect(data.gdpr).to.be.a('string');
173
+ expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
174
+ expect(data.ccpa).to.not.exist;
175
+ delete bidderRequest.gdprConsent;
176
+ });
177
+
178
+ it('Returns data with uspConsent and without gdprConsent', function () {
179
+ bidderRequest.uspConsent = '1---';
180
+ delete bidderRequest.gdprConsent;
181
+ serverRequest = spec.buildRequests(bids, bidderRequest);
182
+ let data = serverRequest.data;
183
+ expect(data.ccpa).to.exist;
184
+ expect(data.ccpa).to.be.a('string');
185
+ expect(data.ccpa).to.equal(bidderRequest.uspConsent);
186
+ expect(data.gdpr).to.not.exist;
187
+ });
188
+
189
+ it('Returns empty data if no valid requests are passed', function () {
190
+ serverRequest = spec.buildRequests([], bidderRequest);
191
+ let data = serverRequest.data;
192
+ expect(data.placements).to.be.an('array').that.is.empty;
193
+ });
194
+ });
195
+
196
+ describe('interpretResponse', function () {
197
+ it('Should interpret banner response', function () {
198
+ const banner = {
199
+ body: [{
200
+ mediaType: 'banner',
201
+ width: 300,
202
+ height: 250,
203
+ cpm: 0.4,
204
+ ad: 'Test',
205
+ requestId: '23fhj33i987f',
206
+ ttl: 120,
207
+ creativeId: '2',
208
+ netRevenue: true,
209
+ currency: 'USD',
210
+ dealId: '1',
211
+ meta: {
212
+ advertiserDomains: ['google.com'],
213
+ advertiserId: 1234
214
+ }
215
+ }]
216
+ };
217
+ let bannerResponses = spec.interpretResponse(banner);
218
+ expect(bannerResponses).to.be.an('array').that.is.not.empty;
219
+ let dataItem = bannerResponses[0];
220
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
221
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
222
+ expect(dataItem.requestId).to.equal(banner.body[0].requestId);
223
+ expect(dataItem.cpm).to.equal(banner.body[0].cpm);
224
+ expect(dataItem.width).to.equal(banner.body[0].width);
225
+ expect(dataItem.height).to.equal(banner.body[0].height);
226
+ expect(dataItem.ad).to.equal(banner.body[0].ad);
227
+ expect(dataItem.ttl).to.equal(banner.body[0].ttl);
228
+ expect(dataItem.creativeId).to.equal(banner.body[0].creativeId);
229
+ expect(dataItem.netRevenue).to.be.true;
230
+ expect(dataItem.currency).to.equal(banner.body[0].currency);
231
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
232
+ });
233
+ it('Should interpret video response', function () {
234
+ const video = {
235
+ body: [{
236
+ vastUrl: 'test.com',
237
+ mediaType: 'video',
238
+ cpm: 0.5,
239
+ requestId: '23fhj33i987f',
240
+ ttl: 120,
241
+ creativeId: '2',
242
+ netRevenue: true,
243
+ currency: 'USD',
244
+ dealId: '1',
245
+ meta: {
246
+ advertiserDomains: ['google.com'],
247
+ advertiserId: 1234
248
+ }
249
+ }]
250
+ };
251
+ let videoResponses = spec.interpretResponse(video);
252
+ expect(videoResponses).to.be.an('array').that.is.not.empty;
253
+
254
+ let dataItem = videoResponses[0];
255
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId',
256
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
257
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
258
+ expect(dataItem.cpm).to.equal(0.5);
259
+ expect(dataItem.vastUrl).to.equal('test.com');
260
+ expect(dataItem.ttl).to.equal(120);
261
+ expect(dataItem.creativeId).to.equal('2');
262
+ expect(dataItem.netRevenue).to.be.true;
263
+ expect(dataItem.currency).to.equal('USD');
264
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
265
+ });
266
+ it('Should interpret native response', function () {
267
+ const native = {
268
+ body: [{
269
+ mediaType: 'native',
270
+ native: {
271
+ clickUrl: 'test.com',
272
+ title: 'Test',
273
+ image: 'test.com',
274
+ impressionTrackers: ['test.com'],
275
+ },
276
+ ttl: 120,
277
+ cpm: 0.4,
278
+ requestId: '23fhj33i987f',
279
+ creativeId: '2',
280
+ netRevenue: true,
281
+ currency: 'USD',
282
+ meta: {
283
+ advertiserDomains: ['google.com'],
284
+ advertiserId: 1234
285
+ }
286
+ }]
287
+ };
288
+ let nativeResponses = spec.interpretResponse(native);
289
+ expect(nativeResponses).to.be.an('array').that.is.not.empty;
290
+
291
+ let dataItem = nativeResponses[0];
292
+ expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta');
293
+ expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image')
294
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
295
+ expect(dataItem.cpm).to.equal(0.4);
296
+ expect(dataItem.native.clickUrl).to.equal('test.com');
297
+ expect(dataItem.native.title).to.equal('Test');
298
+ expect(dataItem.native.image).to.equal('test.com');
299
+ expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty;
300
+ expect(dataItem.native.impressionTrackers[0]).to.equal('test.com');
301
+ expect(dataItem.ttl).to.equal(120);
302
+ expect(dataItem.creativeId).to.equal('2');
303
+ expect(dataItem.netRevenue).to.be.true;
304
+ expect(dataItem.currency).to.equal('USD');
305
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
306
+ });
307
+ it('Should return an empty array if invalid banner response is passed', function () {
308
+ const invBanner = {
309
+ body: [{
310
+ width: 300,
311
+ cpm: 0.4,
312
+ ad: 'Test',
313
+ requestId: '23fhj33i987f',
314
+ ttl: 120,
315
+ creativeId: '2',
316
+ netRevenue: true,
317
+ currency: 'USD',
318
+ dealId: '1'
319
+ }]
320
+ };
321
+
322
+ let serverResponses = spec.interpretResponse(invBanner);
323
+ expect(serverResponses).to.be.an('array').that.is.empty;
324
+ });
325
+ it('Should return an empty array if invalid video response is passed', function () {
326
+ const invVideo = {
327
+ body: [{
328
+ mediaType: 'video',
329
+ cpm: 0.5,
330
+ requestId: '23fhj33i987f',
331
+ ttl: 120,
332
+ creativeId: '2',
333
+ netRevenue: true,
334
+ currency: 'USD',
335
+ dealId: '1'
336
+ }]
337
+ };
338
+ let serverResponses = spec.interpretResponse(invVideo);
339
+ expect(serverResponses).to.be.an('array').that.is.empty;
340
+ });
341
+ it('Should return an empty array if invalid native response is passed', function () {
342
+ const invNative = {
343
+ body: [{
344
+ mediaType: 'native',
345
+ clickUrl: 'test.com',
346
+ title: 'Test',
347
+ impressionTrackers: ['test.com'],
348
+ ttl: 120,
349
+ requestId: '23fhj33i987f',
350
+ creativeId: '2',
351
+ netRevenue: true,
352
+ currency: 'USD',
353
+ }]
354
+ };
355
+ let serverResponses = spec.interpretResponse(invNative);
356
+ expect(serverResponses).to.be.an('array').that.is.empty;
357
+ });
358
+ it('Should return an empty array if invalid response is passed', function () {
359
+ const invalid = {
360
+ body: [{
361
+ ttl: 120,
362
+ creativeId: '2',
363
+ netRevenue: true,
364
+ currency: 'USD',
365
+ dealId: '1'
366
+ }]
367
+ };
368
+ let serverResponses = spec.interpretResponse(invalid);
369
+ expect(serverResponses).to.be.an('array').that.is.empty;
370
+ });
371
+ });
372
+
373
+ describe('getUserSyncs', function() {
374
+ it('Should return array of objects with proper sync config , include GDPR', function() {
375
+ const syncData = spec.getUserSyncs({}, {}, {
376
+ consentString: 'ALL',
377
+ gdprApplies: true,
378
+ }, {});
379
+ expect(syncData).to.be.an('array').which.is.not.empty;
380
+ expect(syncData[0]).to.be.an('object')
381
+ expect(syncData[0].type).to.be.a('string')
382
+ expect(syncData[0].type).to.equal('image')
383
+ expect(syncData[0].url).to.be.a('string')
384
+ expect(syncData[0].url).to.equal('https://cs.admanmedia.com/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0')
385
+ });
386
+ it('Should return array of objects with proper sync config , include CCPA', function() {
387
+ const syncData = spec.getUserSyncs({}, {}, {}, {
388
+ consentString: '1---'
389
+ });
390
+ expect(syncData).to.be.an('array').which.is.not.empty;
391
+ expect(syncData[0]).to.be.an('object')
392
+ expect(syncData[0].type).to.be.a('string')
393
+ expect(syncData[0].type).to.equal('image')
394
+ expect(syncData[0].url).to.be.a('string')
395
+ expect(syncData[0].url).to.equal('https://cs.admanmedia.com/image?pbjs=1&ccpa_consent=1---&coppa=0')
396
+ });
397
+ });
398
+ });
@@ -1195,6 +1195,7 @@ describe('AppNexusAdapter', function () {
1195
1195
  it('should get correct bid response', function () {
1196
1196
  let expectedResponse = [
1197
1197
  {
1198
+ 'adId': '3a1f23123e',
1198
1199
  'requestId': '3db3773286ee59',
1199
1200
  'cpm': 0.5,
1200
1201
  'creativeId': 29681110,
@@ -204,5 +204,16 @@ describe('BeOp Bid Adapter tests', () => {
204
204
  expect(triggerPixelStub.getCall(0).args[0]).to.include('se_ac=won');
205
205
  expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('pid=5a8af500c9e77c00017e4cad');
206
206
  });
207
+ it('should call triggerPixel utils function on bid won and work even if params is an array', function () {
208
+ spec.onBidWon({});
209
+ spec.onBidWon();
210
+ expect(triggerPixelStub.getCall(0)).to.be.null;
211
+ spec.onBidWon({params: [{accountId: '5a8af500c9e77c00017e4cad'}], cpm: 1.2});
212
+ expect(triggerPixelStub.getCall(0)).to.not.be.null;
213
+ expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('https://t.beop.io');
214
+ expect(triggerPixelStub.getCall(0).args[0]).to.include('se_ca=bid');
215
+ expect(triggerPixelStub.getCall(0).args[0]).to.include('se_ac=won');
216
+ expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.include('pid=5a8af500c9e77c00017e4cad');
217
+ });
207
218
  });
208
219
  });
@@ -190,6 +190,7 @@ describe('bigRichMediaAdapterTests', function () {
190
190
  it('should get correct bid response', function () {
191
191
  const expectedResponse = [
192
192
  {
193
+ 'adId': '3a1f23123e',
193
194
  'requestId': '3db3773286ee59',
194
195
  'cpm': 0.5,
195
196
  'creativeId': 29681110,
@@ -496,6 +496,25 @@ describe('Consumable BidAdapter', function () {
496
496
 
497
497
  expect(data.placements[0].video).to.deep.equal(BIDDER_REQUEST_VIDEO.bidRequest[0].mediaTypes.video);
498
498
  });
499
+
500
+ it('sets bidfloor param if present', function () {
501
+ let bidderRequest1 = deepClone(BIDDER_REQUEST_1);
502
+ let bidderRequest2 = deepClone(BIDDER_REQUEST_2);
503
+ bidderRequest1.bidRequest[0].params.bidFloor = 0.05;
504
+ bidderRequest2.bidRequest[0].getFloor = function() {
505
+ return {
506
+ currency: 'USD',
507
+ floor: 0.15
508
+ }
509
+ };
510
+ let request1 = spec.buildRequests(bidderRequest1.bidRequest, BIDDER_REQUEST_1);
511
+ let data1 = JSON.parse(request1.data);
512
+ let request2 = spec.buildRequests(bidderRequest2.bidRequest, BIDDER_REQUEST_2);
513
+ let data2 = JSON.parse(request2.data);
514
+
515
+ expect(data1.placements[0].bidfloor).to.equal(0.05);
516
+ expect(data2.placements[0].bidfloor).to.equal(0.15);
517
+ });
499
518
  });
500
519
  describe('interpretResponse validation', function () {
501
520
  it('response should have valid bidderCode', function () {
@@ -169,6 +169,28 @@ describe('currency', function () {
169
169
  expect(getGlobal().convertCurrency(1.0, 'USD', 'EUR')).to.equal(4);
170
170
  expect(getGlobal().convertCurrency(1.0, 'USD', 'JPY')).to.equal(200);
171
171
  });
172
+ it('uses default rates until currency file is loaded', function () {
173
+ setConfig({
174
+ adServerCurrency: 'USD',
175
+ defaultRates: {
176
+ USD: {
177
+ JPY: 100
178
+ }
179
+ }
180
+ });
181
+
182
+ // Race condition where a bid is converted before the file has been loaded
183
+ expect(getGlobal().convertCurrency(1.0, 'USD', 'JPY')).to.equal(100);
184
+
185
+ fakeCurrencyFileServer.respondWith(JSON.stringify({
186
+ 'dataAsOf': '2017-04-25',
187
+ 'conversions': {
188
+ 'USD': { JPY: 200 }
189
+ }
190
+ }));
191
+ fakeCurrencyFileServer.respond();
192
+ expect(getGlobal().convertCurrency(1.0, 'USD', 'JPY')).to.equal(200);
193
+ });
172
194
  });
173
195
  describe('bidder override', function () {
174
196
  it('allows setConfig to set bidder currency', function () {
@@ -99,4 +99,18 @@ describe('the first party data enrichment module', function() {
99
99
  expect(validated.device).to.deep.equal({ w: 1200, h: 700 });
100
100
  expect(validated.site.keywords).to.be.undefined;
101
101
  });
102
+
103
+ it('should store a reference to gpc witin ortb2.regs.ext if it has been enabled', function() {
104
+ let validated;
105
+ width = 800;
106
+ height = 500;
107
+
108
+ validated = processFpd({}, {}).global;
109
+ expect(validated.regs).to.equal(undefined);
110
+
111
+ const globalPrivacyControlStub = sinon.stub(window, 'navigator').value({globalPrivacyControl: true});
112
+ validated = processFpd({}, {}).global;
113
+ expect(validated.regs.ext.gpc).to.equal(1);
114
+ globalPrivacyControlStub.restore();
115
+ });
102
116
  });
@@ -27,7 +27,8 @@ describe('imRtdProvider', function () {
27
27
  const moduleConfig = {
28
28
  params: {
29
29
  cid: 5126,
30
- setGptKeyValues: true
30
+ setGptKeyValues: true,
31
+ maxSegments: 2
31
32
  }
32
33
  }
33
34
 
@@ -60,11 +61,11 @@ describe('imRtdProvider', function () {
60
61
 
61
62
  it(`should return bid with correct key data: ${bidderName}`, function () {
62
63
  const bid = {bidder: bidderName};
63
- expect(getBidderFunction(bidderName)(bid, {'im_segments': ['12345', '67890']})).to.equal(bid);
64
+ expect(getBidderFunction(bidderName)(bid, {'im_segments': ['12345', '67890']}, {params: {}})).to.equal(bid);
64
65
  });
65
66
  it(`should return bid without data: ${bidderName}`, function () {
66
67
  const bid = {bidder: bidderName};
67
- expect(getBidderFunction(bidderName)(bid, '')).to.equal(bid);
68
+ expect(getBidderFunction(bidderName)(bid, '', {params: {}})).to.equal(bid);
68
69
  });
69
70
  });
70
71
  it(`should return null with unexpected bidder`, function () {
@@ -73,7 +74,7 @@ describe('imRtdProvider', function () {
73
74
  describe('fluct bidder function', function () {
74
75
  it('should return a bid w/o im_segments if not any exists', function () {
75
76
  const bid = {bidder: 'fluct'};
76
- expect(getBidderFunction('fluct')(bid, '')).to.eql(bid);
77
+ expect(getBidderFunction('fluct')(bid, '', {params: {}})).to.eql(bid);
77
78
  });
78
79
  it('should return a bid w/ im_segments if any exists', function () {
79
80
  const bid = {
@@ -84,7 +85,11 @@ describe('imRtdProvider', function () {
84
85
  }
85
86
  }
86
87
  };
87
- expect(getBidderFunction('fluct')(bid, {im_segments: ['12345', '67890']}))
88
+ expect(getBidderFunction('fluct')(
89
+ bid,
90
+ {im_segments: ['12345', '67890', '09876']},
91
+ {params: {maxSegments: 2}}
92
+ ))
88
93
  .to.eql(
89
94
  {
90
95
  bidder: 'fluct',