prebid.js 9.53.1 → 9.53.2

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 (185) hide show
  1. package/dist/33acrossAnalyticsAdapter.js +1 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/BTBidAdapter.js +1 -1
  5. package/dist/adagioAnalyticsAdapter.js +1 -1
  6. package/dist/adagioBidAdapter.js +1 -1
  7. package/dist/adagioUtils.js +1 -1
  8. package/dist/addefendBidAdapter.js +1 -1
  9. package/dist/adgenerationBidAdapter.js +1 -1
  10. package/dist/adlooxRtdProvider.js +1 -1
  11. package/dist/adqueryBidAdapter.js +1 -1
  12. package/dist/adrelevantisBidAdapter.js +1 -1
  13. package/dist/adstirBidAdapter.js +1 -1
  14. package/dist/adtrgtmeBidAdapter.js +1 -1
  15. package/dist/adxcgAnalyticsAdapter.js +1 -1
  16. package/dist/adxcgBidAdapter.js +1 -1
  17. package/dist/adyoulikeBidAdapter.js +1 -1
  18. package/dist/agmaAnalyticsAdapter.js +1 -1
  19. package/dist/ajaBidAdapter.js +1 -1
  20. package/dist/amxBidAdapter.js +1 -1
  21. package/dist/amxIdSystem.js +1 -1
  22. package/dist/aniviewBidAdapter.js +1 -1
  23. package/dist/appierAnalyticsAdapter.js +1 -1
  24. package/dist/appnexusBidAdapter.js +1 -1
  25. package/dist/asoBidAdapter.js +1 -1
  26. package/dist/axonixBidAdapter.js +1 -1
  27. package/dist/beopBidAdapter.js +1 -1
  28. package/dist/bidglassBidAdapter.js +1 -1
  29. package/dist/big-richmediaBidAdapter.js +1 -1
  30. package/dist/bitmediaBidAdapter.js +1 -1
  31. package/dist/bridBidAdapter.js +1 -1
  32. package/dist/bridgeuppBidAdapter.js +1 -1
  33. package/dist/bridgewellBidAdapter.js +1 -1
  34. package/dist/brightMountainMediaBidAdapter.js +1 -1
  35. package/dist/carodaBidAdapter.js +1 -1
  36. package/dist/chtnwBidAdapter.js +1 -1
  37. package/dist/chunk-core.js +1 -1
  38. package/dist/concertBidAdapter.js +1 -1
  39. package/dist/connectadBidAdapter.js +1 -1
  40. package/dist/consumableBidAdapter.js +1 -1
  41. package/dist/contxtfulBidAdapter.js +1 -1
  42. package/dist/conversantAnalyticsAdapter.js +1 -1
  43. package/dist/conversantBidAdapter.js +1 -1
  44. package/dist/craftBidAdapter.js +1 -1
  45. package/dist/criteoBidAdapter.js +1 -1
  46. package/dist/cwireBidAdapter.js +1 -1
  47. package/dist/dailymotionBidAdapter.js +1 -1
  48. package/dist/dependencies.json +6 -1
  49. package/dist/dspxBidAdapter.js +1 -1
  50. package/dist/dxkultureBidAdapter.js +1 -1
  51. package/dist/eplanningBidAdapter.js +1 -1
  52. package/dist/equativBidAdapter.js +1 -1
  53. package/dist/eskimiBidAdapter.js +1 -1
  54. package/dist/euidIdSystem.js +1 -1
  55. package/dist/exadsBidAdapter.js +1 -1
  56. package/dist/excoBidAdapter.js +1 -1
  57. package/dist/fanAdapter.js +1 -1
  58. package/dist/feedadBidAdapter.js +1 -1
  59. package/dist/finativeBidAdapter.js +1 -1
  60. package/dist/freewheel-sspBidAdapter.js +1 -1
  61. package/dist/gmosspBidAdapter.js +1 -1
  62. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  63. package/dist/greenbidsBidAdapter.js +1 -1
  64. package/dist/greenbidsRtdProvider.js +1 -1
  65. package/dist/gridBidAdapter.js +1 -1
  66. package/dist/gumgumBidAdapter.js +1 -1
  67. package/dist/h12mediaBidAdapter.js +1 -1
  68. package/dist/hypelabBidAdapter.js +1 -1
  69. package/dist/id5AnalyticsAdapter.js +1 -1
  70. package/dist/id5IdSystem.js +1 -1
  71. package/dist/imdsBidAdapter.js +1 -1
  72. package/dist/improvedigitalBidAdapter.js +1 -1
  73. package/dist/inmobiBidAdapter.js +1 -1
  74. package/dist/insticatorBidAdapter.js +1 -1
  75. package/dist/intentIqAnalyticsAdapter.js +1 -1
  76. package/dist/ixBidAdapter.js +1 -1
  77. package/dist/jixieBidAdapter.js +1 -1
  78. package/dist/justpremiumBidAdapter.js +1 -1
  79. package/dist/kargoBidAdapter.js +1 -1
  80. package/dist/kimberliteBidAdapter.js +1 -1
  81. package/dist/konduitAnalyticsAdapter.js +1 -1
  82. package/dist/kueezBidAdapter.js +1 -1
  83. package/dist/lassoBidAdapter.js +1 -1
  84. package/dist/lifestreetBidAdapter.js +1 -1
  85. package/dist/liveIntentId.js +1 -1
  86. package/dist/logicadBidAdapter.js +1 -1
  87. package/dist/loglyliftBidAdapter.js +1 -1
  88. package/dist/luceadBidAdapter.js +1 -1
  89. package/dist/mabidderBidAdapter.js +1 -1
  90. package/dist/madsenseBidAdapter.js +1 -1
  91. package/dist/magniteAnalyticsAdapter.js +1 -1
  92. package/dist/malltvAnalyticsAdapter.js +1 -1
  93. package/dist/marsmediaBidAdapter.js +1 -1
  94. package/dist/mediafuseBidAdapter.js +1 -1
  95. package/dist/medianetBidAdapter.js +1 -1
  96. package/dist/medianetUtils.js +1 -1
  97. package/dist/mediasquareBidAdapter.js +1 -1
  98. package/dist/mgidBidAdapter.js +1 -1
  99. package/dist/missenaBidAdapter.js +1 -1
  100. package/dist/mobilefuseBidAdapter.js +1 -1
  101. package/dist/nextMillenniumBidAdapter.js +1 -1
  102. package/dist/nexx360Utils.js +1 -1
  103. package/dist/nobidAnalyticsAdapter.js +1 -1
  104. package/dist/nobidBidAdapter.js +1 -1
  105. package/dist/nodalsAiRtdProvider.js +1 -1
  106. package/dist/not-for-prod/prebid.js +168 -168
  107. package/dist/oguryBidAdapter.js +1 -1
  108. package/dist/onetagBidAdapter.js +1 -1
  109. package/dist/ooloAnalyticsAdapter.js +1 -1
  110. package/dist/openxBidAdapter.js +1 -1
  111. package/dist/optidigitalBidAdapter.js +1 -1
  112. package/dist/orbidderBidAdapter.js +1 -1
  113. package/dist/outbrainBidAdapter.js +1 -1
  114. package/dist/pixfutureBidAdapter.js +1 -1
  115. package/dist/publinkIdSystem.js +1 -1
  116. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  117. package/dist/pubmaticBidAdapter.js +1 -1
  118. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  119. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  120. package/dist/pxyzBidAdapter.js +1 -1
  121. package/dist/quantcastBidAdapter.js +1 -1
  122. package/dist/readpeakBidAdapter.js +1 -1
  123. package/dist/relaidoBidAdapter.js +1 -1
  124. package/dist/retailspotBidAdapter.js +1 -1
  125. package/dist/rhythmoneBidAdapter.js +1 -1
  126. package/dist/riseUtils.js +1 -1
  127. package/dist/rubiconBidAdapter.js +1 -1
  128. package/dist/seedingAllianceBidAdapter.js +1 -1
  129. package/dist/seedtagBidAdapter.js +1 -1
  130. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  131. package/dist/sharethroughBidAdapter.js +1 -1
  132. package/dist/showheroes-bsBidAdapter.js +1 -1
  133. package/dist/smaatoBidAdapter.js +1 -1
  134. package/dist/smartadserverBidAdapter.js +1 -1
  135. package/dist/smartxBidAdapter.js +1 -1
  136. package/dist/smilewantedBidAdapter.js +1 -1
  137. package/dist/snigelBidAdapter.js +1 -1
  138. package/dist/sonobiBidAdapter.js +1 -1
  139. package/dist/sovrnBidAdapter.js +1 -1
  140. package/dist/sparteoBidAdapter.js +1 -1
  141. package/dist/sspBCBidAdapter.js +1 -1
  142. package/dist/stvBidAdapter.js +1 -1
  143. package/dist/sublimeBidAdapter.js +1 -1
  144. package/dist/taboolaBidAdapter.js +1 -1
  145. package/dist/tappxBidAdapter.js +1 -1
  146. package/dist/targetVideoBidAdapter.js +1 -1
  147. package/dist/teadsBidAdapter.js +1 -1
  148. package/dist/terceptAnalyticsAdapter.js +1 -1
  149. package/dist/themoneytizerBidAdapter.js +1 -1
  150. package/dist/trionBidAdapter.js +1 -1
  151. package/dist/tripleliftBidAdapter.js +1 -1
  152. package/dist/ttdBidAdapter.js +1 -1
  153. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  154. package/dist/uid2IdSystem.js +1 -1
  155. package/dist/underdogmediaBidAdapter.js +1 -1
  156. package/dist/undertoneBidAdapter.js +1 -1
  157. package/dist/unrulyBidAdapter.js +1 -1
  158. package/dist/userId.js +1 -1
  159. package/dist/vidazooUtils.js +1 -1
  160. package/dist/videobyteBidAdapter.js +1 -1
  161. package/dist/visxBidAdapter.js +1 -1
  162. package/dist/vuukleBidAdapter.js +1 -1
  163. package/dist/widespaceBidAdapter.js +1 -1
  164. package/dist/winrBidAdapter.js +1 -1
  165. package/dist/yahooAdsBidAdapter.js +1 -1
  166. package/dist/yandexBidAdapter.js +1 -1
  167. package/dist/yieldmoBidAdapter.js +1 -1
  168. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  169. package/libraries/liveIntentId/shared.js +16 -0
  170. package/modules/fanAdapter.js +318 -124
  171. package/modules/userId/index.js +30 -31
  172. package/package.json +4 -4
  173. package/test/spec/modules/euidIdSystem_spec.js +9 -3
  174. package/test/spec/modules/fanAdapter_spec.js +264 -268
  175. package/test/spec/modules/id5IdSystem_spec.js +57 -101
  176. package/test/spec/modules/idxIdSystem_spec.js +2 -75
  177. package/test/spec/modules/liveIntentExternalIdSystem_spec.js +5 -0
  178. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
  179. package/test/spec/modules/liveIntentIdSystem_spec.js +38 -0
  180. package/test/spec/modules/lmpIdSystem_spec.js +2 -81
  181. package/test/spec/modules/pubmaticBidAdapter_spec.js +411 -126
  182. package/test/spec/modules/sharedIdSystem_spec.js +3 -3
  183. package/test/spec/modules/uid2IdSystem_helpers.js +5 -2
  184. package/test/spec/modules/userId_spec.js +142 -387
  185. package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +3 -69
@@ -6,7 +6,7 @@ import { config } from 'src/config.js';
6
6
 
7
7
  describe('PubMatic adapter', () => {
8
8
  let firstBid, videoBid, firstResponse, response, videoResponse;
9
- let request = {};
9
+ const request = {};
10
10
  firstBid = {
11
11
  adUnitCode: 'Div1',
12
12
  bidder: 'pubmatic',
@@ -51,13 +51,13 @@ describe('PubMatic adapter', () => {
51
51
  js: 1,
52
52
  connectiontype: 6
53
53
  },
54
- site: {domain: 'ebay.com', page: 'https://ebay.com'},
54
+ site: {domain: 'ebay.com', page: 'https://ebay.com', publisher: {id: '5670'}},
55
55
  source: {}
56
56
  },
57
57
  ortb2Imp: {
58
58
  ext: {
59
- tid: '92489f71-1bf2-49a0-adf9-000cea934729',
60
- gpid: '/1111/homepage-leftnav',
59
+ tid: '92489f71-1bf2-49a0-adf9-000cea934729',
60
+ gpid: '/1111/homepage-leftnav',
61
61
  data: {
62
62
  pbadslot: '/1111/homepage-leftnav',
63
63
  adserver: {
@@ -70,11 +70,23 @@ describe('PubMatic adapter', () => {
70
70
  }
71
71
  }
72
72
  },
73
+ rtd: {
74
+ jwplayer: {
75
+ targeting: {
76
+ content: {
77
+ id: 'jwplayer-content-id'
78
+ },
79
+ segments: [
80
+ 'jwplayer-segment-1', 'jwplayer-segment-2'
81
+ ]
82
+ }
83
+ }
84
+ }
73
85
  }
74
86
  videoBid = {
75
87
  'seat': 'seat-id',
76
88
  'ext': {
77
- 'buyid': 'BUYER-ID-987'
89
+ 'buyid': 'BUYER-ID-987'
78
90
  },
79
91
  'bid': [{
80
92
  'id': '74858439-49D7-4169-BA5D-44A046315B2F',
@@ -90,13 +102,14 @@ describe('PubMatic adapter', () => {
90
102
  'dspid': 123
91
103
  },
92
104
  'dealid': 'PUBDEAL1',
93
- 'mtype': 2
105
+ 'mtype': 2,
106
+ 'params': {'outstreamAU': 'outstreamAU', 'renderer': 'renderer_test_pubmatic'}
94
107
  }]
95
108
  };
96
109
  firstResponse = {
97
110
  'seat': 'seat-id',
98
111
  'ext': {
99
- 'buyid': 'BUYER-ID-987'
112
+ 'buyid': 'BUYER-ID-987'
100
113
  },
101
114
  'bid': [{
102
115
  'id': '74858439-49D7-4169-BA5D-44A046315B2F',
@@ -117,20 +130,20 @@ describe('PubMatic adapter', () => {
117
130
  };
118
131
  response = {
119
132
  'body': {
120
- cur: 'USD',
121
- id: '93D3BAD6-E2E2-49FB-9D89-920B1761C865',
122
- seatbid: [firstResponse]
133
+ cur: 'USD',
134
+ id: '93D3BAD6-E2E2-49FB-9D89-920B1761C865',
135
+ seatbid: [firstResponse]
123
136
  }
124
137
  };
125
138
  videoResponse = {
126
139
  'body': {
127
- cur: 'USD',
128
- id: '93D3BAD6-E2E2-49FB-9D89-920B1761C865',
129
- seatbid: [videoBid]
140
+ cur: 'USD',
141
+ id: '93D3BAD6-E2E2-49FB-9D89-920B1761C865',
142
+ seatbid: [videoBid]
130
143
  }
131
144
  }
132
- let validBidRequests = [firstBid];
133
- let bidderRequest = {
145
+ const validBidRequests = [firstBid];
146
+ const bidderRequest = {
134
147
  bids: [firstBid],
135
148
  auctionId: 'ee3074fe-97ce-4681-9235-d7622aede74c',
136
149
  auctionStart: 1725514077194,
@@ -152,7 +165,8 @@ describe('PubMatic adapter', () => {
152
165
  site: {domain: 'ebay.com', page: 'https://ebay.com'},
153
166
  source: {}
154
167
  },
155
- timeout: 2000
168
+ timeout: 2000,
169
+
156
170
  };
157
171
  let videoBidRequest, videoBidderRequest, utilsLogWarnMock, nativeBidderRequest;
158
172
 
@@ -165,22 +179,23 @@ describe('PubMatic adapter', () => {
165
179
  it('should return false if publisherId is missing', () => {
166
180
  const bid = utils.deepClone(validBidRequests[0]);
167
181
  delete bid.params.publisherId;
168
- const isValid = spec.isBidRequestValid(bid);
169
- expect(isValid).to.equal(false);
170
- });
182
+ const isValid = spec.isBidRequestValid(bid);
183
+ expect(isValid).to.equal(false);
184
+ });
171
185
 
172
186
  it('should return false if publisherId is not of type string', () => {
173
187
  const bid = utils.deepClone(validBidRequests[0]);
174
188
  bid.params.publisherId = 5890;
175
- const isValid = spec.isBidRequestValid(bid);
176
- expect(isValid).to.equal(false);
177
- });
189
+ const isValid = spec.isBidRequestValid(bid);
190
+ expect(isValid).to.equal(false);
191
+ });
178
192
 
179
193
  if (FEATURES.VIDEO) {
180
194
  describe('VIDEO', () => {
181
195
  beforeEach(() => {
182
196
  videoBidRequest = utils.deepClone(validBidRequests[0]);
183
197
  delete videoBidRequest.mediaTypes.banner;
198
+ delete videoBidRequest.mediaTypes.native;
184
199
  videoBidRequest.mediaTypes.video = {
185
200
  playerSize: [
186
201
  [640, 480]
@@ -191,10 +206,12 @@ describe('PubMatic adapter', () => {
191
206
  skip: 1,
192
207
  linearity: 2
193
208
  }
209
+ videoBidRequest.params.outstreamAU = 'outstreamAU';
210
+ videoBidRequest.params.renderer = 'renderer_test_pubmatic'
194
211
  });
195
212
  it('should return false if mimes are missing in a video impression request', () => {
196
- const isValid = spec.isBidRequestValid(videoBidRequest);
197
- expect(isValid).to.equal(false);
213
+ const isValid = spec.isBidRequestValid(videoBidRequest);
214
+ expect(isValid).to.equal(false);
198
215
  });
199
216
 
200
217
  it('should return false if context is missing in a video impression request', () => {
@@ -206,9 +223,15 @@ describe('PubMatic adapter', () => {
206
223
  it('should return true if banner/native present, but outstreamAU or renderer is missing', () => {
207
224
  videoBidRequest.mediaTypes.video.mimes = ['video/flv'];
208
225
  videoBidRequest.mediaTypes.video.context = 'outstream';
226
+
209
227
  videoBidRequest.mediaTypes.banner = {
210
228
  sizes: [[728, 90], [160, 600]]
211
- }
229
+ };
230
+
231
+ // Remove width and height from the video object to test coverage for missing values
232
+ delete videoBidRequest.mediaTypes.video.width;
233
+ delete videoBidRequest.mediaTypes.video.height;
234
+
212
235
  const isValid = spec.isBidRequestValid(videoBidRequest);
213
236
  expect(isValid).to.equal(true);
214
237
  });
@@ -217,6 +240,11 @@ describe('PubMatic adapter', () => {
217
240
  const isValid = spec.isBidRequestValid(videoBidRequest);
218
241
  expect(isValid).to.equal(false);
219
242
  });
243
+
244
+ it('should return TRUE if outstreamAU or renderer is present', () => {
245
+ const isValid = spec.isBidRequestValid(videoBidRequest);
246
+ expect(isValid).to.equal(false);
247
+ });
220
248
  });
221
249
  }
222
250
  });
@@ -226,7 +254,6 @@ describe('PubMatic adapter', () => {
226
254
  it('should include previousAuctionInfo in request when available', () => {
227
255
  const bidRequestWithPrevAuction = utils.deepClone(validBidRequests[0]);
228
256
  const bidderRequestWithPrevAuction = utils.deepClone(bidderRequest);
229
-
230
257
  bidderRequestWithPrevAuction.ortb2 = bidderRequestWithPrevAuction.ortb2 || {};
231
258
  bidderRequestWithPrevAuction.ortb2.ext = bidderRequestWithPrevAuction.ortb2.ext || {};
232
259
  bidderRequestWithPrevAuction.ortb2.ext.prebid = bidderRequestWithPrevAuction.ortb2.ext.prebid || {};
@@ -273,14 +300,6 @@ describe('PubMatic adapter', () => {
273
300
  expect(imp[0]).to.have.property('ext').to.have.property('key_val');
274
301
  });
275
302
 
276
- it('should not add key_val if dctr is absent in parameters', () => {
277
- delete validBidRequests[0].params.dctr;
278
- const request = spec.buildRequests(validBidRequests, bidderRequest);
279
- const { imp } = request?.data;
280
- expect(imp).to.be.an('array');
281
- expect(imp[0]).to.have.property('ext').to.not.have.property('key_val');
282
- });
283
-
284
303
  it('should set w and h to the primary size for banner', () => {
285
304
  const request = spec.buildRequests(validBidRequests, bidderRequest);
286
305
  const { imp } = request?.data;
@@ -393,7 +412,7 @@ describe('PubMatic adapter', () => {
393
412
  expect(imp[0]).to.have.property('banner').to.have.property('pos').equal(0);
394
413
  });
395
414
 
396
- if (FEATURES.VIDEO) {
415
+ if (FEATURES.VIDEO) {
397
416
  describe('VIDEO', () => {
398
417
  beforeEach(() => {
399
418
  utilsLogWarnMock = sinon.stub(utils, 'logWarn');
@@ -412,10 +431,14 @@ describe('PubMatic adapter', () => {
412
431
  linearity: 1,
413
432
  placement: 2,
414
433
  plcmt: 1,
434
+ context: 'outstream',
415
435
  minbitrate: 10,
416
436
  maxbitrate: 10,
417
437
  playerSize: [640, 480]
418
438
  }
439
+ videoBidderRequest.bids[0].params.outstreamAU = 'outstreamAU';
440
+ videoBidderRequest.bids[0].params.renderer = 'renderer_test_pubmatic'
441
+ videoBidderRequest.bids[0].adUnitCode = 'Div1';
419
442
  });
420
443
 
421
444
  afterEach(() => {
@@ -467,8 +490,8 @@ describe('PubMatic adapter', () => {
467
490
  expect(imp[0]).to.have.property('video').to.have.property('h');
468
491
  });
469
492
  });
470
- }
471
- if (FEATURES.NATIVE) {
493
+ }
494
+ if (FEATURES.NATIVE) {
472
495
  describe('NATIVE', () => {
473
496
  beforeEach(() => {
474
497
  utilsLogWarnMock = sinon.stub(utils, 'logWarn');
@@ -512,60 +535,7 @@ describe('PubMatic adapter', () => {
512
535
  expect(imp[0]).to.have.property('native');
513
536
  });
514
537
  });
515
- }
516
- // describe('MULTIFORMAT', () => {
517
- // let multiFormatBidderRequest;
518
- // it('should have both banner & video impressions', () => {
519
- // multiFormatBidderRequest = utils.deepClone(bidderRequest);
520
- // multiFormatBidderRequest.bids[0].mediaTypes.video = {
521
- // skip: 1,
522
- // mimes: ['video/mp4', 'video/x-flv'],
523
- // minduration: 5,
524
- // maxduration: 30,
525
- // startdelay: 5,
526
- // playbackmethod: [1, 3],
527
- // api: [1, 2],
528
- // protocols: [2, 3],
529
- // battr: [13, 14],
530
- // linearity: 1,
531
- // placement: 2,
532
- // plcmt: 1,
533
- // minbitrate: 10,
534
- // maxbitrate: 10,
535
- // playerSize: [640, 480]
536
- // }
537
- // const request = spec.buildRequests(validBidRequests, multiFormatBidderRequest);
538
- // const { imp } = request?.data;
539
- // expect(imp).to.be.an('array');
540
- // expect(imp[0]).to.have.property('banner');
541
- // expect(imp[0].banner).to.have.property('topframe');
542
- // expect(imp[0].banner).to.have.property('format');
543
- // expect(imp[0]).to.have.property('video');
544
- // });
545
-
546
- // it('should have both banner & native impressions', () => {
547
- // multiFormatBidderRequest = utils.deepClone(bidderRequest);
548
- // multiFormatBidderRequest.bids[0].nativeOrtbRequest = {
549
- // ver: '1.2',
550
- // assets: [{
551
- // id: 0,
552
- // img: {
553
- // 'type': 3,
554
- // 'w': 300,
555
- // 'h': 250
556
- // },
557
- // required: 1,
558
- // }]
559
- // };
560
- // const request = spec.buildRequests(validBidRequests, multiFormatBidderRequest);
561
- // const { imp } = request?.data;
562
- // expect(imp).to.be.an('array');
563
- // expect(imp[0]).to.have.property('banner');
564
- // expect(imp[0].banner).to.have.property('topframe');
565
- // expect(imp[0].banner).to.have.property('format');
566
- // expect(imp[0]).to.have.property('native');
567
- // });
568
- // });
538
+ }
569
539
  });
570
540
 
571
541
  describe('rest of ORTB request', () => {
@@ -821,7 +791,7 @@ describe('PubMatic adapter', () => {
821
791
 
822
792
  describe('GPP', () => {
823
793
  it('should have gpp & gpp_sid in request if set using ortb2 and not present in request', () => {
824
- let copiedBidderRequest = utils.deepClone(bidderRequest);
794
+ const copiedBidderRequest = utils.deepClone(bidderRequest);
825
795
  copiedBidderRequest.ortb2.regs = {
826
796
  gpp: 'DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN',
827
797
  gpp_sid: [5]
@@ -839,14 +809,14 @@ describe('PubMatic adapter', () => {
839
809
  pubrender: 0,
840
810
  datatopub: 2,
841
811
  transparency: [
842
- {
812
+ {
843
813
  domain: 'platform1domain.com',
844
814
  dsaparams: [1]
845
- },
846
- {
815
+ },
816
+ {
847
817
  domain: 'SSP2domain.com',
848
818
  dsaparams: [1, 2]
849
- }
819
+ }
850
820
  ]
851
821
  };
852
822
  beforeEach(() => {
@@ -936,7 +906,34 @@ describe('PubMatic adapter', () => {
936
906
  };
937
907
 
938
908
  spec.onBidWon(bid);
909
+ expect(cpmAdjustment).to.deep.equal({
910
+ currency: 'USD',
911
+ originalCurrency: 'USD',
912
+ adjustment: [
913
+ {
914
+ cpmAdjustment: Number(((3 - 2.5) / 3).toFixed(2)), // Expected: 0.17
915
+ mediaType: 'banner',
916
+ metaMediaType: 'banner',
917
+ cpm: 2.5,
918
+ originalCpm: 3
919
+ }
920
+ ]
921
+ });
922
+ });
939
923
 
924
+ it('should invoke _calculateBidCpmAdjustment and correctly update cpmAdjustment currency is different', () => {
925
+ const bid = {
926
+ cpm: 2.5,
927
+ originalCpm: 3,
928
+ originalCurrency: 'USD',
929
+ currency: 'EUR',
930
+ mediaType: 'banner',
931
+ meta: { mediaType: 'banner' },
932
+ getCpmInNewCurrency: function(currency) {
933
+ return currency === 'EUR' ? 2.8 : this.cpm;
934
+ }
935
+ };
936
+ spec.onBidWon(bid);
940
937
  expect(cpmAdjustment).to.deep.equal({
941
938
  currency: 'USD',
942
939
  originalCurrency: 'USD',
@@ -951,40 +948,139 @@ describe('PubMatic adapter', () => {
951
948
  ]
952
949
  });
953
950
  });
954
- });
955
951
 
956
- // describe('USER ID/ EIDS', () => {
957
- // let copiedBidderRequest;
958
- // beforeEach(() => {
959
- // copiedBidderRequest = utils.deepClone(bidderRequest);
960
- // copiedBidderRequest.bids[0].userId = {
961
- // id5id : {
962
- // uid: 'id5id-xyz-user-id'
963
- // }
964
- // }
965
- // copiedBidderRequest.bids[0].userIdAsEids = [{
966
- // source: 'id5-sync.com',
967
- // uids: [{
968
- // 'id': "ID5*G3_osFE_-UHoUjSuA4T8-f51U-JTNOoGcb2aMpx1APnDy8pDwkKCzXCcoSb1HXIIw9AjWBOWmZ3QbMUDTXKq8MPPW8h0II9mBYkP4F_IXkvD-XG64NuFFDPKvez1YGGx",
969
- // 'atype': 1,
970
- // 'ext': {
971
- // 'linkType': 2,
972
- // 'pba': 'q6Vzr0jEebxzmvS8aSrVQJFoJnOxs9gKBKCOLw1y6ew='
973
- // }
974
- // }]
975
- // }]
976
- // });
977
-
978
- // it('should send gpid if specified', () => {
979
- // const request = spec.buildRequests(validBidRequests, copiedBidderRequest);
980
- // expect(request.data).to.have.property('user');
981
- // expect(request.data.user).to.have.property('eids');
982
- // });
983
- // });
952
+ it('should replace existing adjustment entry if mediaType and metaMediaType match', () => {
953
+ const bid1 = {
954
+ cpm: 2.5,
955
+ originalCpm: 3,
956
+ originalCurrency: 'USD',
957
+ currency: 'USD',
958
+ mediaType: 'banner',
959
+ meta: { mediaType: 'banner' }
960
+ };
961
+ const bid2 = {
962
+ cpm: 1.5,
963
+ originalCpm: 2,
964
+ originalCurrency: 'USD',
965
+ currency: 'USD',
966
+ mediaType: 'banner',
967
+ meta: { mediaType: 'banner' }
968
+ };
969
+
970
+ spec.onBidWon(bid1);
971
+ // Should add the first entry
972
+ expect(cpmAdjustment.adjustment.length).to.equal(1);
973
+ expect(cpmAdjustment.adjustment[0].cpm).to.equal(2.5);
974
+ spec.onBidWon(bid2);
975
+ // Should replace the entry, not add a new one
976
+ expect(cpmAdjustment.adjustment.length).to.equal(1);
977
+ expect(cpmAdjustment.adjustment[0].cpm).to.equal(1.5);
978
+ expect(cpmAdjustment.adjustment[0].originalCpm).to.equal(2);
979
+ });
980
+ });
984
981
  });
985
982
  });
986
983
 
987
984
  describe('Response', () => {
985
+ it('should parse native adm and set bidResponse.native, width, and height', () => {
986
+ // Prepare a valid native bidRequest
987
+ const bidRequest = utils.deepClone(validBidRequests[0]);
988
+ bidRequest.mediaTypes = {
989
+ native: {
990
+ title: { required: true, len: 140 }
991
+ }
992
+ };
993
+ delete bidRequest.mediaTypes.banner;
994
+ delete bidRequest.mediaTypes.video;
995
+ bidRequest.sizes = undefined;
996
+ const request = spec.buildRequests([bidRequest], bidderRequest);
997
+ // Prepare a valid native bid response with matching impid
998
+ const nativeAdm = JSON.stringify({ native: { assets: [{ id: 1, title: { text: 'Test' } }] } });
999
+ const nativeBid = {
1000
+ id: 'bid-id',
1001
+ impid: request.data.imp[0].id, // match the imp id
1002
+ price: 1.2,
1003
+ adm: nativeAdm,
1004
+ w: 123,
1005
+ h: 456,
1006
+ adomain: ['example.com'],
1007
+ mtype: 4 // NATIVE
1008
+ };
1009
+ const seatbid = [{ bid: [nativeBid] }];
1010
+ const nativeResponse = { body: { seatbid } };
1011
+ const bidResponses = spec.interpretResponse(nativeResponse, request);
1012
+ expect(bidResponses).to.be.an('array');
1013
+ expect(bidResponses[0]).to.exist;
1014
+ expect(bidResponses[0].native).to.exist;
1015
+ expect(bidResponses[0].width).to.equal(123);
1016
+ expect(bidResponses[0].height).to.equal(456);
1017
+ });
1018
+
1019
+ it('should handle invalid JSON in native adm gracefully', () => {
1020
+ // Prepare a valid native bidRequest
1021
+ const bidRequest = utils.deepClone(validBidRequests[0]);
1022
+ bidRequest.mediaTypes = {
1023
+ native: {
1024
+ title: { required: true, len: 140 }
1025
+ }
1026
+ };
1027
+ delete bidRequest.mediaTypes.banner;
1028
+ delete bidRequest.mediaTypes.video;
1029
+ bidRequest.sizes = undefined;
1030
+ const request = spec.buildRequests([bidRequest], bidderRequest);
1031
+
1032
+ // Prepare a native bid response with invalid JSON and matching impid
1033
+ const invalidAdm = '{ native: { assets: [ { id: 1, title: { text: "Test" } } ] }'; // missing closing }
1034
+ const nativeBid = {
1035
+ id: 'bid-id',
1036
+ impid: request.data.imp[0].id, // match the imp id
1037
+ price: 1.2,
1038
+ adm: invalidAdm,
1039
+ w: 123,
1040
+ h: 456,
1041
+ adomain: ['example.com'],
1042
+ mtype: 4 // NATIVE
1043
+ };
1044
+ const seatbid = [{ bid: [nativeBid] }];
1045
+ const nativeResponse = { body: { seatbid } };
1046
+ const bidResponses = spec.interpretResponse(nativeResponse, request);
1047
+ expect(bidResponses).to.be.an('array');
1048
+ expect(bidResponses.length).to.equal(0); // No bid should be returned if adm is invalid
1049
+ });
1050
+
1051
+ it('should set DEFAULT_WIDTH and DEFAULT_HEIGHT when bid.w and bid.h are missing for native', () => {
1052
+ // Prepare a valid native bidRequest
1053
+ const bidRequest = utils.deepClone(validBidRequests[0]);
1054
+ bidRequest.mediaTypes = {
1055
+ native: {
1056
+ title: { required: true, len: 140 }
1057
+ }
1058
+ };
1059
+ delete bidRequest.mediaTypes.banner;
1060
+ delete bidRequest.mediaTypes.video;
1061
+ bidRequest.sizes = undefined;
1062
+ const request = spec.buildRequests([bidRequest], bidderRequest);
1063
+ // Prepare a native bid response with missing w and h
1064
+ const nativeAdm = JSON.stringify({ native: { assets: [{ id: 1, title: { text: 'Test' } }] } });
1065
+ const nativeBid = {
1066
+ id: 'bid-id',
1067
+ impid: request.data.imp[0].id, // match the imp id
1068
+ price: 1.2,
1069
+ adm: nativeAdm,
1070
+ // w and h are intentionally missing
1071
+ adomain: ['example.com'],
1072
+ mtype: 4 // NATIVE
1073
+ };
1074
+ const seatbid = [{ bid: [nativeBid] }];
1075
+ const nativeResponse = { body: { seatbid } };
1076
+ const bidResponses = spec.interpretResponse(nativeResponse, request);
1077
+ expect(bidResponses).to.be.an('array');
1078
+ expect(bidResponses[0]).to.exist;
1079
+ expect(bidResponses[0].native).to.exist;
1080
+ expect(bidResponses[0].width).to.equal(0);
1081
+ expect(bidResponses[0].height).to.equal(0);
1082
+ });
1083
+
988
1084
  it('should return response in prebid format', () => {
989
1085
  const request = spec.buildRequests(validBidRequests, bidderRequest);
990
1086
  const bidResponse = spec.interpretResponse(response, request);
@@ -1056,7 +1152,7 @@ describe('PubMatic adapter', () => {
1056
1152
  if (FEATURES.VIDEO) {
1057
1153
  describe('VIDEO', () => {
1058
1154
  beforeEach(() => {
1059
- let videoBidderRequest = utils.deepClone(bidderRequest);
1155
+ const videoBidderRequest = utils.deepClone(bidderRequest);
1060
1156
  delete videoBidderRequest.bids[0].mediaTypes.banner;
1061
1157
  videoBidderRequest.bids[0].mediaTypes.video = {
1062
1158
  skip: 1,
@@ -1076,6 +1172,9 @@ describe('PubMatic adapter', () => {
1076
1172
  maxbitrate: 10,
1077
1173
  playerSize: [640, 480]
1078
1174
  }
1175
+ videoBidderRequest.bids[0].params.outstreamAU = 'outstreamAU';
1176
+ videoBidderRequest.bids[0].params.renderer = 'renderer_test_pubmatic';
1177
+ videoBidderRequest.bids[0].adUnitCode = 'Div1';
1079
1178
  });
1080
1179
 
1081
1180
  it('should generate video response', () => {
@@ -1104,6 +1203,30 @@ describe('PubMatic adapter', () => {
1104
1203
  expect(bidResponse[0]).to.have.property('playerHeight').to.equal(480);
1105
1204
  expect(bidResponse[0]).to.have.property('playerWidth').to.equal(640);
1106
1205
  });
1206
+
1207
+ it('should set renderer and rendererCode for outstream video with outstreamAU', () => {
1208
+ const request = spec.buildRequests(validBidRequests, videoBidderRequest);
1209
+ const bidResponse = spec.interpretResponse(videoResponse, request);
1210
+ expect(bidResponse).to.be.an('array');
1211
+ expect(bidResponse[0]).to.be.an('object');
1212
+ expect(bidResponse[0]).to.have.property('renderer');
1213
+ expect(bidResponse[0].renderer).to.be.an('object');
1214
+ expect(bidResponse[0]).to.have.property('rendererCode').to.equal('outstreamAU');
1215
+ });
1216
+
1217
+ it('should set width and height from playerWidth/playerHeight if not present in bid', () => {
1218
+ // Clone and modify the video response to remove w and h
1219
+ const modifiedVideoResponse = utils.deepClone(videoResponse);
1220
+ delete modifiedVideoResponse.body.seatbid[0].bid[0].w;
1221
+ delete modifiedVideoResponse.body.seatbid[0].bid[0].h;
1222
+ // Set up the request as usual
1223
+ const request = spec.buildRequests(validBidRequests, videoBidderRequest);
1224
+ // Interpret the response
1225
+ const bidResponses = spec.interpretResponse(modifiedVideoResponse, request);
1226
+ // playerWidth = 640, playerHeight = 480 from playerSize in the test setup
1227
+ expect(bidResponses[0].width).to.equal(640);
1228
+ expect(bidResponses[0].height).to.equal(480);
1229
+ });
1107
1230
  });
1108
1231
  }
1109
1232
 
@@ -1172,6 +1295,168 @@ describe('PubMatic adapter', () => {
1172
1295
  });
1173
1296
  });
1174
1297
  })
1298
+
1299
+ it('should add userIdAsEids to user.ext.eids when present in bidRequest', () => {
1300
+ const bidRequestWithEids = utils.deepClone(validBidRequests[0]);
1301
+ bidRequestWithEids.userIdAsEids = [
1302
+ {
1303
+ source: 'pubmatic',
1304
+ uids: [{ id: 'test-id-123' }]
1305
+ }
1306
+ ];
1307
+ // Create a clean bidderRequest without existing eids
1308
+ const cleanBidderRequest = utils.deepClone(bidderRequest);
1309
+ // Ensure user object exists
1310
+ cleanBidderRequest.user = cleanBidderRequest.user || {};
1311
+ cleanBidderRequest.user.ext = cleanBidderRequest.user.ext || {};
1312
+ delete cleanBidderRequest.user.ext.eids;
1313
+ // Also set userIdAsEids on the bidderRequest.bids[0] like MediaKeys test
1314
+ cleanBidderRequest.bids[0].userIdAsEids = bidRequestWithEids.userIdAsEids;
1315
+ const request = spec.buildRequests([bidRequestWithEids], cleanBidderRequest);
1316
+ expect(request.data.user).to.exist;
1317
+ expect(request.data.user.ext).to.exist;
1318
+ expect(request.data.user.ext.eids).to.deep.equal(bidRequestWithEids.userIdAsEids);
1319
+ });
1320
+ it('should not add userIdAsEids when req.user.ext.eids already exists', () => {
1321
+ const bidRequestWithEids = utils.deepClone(validBidRequests[0]);
1322
+ bidRequestWithEids.userIdAsEids = [
1323
+ {
1324
+ source: 'pubmatic',
1325
+ uids: [{ id: 'test-id-123' }]
1326
+ }
1327
+ ];
1328
+ // Create a bidderRequest with existing eids
1329
+ const bidderRequestWithExistingEids = utils.deepClone(bidderRequest);
1330
+ // Ensure user object exists and set existing eids
1331
+ bidderRequestWithExistingEids.user = bidderRequestWithExistingEids.user || {};
1332
+ bidderRequestWithExistingEids.user.ext = bidderRequestWithExistingEids.user.ext || {};
1333
+ bidderRequestWithExistingEids.user.ext.eids = [{ source: 'existing', uids: [{ id: 'existing-id' }] }];
1334
+ // Also set userIdAsEids on the bidderRequest.bids[0] like MediaKeys test
1335
+ bidderRequestWithExistingEids.bids[0].userIdAsEids = bidRequestWithEids.userIdAsEids;
1336
+ // Set existing eids in ortb2.user.ext.eids so the converter will merge them
1337
+ // and the adapter will see them as already existing
1338
+ bidderRequestWithExistingEids.ortb2 = bidderRequestWithExistingEids.ortb2 || {};
1339
+ bidderRequestWithExistingEids.ortb2.user = bidderRequestWithExistingEids.ortb2.user || {};
1340
+ bidderRequestWithExistingEids.ortb2.user.ext = bidderRequestWithExistingEids.ortb2.user.ext || {};
1341
+ bidderRequestWithExistingEids.ortb2.user.ext.eids = [{ source: 'existing', uids: [{ id: 'existing-id' }] }];
1342
+ const request = spec.buildRequests([bidRequestWithEids], bidderRequestWithExistingEids);
1343
+ expect(request.data.user).to.exist;
1344
+ expect(request.data.user.ext).to.exist;
1345
+ expect(request.data.user.ext.eids).to.deep.equal(bidderRequestWithExistingEids.ortb2.user.ext.eids);
1346
+ });
1347
+
1348
+ it('should copy geo from device to user when device has geo but user does not', () => {
1349
+ const bidRequestWithDeviceGeo = utils.deepClone(validBidRequests[0]);
1350
+ // Create a clean bidderRequest without existing geo data
1351
+ const cleanBidderRequest = utils.deepClone(bidderRequest);
1352
+ // Ensure user and device objects exist
1353
+ cleanBidderRequest.user = cleanBidderRequest.user || {};
1354
+ cleanBidderRequest.ortb2 = cleanBidderRequest.ortb2 || {};
1355
+ cleanBidderRequest.ortb2.user = cleanBidderRequest.ortb2.user || {};
1356
+ cleanBidderRequest.ortb2.device = cleanBidderRequest.ortb2.device || {};
1357
+ delete cleanBidderRequest.user.geo;
1358
+ delete cleanBidderRequest.ortb2.user.geo;
1359
+ // Set geo data in bidderRequest.ortb2.device.geo so the converter will merge it
1360
+ cleanBidderRequest.ortb2.device.geo = { lat: 40.7128, lon: -74.0060 };
1361
+ const request = spec.buildRequests([bidRequestWithDeviceGeo], cleanBidderRequest);
1362
+ expect(request.data.user).to.exist;
1363
+ expect(request.data.user.geo).to.deep.equal({ lat: 40.7128, lon: -74.0060 });
1364
+ });
1365
+
1366
+ it('should copy geo from user to device when user has geo but device does not', () => {
1367
+ const bidRequestWithUserGeo = utils.deepClone(validBidRequests[0]);
1368
+ // Create a clean bidderRequest without existing geo data
1369
+ const cleanBidderRequest = utils.deepClone(bidderRequest);
1370
+ // Ensure device object exists
1371
+ cleanBidderRequest.device = cleanBidderRequest.device || {};
1372
+ cleanBidderRequest.ortb2 = cleanBidderRequest.ortb2 || {};
1373
+ cleanBidderRequest.ortb2.device = cleanBidderRequest.ortb2.device || {};
1374
+ cleanBidderRequest.ortb2.user = cleanBidderRequest.ortb2.user || {};
1375
+ delete cleanBidderRequest.device.geo;
1376
+ delete cleanBidderRequest.ortb2.device.geo;
1377
+ // Set geo data in bidderRequest.ortb2.user.geo so the converter will merge it
1378
+ cleanBidderRequest.ortb2.user.geo = { lat: 40.7128, lon: -74.0060 };
1379
+ const request = spec.buildRequests([bidRequestWithUserGeo], cleanBidderRequest);
1380
+ expect(request.data.device).to.exist;
1381
+ expect(request.data.device.geo).to.deep.equal({ lat: 40.7128, lon: -74.0060 });
1382
+ });
1383
+
1384
+ it('should update site.page with kadpageurl when present', () => {
1385
+ const bidRequestWithKadPageUrl = utils.deepClone(validBidRequests[0]);
1386
+ bidRequestWithKadPageUrl.params.kadpageurl = 'https://example.com/page';
1387
+ const request = spec.buildRequests([bidRequestWithKadPageUrl], bidderRequest);
1388
+ expect(request.data.site).to.exist;
1389
+ expect(request.data.site.page).to.equal('https://example.com/page');
1390
+ });
1391
+
1392
+ it('should set site.publisher.id from pubId', () => {
1393
+ // Ensure site.publisher structure exists in bidderRequest.ortb2
1394
+ const bidderRequestWithPublisher = utils.deepClone(bidderRequest);
1395
+ bidderRequestWithPublisher.ortb2 = bidderRequestWithPublisher.ortb2 || {};
1396
+ bidderRequestWithPublisher.ortb2.site = bidderRequestWithPublisher.ortb2.site || {};
1397
+ bidderRequestWithPublisher.ortb2.site.publisher = bidderRequestWithPublisher.ortb2.site.publisher || {};
1398
+ const request = spec.buildRequests(validBidRequests, bidderRequestWithPublisher);
1399
+ expect(request.data.site).to.exist;
1400
+ expect(request.data.site.publisher).to.exist;
1401
+ expect(request.data.site.publisher.id).to.equal('5670'); // pubId from params
1402
+ });
1403
+
1404
+ it('should set site.ref from refURL when not already present', () => {
1405
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
1406
+ expect(request.data.site).to.exist;
1407
+ // Check if site.ref exists (it might be set to empty string or undefined)
1408
+ if (request.data.site.ref !== undefined) {
1409
+ expect(request.data.site.ref).to.exist;
1410
+ }
1411
+ });
1412
+
1413
+ it('should build a basic request successfully', () => {
1414
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
1415
+ expect(request.data).to.exist;
1416
+ expect(request.data.imp).to.be.an('array');
1417
+ expect(request.data.imp.length).to.be.greaterThan(0);
1418
+ });
1419
+
1420
+ it('should set floor values correctly for multi-format requests using getFloor', () => {
1421
+ // Start with a valid bid
1422
+ const testBid = utils.deepClone(validBidRequests[0]);
1423
+ testBid.mediaTypes = {
1424
+ banner: {
1425
+ sizes: [[300, 250], [728, 90]],
1426
+ format: [{ w: 300, h: 250 }, { w: 728, h: 90 }]
1427
+ },
1428
+ video: {},
1429
+ native: {}
1430
+ };
1431
+ testBid.getFloor = ({ currency, mediaType, size }) => {
1432
+ if (mediaType === 'banner') return { currency: 'AUD', floor: 2.5 };
1433
+ if (mediaType === 'video') return { currency: 'AUD', floor: 1.5 };
1434
+ if (mediaType === 'native') return { currency: 'AUD', floor: 1.0 };
1435
+ return { currency: 'AUD', floor: 0 };
1436
+ };
1437
+ const testBidderRequest = {
1438
+ bids: [testBid],
1439
+ auctionId: 'test-auction',
1440
+ bidderCode: 'pubmatic',
1441
+ refererInfo: { page: 'https://example.com', ref: '' },
1442
+ ortb2: { device: { w: 1200, h: 1800 }, site: { domain: 'example.com', page: 'https://example.com' } },
1443
+ timeout: 2000
1444
+ };
1445
+ const request = spec.buildRequests([testBid], testBidderRequest);
1446
+ expect(request).to.exist;
1447
+ const builtImp = request.data.imp[0];
1448
+ if (builtImp.banner && builtImp.banner.ext) {
1449
+ expect(builtImp.banner.ext).to.deep.equal({ bidfloor: 1, bidfloorcur: 'AUD' });
1450
+ }
1451
+ if (builtImp.video && builtImp.video.ext) {
1452
+ expect(builtImp.video.ext).to.deep.equal({ bidfloor: 1, bidfloorcur: 'AUD' });
1453
+ }
1454
+ if (builtImp.native && builtImp.native.ext) {
1455
+ expect(builtImp.native.ext).to.deep.equal({ bidfloor: 1, bidfloorcur: 'AUD' });
1456
+ }
1457
+ // The impression-level bidfloor should match the banner floor (2.5)
1458
+ expect(builtImp.bidfloor).to.equal(2.5);
1459
+ });
1175
1460
  })
1176
1461
 
1177
1462
  describe('addViewabilityToImp', () => {