prebid.js 9.6.0 → 9.8.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 (274) hide show
  1. package/.github/PULL_REQUEST_TEMPLATE.md +1 -1
  2. package/.github/codeql/codeql-config.yml +3 -0
  3. package/.github/codeql/queries/deviceMemory.ql +14 -0
  4. package/.github/codeql/queries/hardwareConcurrency.ql +14 -0
  5. package/.github/codeql/queries/prebid.qll +36 -0
  6. package/.github/codeql/queries/qlpack.yml +8 -0
  7. package/.github/release-drafter.yml +4 -0
  8. package/.github/workflows/jscpd.yml +1 -1
  9. package/README.md +4 -4
  10. package/dist/33acrossAnalyticsAdapter.js +1 -1
  11. package/dist/33acrossBidAdapter.js +1 -1
  12. package/dist/33acrossIdSystem.js +1 -1
  13. package/dist/BTBidAdapter.js +1 -1
  14. package/dist/adagioAnalyticsAdapter.js +1 -1
  15. package/dist/adagioBidAdapter.js +1 -1
  16. package/dist/adagioUtils.js +1 -1
  17. package/dist/addefendBidAdapter.js +1 -1
  18. package/dist/adgenerationBidAdapter.js +1 -1
  19. package/dist/adlooxRtdProvider.js +1 -1
  20. package/dist/admixerBidAdapter.js +1 -1
  21. package/dist/adqueryBidAdapter.js +1 -1
  22. package/dist/adrelevantisBidAdapter.js +1 -1
  23. package/dist/adstirBidAdapter.js +1 -1
  24. package/dist/adtrgtmeBidAdapter.js +1 -1
  25. package/dist/adxcgAnalyticsAdapter.js +1 -1
  26. package/dist/adxcgBidAdapter.js +1 -1
  27. package/dist/adyoulikeBidAdapter.js +1 -1
  28. package/dist/agmaAnalyticsAdapter.js +1 -1
  29. package/dist/ajaBidAdapter.js +1 -1
  30. package/dist/amxBidAdapter.js +1 -1
  31. package/dist/amxIdSystem.js +1 -1
  32. package/dist/appierAnalyticsAdapter.js +1 -1
  33. package/dist/appnexusBidAdapter.js +1 -1
  34. package/dist/asoBidAdapter.js +1 -1
  35. package/dist/axonixBidAdapter.js +1 -1
  36. package/dist/bidglassBidAdapter.js +1 -1
  37. package/dist/big-richmediaBidAdapter.js +1 -1
  38. package/dist/bridBidAdapter.js +1 -1
  39. package/dist/bridgewellBidAdapter.js +1 -1
  40. package/dist/brightMountainMediaBidAdapter.js +1 -1
  41. package/dist/carodaBidAdapter.js +1 -1
  42. package/dist/ccxBidAdapter.js +1 -1
  43. package/dist/chtnwBidAdapter.js +1 -1
  44. package/dist/chunk-core.js +1 -1
  45. package/dist/cleanmedianetBidAdapter.js +1 -1
  46. package/dist/concertBidAdapter.js +1 -1
  47. package/dist/connectadBidAdapter.js +1 -1
  48. package/dist/connectionInfo.js +1 -0
  49. package/dist/consumableBidAdapter.js +1 -1
  50. package/dist/contxtfulRtdProvider.js +1 -1
  51. package/dist/conversantAnalyticsAdapter.js +1 -1
  52. package/dist/conversantBidAdapter.js +1 -1
  53. package/dist/craftBidAdapter.js +1 -1
  54. package/dist/criteoBidAdapter.js +1 -1
  55. package/dist/cwireBidAdapter.js +1 -1
  56. package/dist/dailymotionBidAdapter.js +1 -1
  57. package/dist/dependencies.json +16 -3
  58. package/dist/discoveryBidAdapter.js +1 -1
  59. package/dist/docereeAdManagerBidAdapter.js +1 -1
  60. package/dist/dspxBidAdapter.js +1 -1
  61. package/dist/dxkultureBidAdapter.js +1 -1
  62. package/dist/eightPodAnalyticsAdapter.js +1 -1
  63. package/dist/eplanningBidAdapter.js +1 -1
  64. package/dist/euidIdSystem.js +1 -1
  65. package/dist/exadsBidAdapter.js +1 -1
  66. package/dist/feedadBidAdapter.js +1 -1
  67. package/dist/finativeBidAdapter.js +1 -1
  68. package/dist/freewheel-sspBidAdapter.js +1 -1
  69. package/dist/gamoshiBidAdapter.js +1 -1
  70. package/dist/gmosspBidAdapter.js +1 -1
  71. package/dist/goldbachBidAdapter.js +1 -1
  72. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  73. package/dist/greenbidsRtdProvider.js +1 -1
  74. package/dist/gridBidAdapter.js +1 -1
  75. package/dist/gumgumBidAdapter.js +1 -1
  76. package/dist/h12mediaBidAdapter.js +1 -1
  77. package/dist/hypelabBidAdapter.js +1 -1
  78. package/dist/id5AnalyticsAdapter.js +1 -1
  79. package/dist/id5IdSystem.js +1 -1
  80. package/dist/idImportLibrary.js +1 -1
  81. package/dist/imdsBidAdapter.js +1 -1
  82. package/dist/improvedigitalBidAdapter.js +1 -1
  83. package/dist/insticatorBidAdapter.js +1 -1
  84. package/dist/intentIqAnalyticsAdapter.js +1 -1
  85. package/dist/ixBidAdapter.js +1 -1
  86. package/dist/jixieBidAdapter.js +1 -1
  87. package/dist/justpremiumBidAdapter.js +1 -1
  88. package/dist/kargoBidAdapter.js +1 -1
  89. package/dist/kimberliteBidAdapter.js +1 -1
  90. package/dist/konduitAnalyticsAdapter.js +1 -1
  91. package/dist/kueezBidAdapter.js +1 -1
  92. package/dist/lassoBidAdapter.js +1 -1
  93. package/dist/lifestreetBidAdapter.js +1 -1
  94. package/dist/liveIntentIdSystem.js +1 -1
  95. package/dist/logicadBidAdapter.js +1 -1
  96. package/dist/loglyliftBidAdapter.js +1 -1
  97. package/dist/luceadBidAdapter.js +1 -1
  98. package/dist/mabidderBidAdapter.js +1 -1
  99. package/dist/magniteAnalyticsAdapter.js +1 -1
  100. package/dist/malltvAnalyticsAdapter.js +1 -1
  101. package/dist/marsmediaBidAdapter.js +1 -1
  102. package/dist/mediafuseBidAdapter.js +1 -1
  103. package/dist/mediagoBidAdapter.js +1 -1
  104. package/dist/medianetAnalyticsAdapter.js +1 -1
  105. package/dist/medianetBidAdapter.js +1 -1
  106. package/dist/mediasquareBidAdapter.js +1 -1
  107. package/dist/mgidBidAdapter.js +1 -1
  108. package/dist/mgidUtils.js +1 -0
  109. package/dist/mgidXBidAdapter.js +1 -1
  110. package/dist/missenaBidAdapter.js +1 -1
  111. package/dist/mobianRtdProvider.js +1 -1
  112. package/dist/navigatorData.js +1 -0
  113. package/dist/nexx360BidAdapter.js +1 -1
  114. package/dist/nobidAnalyticsAdapter.js +1 -1
  115. package/dist/nobidBidAdapter.js +1 -1
  116. package/dist/not-for-prod/prebid.js +176 -170
  117. package/dist/oguryBidAdapter.js +1 -1
  118. package/dist/omsBidAdapter.js +1 -1
  119. package/dist/onetagBidAdapter.js +1 -1
  120. package/dist/ooloAnalyticsAdapter.js +1 -1
  121. package/dist/openxBidAdapter.js +1 -1
  122. package/dist/optidigitalBidAdapter.js +1 -1
  123. package/dist/orbidderBidAdapter.js +1 -1
  124. package/dist/ortbConverter.js +1 -1
  125. package/dist/outbrainBidAdapter.js +1 -1
  126. package/dist/ownadxBidAdapter.js +1 -0
  127. package/dist/pixfutureBidAdapter.js +1 -1
  128. package/dist/prismaBidAdapter.js +1 -1
  129. package/dist/publinkIdSystem.js +1 -1
  130. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  131. package/dist/pubmaticBidAdapter.js +1 -1
  132. package/dist/pubriseBidAdapter.js +1 -0
  133. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  134. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  135. package/dist/pubxaiRtdProvider.js +1 -1
  136. package/dist/pxyzBidAdapter.js +1 -1
  137. package/dist/quantcastBidAdapter.js +1 -1
  138. package/dist/readpeakBidAdapter.js +1 -1
  139. package/dist/redtramBidAdapter.js +1 -1
  140. package/dist/relaidoBidAdapter.js +1 -1
  141. package/dist/retailspotBidAdapter.js +1 -1
  142. package/dist/rhythmoneBidAdapter.js +1 -1
  143. package/dist/riseUtils.js +1 -1
  144. package/dist/rubiconBidAdapter.js +1 -1
  145. package/dist/seedingAllianceBidAdapter.js +1 -1
  146. package/dist/seedtagBidAdapter.js +1 -1
  147. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  148. package/dist/sharethroughBidAdapter.js +1 -1
  149. package/dist/smaatoBidAdapter.js +1 -1
  150. package/dist/smartadserverBidAdapter.js +1 -1
  151. package/dist/smarthubBidAdapter.js +1 -1
  152. package/dist/smartxBidAdapter.js +1 -1
  153. package/dist/smilewantedBidAdapter.js +1 -1
  154. package/dist/snigelBidAdapter.js +1 -1
  155. package/dist/sonobiBidAdapter.js +1 -1
  156. package/dist/sovrnBidAdapter.js +1 -1
  157. package/dist/sspBCBidAdapter.js +1 -1
  158. package/dist/stvBidAdapter.js +1 -1
  159. package/dist/sublimeBidAdapter.js +1 -1
  160. package/dist/taboolaBidAdapter.js +1 -1
  161. package/dist/tappxBidAdapter.js +1 -1
  162. package/dist/targetVideoBidAdapter.js +1 -1
  163. package/dist/teadsBidAdapter.js +1 -1
  164. package/dist/terceptAnalyticsAdapter.js +1 -1
  165. package/dist/themoneytizerBidAdapter.js +1 -1
  166. package/dist/trionBidAdapter.js +1 -1
  167. package/dist/tripleliftBidAdapter.js +1 -1
  168. package/dist/ttdBidAdapter.js +1 -1
  169. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  170. package/dist/uid2IdSystem.js +1 -1
  171. package/dist/underdogmediaBidAdapter.js +1 -1
  172. package/dist/undertoneBidAdapter.js +1 -1
  173. package/dist/unrulyBidAdapter.js +1 -1
  174. package/dist/userId.js +1 -1
  175. package/dist/viantOrtbBidAdapter.js +1 -1
  176. package/dist/vidazooUtils.js +1 -1
  177. package/dist/videobyteBidAdapter.js +1 -1
  178. package/dist/visxBidAdapter.js +1 -1
  179. package/dist/vuukleBidAdapter.js +1 -1
  180. package/dist/widespaceBidAdapter.js +1 -1
  181. package/dist/winrBidAdapter.js +1 -1
  182. package/dist/wurflRtdProvider.js +1 -0
  183. package/dist/yahooAdsBidAdapter.js +1 -1
  184. package/dist/yieldmoBidAdapter.js +1 -1
  185. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  186. package/integrationExamples/gpt/wurflRtdProvider_example.html +106 -0
  187. package/libraries/connectionInfo/connectionUtils.js +33 -0
  188. package/libraries/mgidUtils/mgidUtils.js +73 -0
  189. package/{src/fpd/navigator.js → libraries/navigatorData/navigatorData.js} +1 -1
  190. package/libraries/ortbConverter/processors/video.js +2 -24
  191. package/libraries/riseUtils/index.js +2 -1
  192. package/libraries/vidazooUtils/bidderUtils.js +16 -0
  193. package/modules/.submodules.json +3 -1
  194. package/modules/51DegreesRtdProvider.md +11 -7
  195. package/modules/adagioBidAdapter.js +10 -50
  196. package/modules/admixerBidAdapter.js +12 -5
  197. package/modules/appnexusBidAdapter.js +1 -1
  198. package/modules/ccxBidAdapter.js +6 -2
  199. package/modules/cleanmedianetBidAdapter.js +1 -1
  200. package/modules/contxtfulRtdProvider.js +15 -12
  201. package/modules/cwireBidAdapter.js +13 -9
  202. package/modules/cwireBidAdapter.md +29 -10
  203. package/modules/dailymotionBidAdapter.js +20 -1
  204. package/modules/dailymotionBidAdapter.md +11 -7
  205. package/modules/discoveryBidAdapter.js +1 -1
  206. package/modules/docereeAdManagerBidAdapter.js +9 -12
  207. package/modules/eightPodAnalyticsAdapter.js +13 -1
  208. package/modules/gamoshiBidAdapter.js +1 -1
  209. package/modules/greenbidsAnalyticsAdapter.js +7 -4
  210. package/modules/greenbidsRtdProvider.js +15 -5
  211. package/modules/id5IdSystem.js +14 -93
  212. package/modules/idImportLibrary.js +14 -6
  213. package/modules/ixBidAdapter.js +0 -1
  214. package/modules/mediagoBidAdapter.js +4 -4
  215. package/modules/mgidBidAdapter.js +30 -109
  216. package/modules/mgidXBidAdapter.js +2 -66
  217. package/modules/mobianRtdProvider.js +28 -14
  218. package/modules/omsBidAdapter.js +1 -1
  219. package/modules/ownadxBidAdapter.js +99 -0
  220. package/modules/prismaBidAdapter.js +1 -27
  221. package/modules/pubmaticBidAdapter.js +2 -1
  222. package/modules/pubriseBidAdapter.js +19 -0
  223. package/modules/pubriseBidAdapter.md +79 -0
  224. package/modules/pubxaiAnalyticsAdapter.js +9 -4
  225. package/modules/pubxaiRtdProvider.js +38 -18
  226. package/modules/pubxaiRtdProvider.md +2 -2
  227. package/modules/redtramBidAdapter.js +2 -6
  228. package/modules/rubiconBidAdapter.js +3 -3
  229. package/modules/sharethroughBidAdapter.js +5 -0
  230. package/modules/smarthubBidAdapter.js +2 -0
  231. package/modules/teadsBidAdapter.js +4 -3
  232. package/modules/ttdBidAdapter.js +14 -32
  233. package/modules/undertoneBidAdapter.js +1 -19
  234. package/modules/userId/index.js +1 -1
  235. package/modules/viantOrtbBidAdapter.js +1 -1
  236. package/modules/wurflRtdProvider.js +213 -0
  237. package/modules/wurflRtdProvider.md +67 -0
  238. package/package.json +1 -1
  239. package/src/adloader.js +1 -0
  240. package/src/prebid.js +2 -1
  241. package/src/utils/focusTimeout.js +17 -6
  242. package/src/utils/ttlCollection.js +1 -1
  243. package/src/utils.js +28 -0
  244. package/src/video.js +78 -1
  245. package/test/spec/modules/adagioBidAdapter_spec.js +0 -1
  246. package/test/spec/modules/admixerBidAdapter_spec.js +2 -2
  247. package/test/spec/modules/appnexusBidAdapter_spec.js +0 -33
  248. package/test/spec/modules/ccxBidAdapter_spec.js +81 -0
  249. package/test/spec/modules/cleanmedianetBidAdapter_spec.js +1 -1
  250. package/test/spec/modules/contxtfulRtdProvider_spec.js +19 -19
  251. package/test/spec/modules/dailymotionBidAdapter_spec.js +62 -12
  252. package/test/spec/modules/discoveryBidAdapter_spec.js +1 -1
  253. package/test/spec/modules/docereeAdManagerBidAdapter_spec.js +1 -0
  254. package/test/spec/modules/gamoshiBidAdapter_spec.js +1 -1
  255. package/test/spec/modules/id5IdSystem_spec.js +25 -98
  256. package/test/spec/modules/idImportLibrary_spec.js +14 -0
  257. package/test/spec/modules/ixBidAdapter_spec.js +8 -1
  258. package/test/spec/modules/mobianRtdProvider_spec.js +46 -43
  259. package/test/spec/modules/openxBidAdapter_spec.js +1 -1
  260. package/test/spec/modules/ownadxBidAdapter_spec.js +103 -0
  261. package/test/spec/modules/pubmaticBidAdapter_spec.js +18 -0
  262. package/test/spec/modules/pubriseBidAdapter_spec.js +514 -0
  263. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +9 -4
  264. package/test/spec/modules/pubxaiRtdProvider_spec.js +37 -5
  265. package/test/spec/modules/rubiconBidAdapter_spec.js +10 -0
  266. package/test/spec/modules/sharethroughBidAdapter_spec.js +35 -0
  267. package/test/spec/modules/trafficgateBidAdapter_spec.js +1 -1
  268. package/test/spec/modules/ttdBidAdapter_spec.js +10 -1
  269. package/test/spec/modules/viantOrtbBidAdapter_spec.js +1 -1
  270. package/test/spec/modules/vidazooBidAdapter_spec.js +12 -4
  271. package/test/spec/modules/wurflRtdProvider_spec.js +324 -0
  272. package/test/spec/ortbConverter/userId_spec.js +23 -2
  273. package/test/spec/unit/utils/focusTimeout_spec.js +33 -6
  274. package/test/spec/video_spec.js +103 -1
@@ -3987,6 +3987,16 @@ describe('the rubicon adapter', function () {
3987
3987
  let bids = spec.interpretResponse({body: response}, {data: request});
3988
3988
  expect(bids).to.have.nested.property('[0].native');
3989
3989
  });
3990
+ it('should set 0 to bids width and height if `w` and `h` in response object not defined', () => {
3991
+ const nativeBidderRequest = addNativeToBidRequest(bidderRequest);
3992
+ const request = converter.toORTB({bidderRequest: nativeBidderRequest, bidRequests: nativeBidderRequest.bids});
3993
+ let response = getNativeResponse({impid: request.imp[0].id});
3994
+ delete response.seatbid[0].bid[0].w;
3995
+ delete response.seatbid[0].bid[0].h
3996
+ let bids = spec.interpretResponse({body: response}, {data: request});
3997
+ expect(bids[0].width).to.equal(0);
3998
+ expect(bids[0].height).to.equal(0);
3999
+ })
3990
4000
  });
3991
4001
  }
3992
4002
 
@@ -346,6 +346,41 @@ describe('sharethrough adapter spec', function () {
346
346
 
347
347
  expect(openRtbReq.user.ext.eids).to.deep.equal([]);
348
348
  });
349
+
350
+ it('should add ORTB2 device data to the request', () => {
351
+ const bidderRequestWithOrtb2Device = {
352
+ ...bidderRequest,
353
+ ...{
354
+ ortb2: {
355
+ device: {
356
+ w: 980,
357
+ h: 1720,
358
+ dnt: 0,
359
+ ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/125.0.6422.80 Mobile/15E148 Safari/604.1',
360
+ language: 'en',
361
+ devicetype: 1,
362
+ make: 'Apple',
363
+ model: 'iPhone 12 Pro Max',
364
+ os: 'iOS',
365
+ osv: '17.4',
366
+ },
367
+ },
368
+ },
369
+ };
370
+
371
+ const [request] = spec.buildRequests(bidRequests, bidderRequestWithOrtb2Device);
372
+
373
+ expect(request.data.device.w).to.equal(bidderRequestWithOrtb2Device.ortb2.device.w);
374
+ expect(request.data.device.h).to.equal(bidderRequestWithOrtb2Device.ortb2.device.h);
375
+ expect(request.data.device.dnt).to.equal(bidderRequestWithOrtb2Device.ortb2.device.dnt);
376
+ expect(request.data.device.ua).to.equal(bidderRequestWithOrtb2Device.ortb2.device.ua);
377
+ expect(request.data.device.language).to.equal(bidderRequestWithOrtb2Device.ortb2.device.language);
378
+ expect(request.data.device.devicetype).to.equal(bidderRequestWithOrtb2Device.ortb2.device.devicetype);
379
+ expect(request.data.device.make).to.equal(bidderRequestWithOrtb2Device.ortb2.device.make);
380
+ expect(request.data.device.model).to.equal(bidderRequestWithOrtb2Device.ortb2.device.model);
381
+ expect(request.data.device.os).to.equal(bidderRequestWithOrtb2Device.ortb2.device.os);
382
+ expect(request.data.device.osv).to.equal(bidderRequestWithOrtb2Device.ortb2.device.osv);
383
+ });
349
384
  });
350
385
 
351
386
  describe('no referer provided', () => {
@@ -1006,7 +1006,7 @@ describe('TrafficgateOpenxRtbAdapter', function () {
1006
1006
  // enrich bid request with userId key/value
1007
1007
 
1008
1008
  const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
1009
- expect(request[0].data.user.ext.eids).to.equal(userIdAsEids);
1009
+ expect(request[0].data.user.ext.eids).to.eql(userIdAsEids);
1010
1010
  });
1011
1011
 
1012
1012
  it(`when no user ids are available, it should not send any extended ids`, function () {
@@ -277,6 +277,13 @@ describe('ttdBidAdapter', function () {
277
277
  expect(url).to.equal('https://direct.adsrvr.org/bid/bidder/supplier');
278
278
  });
279
279
 
280
+ it('sends bid requests to the correct custom endpoint', function () {
281
+ let bannerBidRequestsWithCustomEndpoint = deepClone(baseBannerBidRequests);
282
+ bannerBidRequestsWithCustomEndpoint[0].params.useHttp2 = true;
283
+ const url = testBuildRequests(bannerBidRequestsWithCustomEndpoint, baseBidderRequest).url;
284
+ expect(url).to.equal('https://d2.adsrvr.org/bid/bidder/supplier');
285
+ });
286
+
280
287
  it('sends publisher id', function () {
281
288
  const requestBody = testBuildRequests(baseBannerBidRequests, baseBidderRequest).data;
282
289
  expect(requestBody.site).to.be.not.null;
@@ -442,7 +449,9 @@ describe('ttdBidAdapter', function () {
442
449
  let clonedBannerRequests = deepClone(baseBannerBidRequests);
443
450
  const battr = [1, 2, 3];
444
451
  clonedBannerRequests[0].ortb2Imp = {
445
- battr: battr
452
+ banner: {
453
+ battr: battr
454
+ }
446
455
  };
447
456
  const requestBody = testBuildRequests(clonedBannerRequests, baseBidderRequest).data;
448
457
  expect(requestBody.imp[0].banner.battr).to.equal(battr);
@@ -268,7 +268,7 @@ describe('viantOrtbBidAdapter', function () {
268
268
  });
269
269
  it('sends bid requests to the correct endpoint', function () {
270
270
  const url = testBuildRequests(baseBannerBidRequests, baseBidderRequest)[0].url;
271
- expect(url).to.equal('https://bidders-us-east-1.adelphic.net/d/rtb/v25/prebid/bidder');
271
+ expect(url).to.equal('https://bidders-us.adelphic.net/d/rtb/v25/prebid/bidder');
272
272
  });
273
273
 
274
274
  it('sends site', function () {
@@ -92,7 +92,7 @@ const VIDEO_BID = {
92
92
  'minduration': 0,
93
93
  'startdelay': 0,
94
94
  'linearity': 1,
95
- 'api': [2],
95
+ 'api': [2, 7],
96
96
  'placement': 1
97
97
  }
98
98
  }
@@ -157,8 +157,14 @@ const BIDDER_REQUEST = {
157
157
  segment: [{id: '243'}],
158
158
  },
159
159
  ],
160
+ },
161
+ source: {
162
+ ext: {
163
+ omidpn: 'MyIntegrationPartner',
164
+ omidpv: '7.1'
165
+ }
160
166
  }
161
- },
167
+ }
162
168
  };
163
169
 
164
170
  const SERVER_RESPONSE = {
@@ -359,7 +365,7 @@ describe('VidazooBidAdapter', function () {
359
365
  webSessionId: webSessionId,
360
366
  mediaTypes: {
361
367
  video: {
362
- api: [2],
368
+ api: [2, 7],
363
369
  context: 'instream',
364
370
  linearity: 1,
365
371
  maxduration: 60,
@@ -373,7 +379,9 @@ describe('VidazooBidAdapter', function () {
373
379
  protocols: [2, 3, 5, 6],
374
380
  startdelay: 0
375
381
  }
376
- }
382
+ },
383
+ omidpn: 'MyIntegrationPartner',
384
+ omidpv: '7.1'
377
385
  }
378
386
  })
379
387
  ;
@@ -0,0 +1,324 @@
1
+ import {
2
+ bidderData,
3
+ enrichBidderRequest,
4
+ lowEntropyData,
5
+ wurflSubmodule,
6
+ } from 'modules/wurflRtdProvider';
7
+ import * as ajaxModule from 'src/ajax';
8
+ import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js';
9
+
10
+ describe('wurflRtdProvider', function () {
11
+ describe('wurflSubmodule', function () {
12
+ const altHost = 'http://example.local/wurfl.js';
13
+ const wurfl_pbjs = {
14
+ low_entropy_caps: ['complete_device_name', 'form_factor', 'is_mobile'],
15
+ caps: [
16
+ 'advertised_browser',
17
+ 'advertised_browser_version',
18
+ 'advertised_device_os',
19
+ 'advertised_device_os_version',
20
+ 'brand_name',
21
+ 'complete_device_name',
22
+ 'form_factor',
23
+ 'is_app_webview',
24
+ 'is_full_desktop',
25
+ 'is_mobile',
26
+ 'is_robot',
27
+ 'is_smartphone',
28
+ 'is_smarttv',
29
+ 'is_tablet',
30
+ 'manufacturer_name',
31
+ 'marketing_name'
32
+ ],
33
+ authorized_bidders: {
34
+ 'bidder1': [0, 1, 2, 3, 4, 5, 6, 7, 10, 13, 15],
35
+ 'bidder2': [5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
36
+ }
37
+ }
38
+
39
+ const WURFL = {
40
+ advertised_browser: 'Chrome',
41
+ advertised_browser_version: '125.0.6422.76',
42
+ advertised_device_os: 'Linux',
43
+ advertised_device_os_version: '6.5.0',
44
+ brand_name: 'Google',
45
+ complete_device_name: 'Google Chrome',
46
+ form_factor: 'Desktop',
47
+ is_app_webview: !1,
48
+ is_full_desktop: !0,
49
+ is_mobile: !1,
50
+ is_robot: !1,
51
+ is_smartphone: !1,
52
+ is_smarttv: !1,
53
+ is_tablet: !1,
54
+ manufacturer_name: '',
55
+ marketing_name: '',
56
+ }
57
+
58
+ // expected analytics values
59
+ const expectedStatsURL = 'https://prebid.wurflcloud.com/v1/prebid/stats';
60
+ const expectedData = JSON.stringify({ bidders: ['bidder1', 'bidder2'] });
61
+
62
+ let sandbox;
63
+
64
+ beforeEach(function() {
65
+ sandbox = sinon.createSandbox();
66
+ window.WURFLPromises = {
67
+ init: new Promise(function(resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }),
68
+ complete: new Promise(function(resolve, reject) { resolve({ WURFL, wurfl_pbjs }) }),
69
+ };
70
+ });
71
+
72
+ afterEach(() => {
73
+ // Restore the original functions
74
+ sandbox.restore();
75
+ window.WURFLPromises = undefined;
76
+ });
77
+
78
+ // Bid request config
79
+ const reqBidsConfigObj = {
80
+ adUnits: [{
81
+ bids: [
82
+ { bidder: 'bidder1' },
83
+ { bidder: 'bidder2' },
84
+ { bidder: 'bidder3' },
85
+ ]
86
+ }],
87
+ ortb2Fragments: {
88
+ bidder: {},
89
+ }
90
+ };
91
+
92
+ it('initialises the WURFL RTD provider', function () {
93
+ expect(wurflSubmodule.init()).to.be.true;
94
+ });
95
+
96
+ it('should enrich the bid request data', (done) => {
97
+ const expectedURL = new URL(altHost);
98
+ expectedURL.searchParams.set('debug', true);
99
+ expectedURL.searchParams.set('mode', 'prebid');
100
+
101
+ const callback = () => {
102
+ expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({
103
+ bidder1: {
104
+ device: {
105
+ ext: {
106
+ wurfl: {
107
+ advertised_browser: 'Chrome',
108
+ advertised_browser_version: '125.0.6422.76',
109
+ advertised_device_os: 'Linux',
110
+ advertised_device_os_version: '6.5.0',
111
+ brand_name: 'Google',
112
+ complete_device_name: 'Google Chrome',
113
+ form_factor: 'Desktop',
114
+ is_app_webview: !1,
115
+ is_robot: !1,
116
+ is_tablet: !1,
117
+ marketing_name: '',
118
+ },
119
+ },
120
+ },
121
+ },
122
+ bidder2: {
123
+ device: {
124
+ ext: {
125
+ wurfl: {
126
+ complete_device_name: 'Google Chrome',
127
+ form_factor: 'Desktop',
128
+ is_app_webview: !1,
129
+ is_full_desktop: !0,
130
+ is_mobile: !1,
131
+ is_robot: !1,
132
+ is_smartphone: !1,
133
+ is_smarttv: !1,
134
+ is_tablet: !1,
135
+ manufacturer_name: '',
136
+ },
137
+ },
138
+ },
139
+ },
140
+ bidder3: {
141
+ device: {
142
+ ext: {
143
+ wurfl: {
144
+ complete_device_name: 'Google Chrome',
145
+ form_factor: 'Desktop',
146
+ is_mobile: !1,
147
+ },
148
+ },
149
+ },
150
+ },
151
+ });
152
+ done();
153
+ };
154
+
155
+ const config = {
156
+ params: {
157
+ altHost: altHost,
158
+ debug: true,
159
+ }
160
+ };
161
+ const userConsent = {};
162
+
163
+ wurflSubmodule.getBidRequestData(reqBidsConfigObj, callback, config, userConsent);
164
+ expect(loadExternalScriptStub.calledOnce).to.be.true;
165
+ const loadExternalScriptCall = loadExternalScriptStub.getCall(0);
166
+ expect(loadExternalScriptCall.args[0]).to.equal(expectedURL.toString());
167
+ expect(loadExternalScriptCall.args[1]).to.equal('wurfl');
168
+ });
169
+
170
+ it('onAuctionEndEvent: should send analytics data using navigator.sendBeacon, if available', () => {
171
+ const auctionDetails = {};
172
+ const config = {};
173
+ const userConsent = {};
174
+
175
+ const sendBeaconStub = sandbox.stub(navigator, 'sendBeacon');
176
+
177
+ // Call the function
178
+ wurflSubmodule.onAuctionEndEvent(auctionDetails, config, userConsent);
179
+
180
+ // Assertions
181
+ expect(sendBeaconStub.calledOnce).to.be.true;
182
+ expect(sendBeaconStub.calledWithExactly(expectedStatsURL, expectedData)).to.be.true;
183
+ });
184
+
185
+ it('onAuctionEndEvent: should send analytics data using fetch as fallback, if navigator.sendBeacon is not available', () => {
186
+ const auctionDetails = {};
187
+ const config = {};
188
+ const userConsent = {};
189
+
190
+ const sendBeaconStub = sandbox.stub(navigator, 'sendBeacon').value(undefined);
191
+ const windowFetchStub = sandbox.stub(window, 'fetch');
192
+ const fetchAjaxStub = sandbox.stub(ajaxModule, 'fetch');
193
+
194
+ // Call the function
195
+ wurflSubmodule.onAuctionEndEvent(auctionDetails, config, userConsent);
196
+
197
+ // Assertions
198
+ expect(sendBeaconStub.called).to.be.false;
199
+
200
+ expect(fetchAjaxStub.calledOnce).to.be.true;
201
+ const fetchAjaxCall = fetchAjaxStub.getCall(0);
202
+ expect(fetchAjaxCall.args[0]).to.equal(expectedStatsURL);
203
+ expect(fetchAjaxCall.args[1].method).to.equal('POST');
204
+ expect(fetchAjaxCall.args[1].body).to.equal(expectedData);
205
+ expect(fetchAjaxCall.args[1].mode).to.equal('no-cors');
206
+ });
207
+ });
208
+
209
+ describe('bidderData', () => {
210
+ it('should return the WURFL data for a bidder', () => {
211
+ const wjsData = {
212
+ capability1: 'value1',
213
+ capability2: 'value2',
214
+ capability3: 'value3',
215
+ };
216
+ const caps = ['capability1', 'capability2', 'capability3'];
217
+ const filter = [0, 2];
218
+
219
+ const result = bidderData(wjsData, caps, filter);
220
+
221
+ expect(result).to.deep.equal({
222
+ capability1: 'value1',
223
+ capability3: 'value3',
224
+ });
225
+ });
226
+
227
+ it('should return an empty object if the filter is empty', () => {
228
+ const wjsData = {
229
+ capability1: 'value1',
230
+ capability2: 'value2',
231
+ capability3: 'value3',
232
+ };
233
+ const caps = ['capability1', 'capability3'];
234
+ const filter = [];
235
+
236
+ const result = bidderData(wjsData, caps, filter);
237
+
238
+ expect(result).to.deep.equal({});
239
+ });
240
+ });
241
+
242
+ describe('lowEntropyData', () => {
243
+ it('should return the correct low entropy data for Apple devices', () => {
244
+ const wjsData = {
245
+ complete_device_name: 'Apple iPhone X',
246
+ form_factor: 'Smartphone',
247
+ is_mobile: !0,
248
+ };
249
+ const lowEntropyCaps = ['complete_device_name', 'form_factor', 'is_mobile'];
250
+ const expectedData = {
251
+ complete_device_name: 'Apple iPhone',
252
+ form_factor: 'Smartphone',
253
+ is_mobile: !0,
254
+ };
255
+ const result = lowEntropyData(wjsData, lowEntropyCaps);
256
+ expect(result).to.deep.equal(expectedData);
257
+ });
258
+
259
+ it('should return the correct low entropy data for Android devices', () => {
260
+ const wjsData = {
261
+ complete_device_name: 'Samsung SM-G981B (Galaxy S20 5G)',
262
+ form_factor: 'Smartphone',
263
+ is_mobile: !0,
264
+ };
265
+ const lowEntropyCaps = ['complete_device_name', 'form_factor', 'is_mobile'];
266
+ const expectedData = {
267
+ complete_device_name: 'Samsung SM-G981B (Galaxy S20 5G)',
268
+ form_factor: 'Smartphone',
269
+ is_mobile: !0,
270
+ };
271
+ const result = lowEntropyData(wjsData, lowEntropyCaps);
272
+ expect(result).to.deep.equal(expectedData);
273
+ });
274
+
275
+ it('should return an empty object if the lowEntropyCaps array is empty', () => {
276
+ const wjsData = {
277
+ complete_device_name: 'Samsung SM-G981B (Galaxy S20 5G)',
278
+ form_factor: 'Smartphone',
279
+ is_mobile: !0,
280
+ };
281
+ const lowEntropyCaps = [];
282
+ const expectedData = {};
283
+ const result = lowEntropyData(wjsData, lowEntropyCaps);
284
+ expect(result).to.deep.equal(expectedData);
285
+ });
286
+ });
287
+
288
+ describe('enrichBidderRequest', () => {
289
+ it('should enrich the bidder request with WURFL data', () => {
290
+ const reqBidsConfigObj = {
291
+ ortb2Fragments: {
292
+ bidder: {
293
+ exampleBidder: {
294
+ device: {
295
+ ua: 'user-agent',
296
+ }
297
+ }
298
+ }
299
+ }
300
+ };
301
+ const bidderCode = 'exampleBidder';
302
+ const wjsData = {
303
+ capability1: 'value1',
304
+ capability2: 'value2'
305
+ };
306
+
307
+ enrichBidderRequest(reqBidsConfigObj, bidderCode, wjsData);
308
+
309
+ expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({
310
+ exampleBidder: {
311
+ device: {
312
+ ua: 'user-agent',
313
+ ext: {
314
+ wurfl: {
315
+ capability1: 'value1',
316
+ capability2: 'value2'
317
+ }
318
+ }
319
+ }
320
+ }
321
+ });
322
+ });
323
+ });
324
+ });
@@ -6,13 +6,34 @@ describe('pbjs - ortb user eids', () => {
6
6
  setOrtbUserExtEids(req, {}, {
7
7
  bidRequests: [
8
8
  {
9
- userIdAsEids: {e: 'id'}
9
+ userIdAsEids: [{e: 'id'}]
10
10
  }
11
11
  ]
12
12
  });
13
- expect(req.user.ext.eids).to.eql({e: 'id'});
13
+ expect(req.user.ext.eids).to.eql([{e: 'id'}]);
14
14
  });
15
15
 
16
+ it('should not override eids from fpd', () => {
17
+ const req = {
18
+ user: {
19
+ ext: {
20
+ eids: [{existing: 'id'}]
21
+ }
22
+ }
23
+ };
24
+ setOrtbUserExtEids(req, {}, {
25
+ bidRequests: [
26
+ {
27
+ userIdAsEids: [{nw: 'id'}]
28
+ }
29
+ ]
30
+ });
31
+ expect(req.user.ext.eids).to.eql([
32
+ {nw: 'id'},
33
+ {existing: 'id'},
34
+ ])
35
+ })
36
+
16
37
  it('has no effect if requests have no eids', () => {
17
38
  const req = {};
18
39
  setOrtbUserExtEids(req, {}, [{}]);
@@ -1,4 +1,4 @@
1
- import setFocusTimeout from '../../../../src/utils/focusTimeout';
1
+ import {setFocusTimeout, reset} from '../../../../src/utils/focusTimeout';
2
2
 
3
3
  export const setDocumentHidden = (hidden) => {
4
4
  Object.defineProperty(document, 'hidden', {
@@ -9,10 +9,12 @@ export const setDocumentHidden = (hidden) => {
9
9
  };
10
10
 
11
11
  describe('focusTimeout', () => {
12
- let clock;
12
+ let clock, callback;
13
13
 
14
14
  beforeEach(() => {
15
+ reset()
15
16
  clock = sinon.useFakeTimers();
17
+ callback = sinon.spy();
16
18
  });
17
19
 
18
20
  afterEach(() => {
@@ -20,14 +22,21 @@ describe('focusTimeout', () => {
20
22
  })
21
23
 
22
24
  it('should invoke callback when page is visible', () => {
23
- let callback = sinon.stub();
24
25
  setFocusTimeout(callback, 2000);
25
26
  clock.tick(2000);
26
27
  expect(callback.called).to.be.true;
27
28
  });
28
29
 
30
+ it('should not choke if page starts hidden', () => {
31
+ setDocumentHidden(true);
32
+ reset();
33
+ setDocumentHidden(false);
34
+ setFocusTimeout(callback, 1000);
35
+ clock.tick(1000);
36
+ sinon.assert.called(callback);
37
+ })
38
+
29
39
  it('should not invoke callback if page was hidden', () => {
30
- let callback = sinon.stub();
31
40
  setFocusTimeout(callback, 2000);
32
41
  setDocumentHidden(true);
33
42
  clock.tick(3000);
@@ -35,7 +44,6 @@ describe('focusTimeout', () => {
35
44
  });
36
45
 
37
46
  it('should defer callback execution when page is hidden', () => {
38
- let callback = sinon.stub();
39
47
  setFocusTimeout(callback, 4000);
40
48
  clock.tick(2000);
41
49
  setDocumentHidden(true);
@@ -46,8 +54,27 @@ describe('focusTimeout', () => {
46
54
  expect(callback.called).to.be.true;
47
55
  });
48
56
 
57
+ it('should not execute deferred callbacks again', () => {
58
+ setDocumentHidden(true);
59
+ setFocusTimeout(callback, 1000);
60
+ clock.tick(2000);
61
+ [false, true, false].forEach(setDocumentHidden);
62
+ clock.tick(2000);
63
+ sinon.assert.calledOnce(callback);
64
+ });
65
+
66
+ it('should run callbacks that expire while page is hidden', () => {
67
+ setFocusTimeout(callback, 1000);
68
+ clock.tick(500);
69
+ setDocumentHidden(true);
70
+ clock.tick(1000);
71
+ setDocumentHidden(false);
72
+ sinon.assert.notCalled(callback);
73
+ clock.tick(1000);
74
+ sinon.assert.called(callback);
75
+ })
76
+
49
77
  it('should return updated timerId after page was showed again', () => {
50
- let callback = sinon.stub();
51
78
  const getCurrentTimerId = setFocusTimeout(callback, 4000);
52
79
  const oldTimerId = getCurrentTimerId();
53
80
  clock.tick(2000);