prebid.js 5.18.0 → 6.1.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 (150) hide show
  1. package/.babelrc.js +1 -10
  2. package/README.md +3 -1
  3. package/browsers.json +1 -8
  4. package/gulpfile.js +1 -0
  5. package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
  6. package/modules/.submodules.json +1 -0
  7. package/modules/adfBidAdapter.js +21 -16
  8. package/modules/adheseBidAdapter.js +7 -2
  9. package/modules/adkernelBidAdapter.js +1 -0
  10. package/modules/adlivetechBidAdapter.md +61 -0
  11. package/modules/adomikAnalyticsAdapter.js +10 -4
  12. package/modules/adtelligentBidAdapter.js +2 -1
  13. package/modules/airgridRtdProvider.js +1 -1
  14. package/modules/akamaiDapRtdProvider.js +474 -0
  15. package/modules/akamaiDapRtdProvider.md +47 -0
  16. package/modules/appnexusBidAdapter.js +9 -3
  17. package/modules/atsAnalyticsAdapter.js +67 -46
  18. package/modules/atsAnalyticsAdapter.md +1 -0
  19. package/modules/betweenBidAdapter.js +20 -3
  20. package/modules/browsiRtdProvider.js +106 -18
  21. package/modules/cleanioRtdProvider.js +192 -0
  22. package/modules/cleanioRtdProvider.md +59 -0
  23. package/modules/codefuelBidAdapter.js +181 -0
  24. package/modules/codefuelBidAdapter.md +111 -0
  25. package/modules/connectIdSystem.js +104 -0
  26. package/modules/connectIdSystem.md +33 -0
  27. package/modules/datablocksBidAdapter.js +3 -3
  28. package/modules/deepintentBidAdapter.js +107 -10
  29. package/modules/deepintentBidAdapter.md +36 -1
  30. package/modules/deltaprojectsBidAdapter.js +252 -0
  31. package/modules/deltaprojectsBidAdapter.md +32 -0
  32. package/modules/engageyaBidAdapter.js +171 -0
  33. package/modules/glimpseBidAdapter.js +31 -16
  34. package/modules/gptPreAuction.js +11 -5
  35. package/modules/gridBidAdapter.js +1 -0
  36. package/modules/gumgumBidAdapter.js +8 -0
  37. package/modules/id5IdSystem.md +6 -6
  38. package/modules/imRtdProvider.js +31 -0
  39. package/modules/inskinBidAdapter.js +7 -3
  40. package/modules/ixBidAdapter.js +174 -22
  41. package/modules/jixieBidAdapter.js +8 -2
  42. package/modules/justpremiumBidAdapter.js +6 -1
  43. package/modules/limelightDigitalBidAdapter.js +22 -2
  44. package/modules/livewrappedAnalyticsAdapter.js +49 -1
  45. package/modules/merkleIdSystem.js +5 -0
  46. package/modules/multibid/index.js +3 -3
  47. package/modules/nativoBidAdapter.js +32 -2
  48. package/modules/nextMillenniumBidAdapter.js +12 -3
  49. package/modules/oguryBidAdapter.js +16 -2
  50. package/modules/openxBidAdapter.js +40 -23
  51. package/modules/operaadsBidAdapter.js +21 -1
  52. package/modules/otmBidAdapter.js +146 -0
  53. package/modules/otmBidAdapter.md +27 -26
  54. package/modules/outbrainBidAdapter.js +5 -0
  55. package/modules/playwireBidAdapter.md +61 -0
  56. package/modules/prebidServerBidAdapter/index.js +3 -3
  57. package/modules/publinkIdSystem.js +11 -6
  58. package/modules/pubmaticBidAdapter.js +2 -0
  59. package/modules/rtdModule/index.js +2 -2
  60. package/modules/saambaaBidAdapter.js +420 -0
  61. package/modules/saambaaBidAdapter.md +65 -68
  62. package/modules/seedtagBidAdapter.js +6 -0
  63. package/modules/smaatoBidAdapter.js +6 -1
  64. package/modules/sonobiBidAdapter.js +7 -0
  65. package/modules/sortableBidAdapter.js +1 -0
  66. package/modules/sspBCBidAdapter.js +34 -3
  67. package/modules/teadsBidAdapter.js +3 -0
  68. package/modules/tripleliftBidAdapter.js +22 -5
  69. package/modules/trustxBidAdapter.js +18 -7
  70. package/modules/undertoneBidAdapter.js +9 -5
  71. package/modules/undertoneBidAdapter.md +5 -1
  72. package/modules/userId/eids.js +18 -0
  73. package/modules/userId/eids.md +7 -0
  74. package/modules/userId/userId.md +12 -0
  75. package/modules/ventesBidAdapter.js +370 -0
  76. package/modules/ventesBidAdapter.md +94 -0
  77. package/modules/videobyteBidAdapter.js +13 -6
  78. package/modules/videobyteBidAdapter.md +49 -0
  79. package/modules/vidoomyBidAdapter.js +51 -100
  80. package/modules/visxBidAdapter.js +1 -1
  81. package/modules/yahoosspBidAdapter.js +6 -6
  82. package/modules/yieldlabBidAdapter.js +41 -10
  83. package/modules/yieldlabBidAdapter.md +91 -48
  84. package/modules/yieldmoSyntheticInventoryModule.js +46 -0
  85. package/modules/yieldmoSyntheticInventoryModule.md +68 -0
  86. package/package.json +6 -1
  87. package/src/adapterManager.js +19 -8
  88. package/src/adapters/bidderFactory.js +4 -3
  89. package/src/auction.js +11 -11
  90. package/src/constants.json +1 -0
  91. package/src/secureCreatives.js +6 -7
  92. package/src/targeting.js +11 -9
  93. package/test/spec/modules/adfBidAdapter_spec.js +83 -29
  94. package/test/spec/modules/adheseBidAdapter_spec.js +27 -1
  95. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  96. package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
  97. package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +16 -1
  99. package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
  100. package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
  101. package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
  102. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  103. package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
  104. package/test/spec/modules/connectIdSystem_spec.js +189 -0
  105. package/test/spec/modules/datablocksBidAdapter_spec.js +3 -3
  106. package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
  107. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  108. package/test/spec/modules/engageyaBidAdapter_spec.js +422 -0
  109. package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
  110. package/test/spec/modules/glimpseBidAdapter_spec.js +33 -0
  111. package/test/spec/modules/gptPreAuction_spec.js +58 -4
  112. package/test/spec/modules/gumgumBidAdapter_spec.js +5 -1
  113. package/test/spec/modules/imRtdProvider_spec.js +25 -0
  114. package/test/spec/modules/ixBidAdapter_spec.js +298 -5
  115. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  116. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  117. package/test/spec/modules/konduitWrapper_spec.js +0 -1
  118. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
  119. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +52 -7
  120. package/test/spec/modules/merkleIdSystem_spec.js +18 -0
  121. package/test/spec/modules/multibid_spec.js +31 -31
  122. package/test/spec/modules/nativoBidAdapter_spec.js +35 -18
  123. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
  124. package/test/spec/modules/oguryBidAdapter_spec.js +66 -23
  125. package/test/spec/modules/openxBidAdapter_spec.js +90 -13
  126. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  127. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  128. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  129. package/test/spec/modules/prebidServerBidAdapter_spec.js +19 -2
  130. package/test/spec/modules/publinkIdSystem_spec.js +6 -6
  131. package/test/spec/modules/seedtagBidAdapter_spec.js +3 -0
  132. package/test/spec/modules/smaatoBidAdapter_spec.js +30 -0
  133. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  134. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  135. package/test/spec/modules/sspBCBidAdapter_spec.js +33 -3
  136. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  137. package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
  138. package/test/spec/modules/trustxBidAdapter_spec.js +45 -3
  139. package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
  140. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  141. package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
  142. package/test/spec/modules/vidoomyBidAdapter_spec.js +32 -13
  143. package/test/spec/modules/visxBidAdapter_spec.js +1 -1
  144. package/test/spec/modules/yieldlabBidAdapter_spec.js +81 -0
  145. package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
  146. package/test/spec/unit/core/adapterManager_spec.js +56 -6
  147. package/test/spec/unit/core/bidderFactory_spec.js +61 -1
  148. package/test/spec/unit/pbjs_api_spec.js +37 -2
  149. package/test/spec/unit/secureCreatives_spec.js +54 -25
  150. package/wdio.conf.js +1 -1
@@ -153,7 +153,7 @@ describe('VideoByteBidAdapter', function () {
153
153
  it('should create a POST request for every bid', function () {
154
154
  const requests = spec.buildRequests([bidRequest], bidderRequest);
155
155
  expect(requests[0].method).to.equal('POST');
156
- expect(requests[0].url).to.equal(spec.ENDPOINT + bidRequest.params.pubId);
156
+ expect(requests[0].url).to.equal(spec.ENDPOINT + '?pid=' + bidRequest.params.pubId);
157
157
  });
158
158
 
159
159
  it('should attach request data', function () {
@@ -172,7 +172,7 @@ describe('VideoByteBidAdapter', function () {
172
172
  bidRequest.params.video.e2etest = true;
173
173
  const requests = spec.buildRequests([bidRequest], bidderRequest);
174
174
  expect(requests[0].method).to.equal('POST');
175
- expect(requests[0].url).to.equal(spec.ENDPOINT + 'e2etest');
175
+ expect(requests[0].url).to.equal(spec.ENDPOINT + '?pid=e2etest');
176
176
  });
177
177
 
178
178
  it('should attach End 2 End test data', function () {
@@ -4,6 +4,7 @@ import { newBidder } from 'src/adapters/bidderFactory.js';
4
4
  import { INSTREAM } from '../../../src/video';
5
5
 
6
6
  const ENDPOINT = `https://d.vidoomy.com/api/rtbserver/prebid/`;
7
+ const PIXELS = ['/test.png', '/test2.png?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}']
7
8
 
8
9
  describe('vidoomyBidAdapter', function() {
9
10
  const adapter = newBidder(spec);
@@ -101,24 +102,24 @@ describe('vidoomyBidAdapter', function() {
101
102
  });
102
103
 
103
104
  it('attaches source and version to endpoint URL as query params', function () {
104
- expect(request[0].url).to.include(ENDPOINT);
105
- expect(request[1].url).to.include(ENDPOINT);
105
+ expect(request[0].url).to.equal(ENDPOINT);
106
+ expect(request[1].url).to.equal(ENDPOINT);
106
107
  });
107
108
 
108
109
  it('only accepts first width and height sizes', function () {
109
- expect(request[0].url).to.include('w=300');
110
- expect(request[0].url).to.include('h=250');
111
- expect(request[0].url).to.not.include('w=200');
112
- expect(request[0].url).to.not.include('h=100');
113
- expect(request[1].url).to.include('w=400');
114
- expect(request[1].url).to.include('h=225');
110
+ expect('' + request[0].data.w).to.equal('300');
111
+ expect('' + request[0].data.h).to.equal('250');
112
+ expect('' + request[0].data.w).to.not.equal('200');
113
+ expect('' + request[0].data.h).to.not.equal('100');
114
+ expect('' + request[1].data.w).to.equal('400');
115
+ expect('' + request[1].data.h).to.equal('225');
115
116
  });
116
117
 
117
118
  it('should send id and pid parameters', function () {
118
- expect(request[0].url).to.include('id=123123');
119
- expect(request[0].url).to.include('pid=123123');
120
- expect(request[1].url).to.include('id=456456');
121
- expect(request[1].url).to.include('pid=456456');
119
+ expect('' + request[0].data.id).to.equal('123123');
120
+ expect('' + request[0].data.pid).to.equal('123123');
121
+ expect('' + request[1].data.id).to.equal('456456');
122
+ expect('' + request[1].data.pid).to.equal('456456');
122
123
  });
123
124
  });
124
125
 
@@ -182,7 +183,8 @@ describe('vidoomyBidAdapter', function() {
182
183
  'networkName': null,
183
184
  'primaryCatId': 'IAB3-1',
184
185
  'secondaryCatIds': null
185
- }
186
+ },
187
+ 'pixels': PIXELS
186
188
  }
187
189
  }
188
190
 
@@ -206,5 +208,22 @@ describe('vidoomyBidAdapter', function() {
206
208
 
207
209
  expect(result[0].requestId).to.equal(serverResponseBanner.body.requestId);
208
210
  });
211
+
212
+ it('should sync user cookies', function () {
213
+ const GDPR_CONSENT = 'GDPR_TEST'
214
+ const result = spec.getUserSyncs({
215
+ pixelEnabled: true
216
+ }, [serverResponseBanner], { consentString: GDPR_CONSENT, gdprApplies: 1 }, null)
217
+ expect(result).to.eql([
218
+ {
219
+ type: 'image',
220
+ url: PIXELS[0]
221
+ },
222
+ {
223
+ type: 'image',
224
+ url: `/test2.png?gdpr=1&gdpr_consent=${GDPR_CONSENT}`
225
+ }
226
+ ])
227
+ });
209
228
  });
210
229
  });
@@ -1149,7 +1149,7 @@ describe('VisxAdapter', function () {
1149
1149
  it('onTimeout', function () {
1150
1150
  const data = { timeout: 3000, bidId: '23423', params: { uid: 1 } };
1151
1151
  spec.onTimeout(data);
1152
- expect(utils.triggerPixel.calledOnceWith('https://t.visx.net/track/bid_timeout?data=' + JSON.stringify(data))).to.equal(true);
1152
+ expect(utils.triggerPixel.calledOnceWith('https://t.visx.net/track/bid_timeout//' + JSON.stringify(data))).to.equal(true);
1153
1153
  });
1154
1154
  });
1155
1155
 
@@ -73,6 +73,12 @@ const VIDEO_REQUEST = Object.assign({}, REQUEST, {
73
73
  }
74
74
  })
75
75
 
76
+ const NATIVE_REQUEST = Object.assign({}, REQUEST, {
77
+ 'mediaTypes': {
78
+ 'native': { }
79
+ }
80
+ })
81
+
76
82
  const RESPONSE = {
77
83
  advertiser: 'yieldlab',
78
84
  curl: 'https://www.yieldlab.de',
@@ -84,6 +90,42 @@ const RESPONSE = {
84
90
  adtype: 'BANNER'
85
91
  }
86
92
 
93
+ const NATIVE_RESPONSE = Object.assign({}, RESPONSE, {
94
+ 'adtype': 'NATIVE',
95
+ 'native': {
96
+ 'link': {
97
+ 'url': 'https://www.yieldlab.de'
98
+ },
99
+ 'assets': [
100
+ {
101
+ 'id': 1,
102
+ 'title': {
103
+ 'text': 'This is a great headline'
104
+ }
105
+ },
106
+ {
107
+ 'id': 2,
108
+ 'img': {
109
+ 'url': 'https://localhost:8080/yl-logo100x100.jpg',
110
+ 'w': 100,
111
+ 'h': 100
112
+ }
113
+ },
114
+ {
115
+ 'id': 3,
116
+ 'data': {
117
+ 'value': 'Native body value'
118
+ }
119
+ }
120
+ ],
121
+ 'imptrackers': [
122
+ 'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12',
123
+ 'http://localhost:8080/md/1111/9efa4e76-2030-4f04-bb9f-322541f8d611?mdata=false&pvid=false&ids=x:1',
124
+ 'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0'
125
+ ]
126
+ }
127
+ })
128
+
87
129
  const VIDEO_RESPONSE = Object.assign({}, RESPONSE, {
88
130
  'adtype': 'VIDEO'
89
131
  })
@@ -297,6 +339,45 @@ describe('yieldlabBidAdapter', function () {
297
339
  expect(result[0].vastUrl).to.include('&id=abc')
298
340
  })
299
341
 
342
+ it('should add adUrl and native assets when type is Native', function () {
343
+ const result = spec.interpretResponse({body: [NATIVE_RESPONSE]}, {validBidRequests: [NATIVE_REQUEST], queryParams: REQPARAMS})
344
+
345
+ expect(result[0].requestId).to.equal('2d925f27f5079f')
346
+ expect(result[0].cpm).to.equal(0.01)
347
+ expect(result[0].mediaType).to.equal('native')
348
+ expect(result[0].adUrl).to.include('https://ad.yieldlab.net/d/1111/2222/?ts=')
349
+ expect(result[0].native.title).to.equal('This is a great headline')
350
+ expect(result[0].native.body).to.equal('Native body value')
351
+ expect(result[0].native.image.url).to.equal('https://localhost:8080/yl-logo100x100.jpg')
352
+ expect(result[0].native.image.width).to.equal(100)
353
+ expect(result[0].native.image.height).to.equal(100)
354
+ expect(result[0].native.clickUrl).to.equal('https://www.yieldlab.de')
355
+ expect(result[0].native.impressionTrackers.length).to.equal(3)
356
+ })
357
+
358
+ it('should add adUrl and default native assets when type is Native', function () {
359
+ const NATIVE_RESPONSE_2 = Object.assign({}, NATIVE_RESPONSE, {
360
+ 'native': {
361
+ 'link': {
362
+ 'url': 'https://www.yieldlab.de'
363
+ },
364
+ 'assets': [],
365
+ 'imptrackers': []
366
+ }
367
+ })
368
+ const result = spec.interpretResponse({body: [NATIVE_RESPONSE_2]}, {validBidRequests: [NATIVE_REQUEST], queryParams: REQPARAMS})
369
+
370
+ expect(result[0].requestId).to.equal('2d925f27f5079f')
371
+ expect(result[0].cpm).to.equal(0.01)
372
+ expect(result[0].mediaType).to.equal('native')
373
+ expect(result[0].adUrl).to.include('https://ad.yieldlab.net/d/1111/2222/?ts=')
374
+ expect(result[0].native.title).to.equal('')
375
+ expect(result[0].native.body).to.equal('')
376
+ expect(result[0].native.image.url).to.equal('')
377
+ expect(result[0].native.image.width).to.equal(0)
378
+ expect(result[0].native.image.height).to.equal(0)
379
+ })
380
+
300
381
  it('should append gdpr parameters to vastUrl', function () {
301
382
  const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST], queryParams: REQPARAMS_GDPR})
302
383
 
@@ -0,0 +1,89 @@
1
+ import { expect } from 'chai';
2
+ import {
3
+ init,
4
+ MODULE_NAME,
5
+ validateConfig
6
+ } from 'modules/yieldmoSyntheticInventoryModule';
7
+
8
+ const mockedYmConfig = {
9
+ placementId: '123456',
10
+ adUnitPath: '/6355419/ad_unit_name_used_in_gam'
11
+ };
12
+
13
+ const setGoogletag = () => {
14
+ window.googletag = {
15
+ cmd: [],
16
+ defineSlot: sinon.stub(),
17
+ addService: sinon.stub(),
18
+ pubads: sinon.stub(),
19
+ setTargeting: sinon.stub(),
20
+ enableServices: sinon.stub(),
21
+ display: sinon.stub(),
22
+ };
23
+ window.googletag.defineSlot.returns(window.googletag);
24
+ window.googletag.addService.returns(window.googletag);
25
+ window.googletag.pubads.returns({getSlots: sinon.stub()});
26
+ return window.googletag;
27
+ }
28
+
29
+ describe('Yieldmo Synthetic Inventory Module', function() {
30
+ let config = Object.assign({}, mockedYmConfig);
31
+ let googletagBkp;
32
+
33
+ beforeEach(function () {
34
+ googletagBkp = window.googletag;
35
+ delete window.googletag;
36
+ });
37
+
38
+ afterEach(function () {
39
+ window.googletag = googletagBkp;
40
+ });
41
+
42
+ it('should be enabled with valid required params', function() {
43
+ expect(function () {
44
+ init(mockedYmConfig);
45
+ }).not.to.throw()
46
+ });
47
+
48
+ it('should throw an error if placementId is missed', function() {
49
+ const {placementId, ...config} = mockedYmConfig;
50
+
51
+ expect(function () {
52
+ validateConfig(config);
53
+ }).throw(`${MODULE_NAME}: placementId required`)
54
+ });
55
+
56
+ it('should throw an error if adUnitPath is missed', function() {
57
+ const {adUnitPath, ...config} = mockedYmConfig;
58
+
59
+ expect(function () {
60
+ validateConfig(config);
61
+ }).throw(`${MODULE_NAME}: adUnitPath required`)
62
+ });
63
+
64
+ it('should add correct googletag.cmd', function() {
65
+ const containerName = 'ym_sim_container_' + mockedYmConfig.placementId;
66
+ const gtag = setGoogletag();
67
+
68
+ init(mockedYmConfig);
69
+
70
+ expect(gtag.cmd.length).to.equal(1);
71
+
72
+ gtag.cmd[0]();
73
+
74
+ expect(gtag.addService.getCall(0)).to.not.be.null;
75
+ expect(gtag.setTargeting.getCall(0)).to.not.be.null;
76
+ expect(gtag.setTargeting.getCall(0).args[0]).to.exist.and.to.equal('ym_sim_p_id');
77
+ expect(gtag.setTargeting.getCall(0).args[1]).to.exist.and.to.equal(mockedYmConfig.placementId);
78
+ expect(gtag.defineSlot.getCall(0)).to.not.be.null;
79
+ expect(gtag.enableServices.getCall(0)).to.not.be.null;
80
+ expect(gtag.display.getCall(0)).to.not.be.null;
81
+ expect(gtag.display.getCall(0).args[0]).to.exist.and.to.equal(containerName);
82
+ expect(gtag.pubads.getCall(0)).to.not.be.null;
83
+
84
+ const gamContainerEl = window.document.getElementById(containerName);
85
+ expect(gamContainerEl).to.not.be.null;
86
+
87
+ gamContainerEl.parentNode.removeChild(gamContainerEl);
88
+ });
89
+ });
@@ -162,7 +162,7 @@ describe('adapterManager tests', function () {
162
162
  'bidderCode': 'appnexus',
163
163
  'auctionId': '1863e370099523',
164
164
  'bidderRequestId': '2946b569352ef2',
165
- 'tid': '34566b569352ef2',
165
+ 'uniquePbsTid': '34566b569352ef2',
166
166
  'bids': [
167
167
  {
168
168
  'bidder': 'appnexus',
@@ -436,6 +436,38 @@ describe('adapterManager tests', function () {
436
436
  });
437
437
  }); // end onBidViewable
438
438
 
439
+ describe('onBidderError', function () {
440
+ const bidder = 'appnexus';
441
+ const appnexusSpec = { onBidderError: sinon.stub() };
442
+ const appnexusAdapter = {
443
+ bidder,
444
+ getSpec: function() { return appnexusSpec; },
445
+ }
446
+ before(function () {
447
+ config.setConfig({s2sConfig: { enabled: false }});
448
+ });
449
+
450
+ beforeEach(function () {
451
+ adapterManager.bidderRegistry[bidder] = appnexusAdapter;
452
+ });
453
+
454
+ afterEach(function () {
455
+ delete adapterManager.bidderRegistry[bidder];
456
+ });
457
+
458
+ it('should call spec\'s onBidderError callback when callBidderError is called', function () {
459
+ const bidRequests = getBidRequests();
460
+ const bidderRequest = find(bidRequests, bidRequest => bidRequest.bidderCode === bidder);
461
+ const xhrErrorMock = {
462
+ status: 500,
463
+ statusText: 'Internal Server Error'
464
+ };
465
+ adapterManager.callBidderError(bidder, xhrErrorMock, bidderRequest);
466
+ sinon.assert.calledOnce(appnexusSpec.onBidderError);
467
+ sinon.assert.calledWithExactly(appnexusSpec.onBidderError, { error: xhrErrorMock, bidderRequest });
468
+ });
469
+ }); // end onBidderError
470
+
439
471
  describe('S2S tests', function () {
440
472
  beforeEach(function () {
441
473
  config.setConfig({s2sConfig: CONFIG});
@@ -447,7 +479,7 @@ describe('adapterManager tests', function () {
447
479
  'bidderCode': 'appnexus',
448
480
  'auctionId': '1863e370099523',
449
481
  'bidderRequestId': '2946b569352ef2',
450
- 'tid': '34566b569352ef2',
482
+ 'uniquePbsTid': '34566b569352ef2',
451
483
  'timeout': 1000,
452
484
  'src': 's2s',
453
485
  'adUnitsS2SCopy': [
@@ -676,7 +708,7 @@ describe('adapterManager tests', function () {
676
708
  'bidderCode': 'appnexus',
677
709
  'auctionId': '1863e370099523',
678
710
  'bidderRequestId': '2946b569352ef2',
679
- 'tid': '34566b569352ef2',
711
+ 'uniquePbsTid': '34566b569352ef2',
680
712
  'timeout': 1000,
681
713
  'src': 's2s',
682
714
  'adUnitsS2SCopy': [
@@ -812,7 +844,7 @@ describe('adapterManager tests', function () {
812
844
  'bidderCode': 'pubmatic',
813
845
  'auctionId': '1863e370099523',
814
846
  'bidderRequestId': '2946b569352ef2',
815
- 'tid': '2342342342lfi23',
847
+ 'uniquePbsTid': '2342342342lfi23',
816
848
  'timeout': 1000,
817
849
  'src': 's2s',
818
850
  'adUnitsS2SCopy': [
@@ -1009,6 +1041,21 @@ describe('adapterManager tests', function () {
1009
1041
  sinon.assert.calledTwice(prebidServerAdapterMock.callBids);
1010
1042
  });
1011
1043
 
1044
+ it('should have one tid for ALL s2s bidRequests', function () {
1045
+ let adUnits = utils.deepClone(getAdUnits()).map(adUnit => {
1046
+ adUnit.bids = adUnit.bids.filter(bid => includes(['appnexus', 'pubmatic'], bid.bidder));
1047
+ return adUnit;
1048
+ })
1049
+ let bidRequests = adapterManager.makeBidRequests(adUnits, 1111, 2222, 1000);
1050
+ adapterManager.callBids(adUnits, bidRequests, () => {}, () => {});
1051
+ sinon.assert.calledTwice(prebidServerAdapterMock.callBids);
1052
+ const firstBid = prebidServerAdapterMock.callBids.firstCall.args[0];
1053
+ const secondBid = prebidServerAdapterMock.callBids.secondCall.args[0];
1054
+
1055
+ // TIDS should be the same
1056
+ expect(firstBid.tid).to.equal(secondBid.tid);
1057
+ });
1058
+
1012
1059
  it('should fire for simultaneous s2s and client requests', function () {
1013
1060
  adapterManager.bidderRegistry['adequant'] = adequantAdapterMock;
1014
1061
  let adUnits = utils.deepClone(getAdUnits()).map(adUnit => {
@@ -1665,14 +1712,17 @@ describe('adapterManager tests', function () {
1665
1712
  });
1666
1713
 
1667
1714
  describe('sizeMapping', function () {
1715
+ let sandbox;
1668
1716
  beforeEach(function () {
1717
+ sandbox = sinon.sandbox.create();
1669
1718
  allS2SBidders.length = 0;
1670
1719
  clientTestAdapters.length = 0;
1671
- sinon.stub(window, 'matchMedia').callsFake(() => ({matches: true}));
1720
+ // always have matchMedia return true for us
1721
+ sandbox.stub(utils.getWindowTop(), 'matchMedia').callsFake(() => ({matches: true}));
1672
1722
  });
1673
1723
 
1674
1724
  afterEach(function () {
1675
- matchMedia.restore();
1725
+ sandbox.restore();
1676
1726
  config.resetConfig();
1677
1727
  setSizeConfig([]);
1678
1728
  });
@@ -552,17 +552,27 @@ describe('bidders created by newBidder', function () {
552
552
 
553
553
  describe('when the ajax call fails', function () {
554
554
  let ajaxStub;
555
+ let callBidderErrorStub;
556
+ let eventEmitterStub;
557
+ let xhrErrorMock = {
558
+ status: 500,
559
+ statusText: 'Internal Server Error'
560
+ };
555
561
 
556
562
  beforeEach(function () {
557
563
  ajaxStub = sinon.stub(ajax, 'ajax').callsFake(function(url, callbacks) {
558
- callbacks.error('ajax call failed.');
564
+ callbacks.error('ajax call failed.', xhrErrorMock);
559
565
  });
566
+ callBidderErrorStub = sinon.stub(adapterManager, 'callBidderError');
567
+ eventEmitterStub = sinon.stub(events, 'emit');
560
568
  addBidResponseStub.reset();
561
569
  doneStub.reset();
562
570
  });
563
571
 
564
572
  afterEach(function () {
565
573
  ajaxStub.restore();
574
+ callBidderErrorStub.restore();
575
+ eventEmitterStub.restore();
566
576
  });
567
577
 
568
578
  it('should not spec.interpretResponse()', function () {
@@ -580,6 +590,14 @@ describe('bidders created by newBidder', function () {
580
590
 
581
591
  expect(spec.interpretResponse.called).to.equal(false);
582
592
  expect(doneStub.calledOnce).to.equal(true);
593
+ expect(callBidderErrorStub.calledOnce).to.equal(true);
594
+ expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE);
595
+ expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock);
596
+ expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST);
597
+ sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, {
598
+ error: xhrErrorMock,
599
+ bidderRequest: MOCK_BIDS_REQUEST
600
+ });
583
601
  });
584
602
 
585
603
  it('should not add bids for each adunit code into the auction', function () {
@@ -598,6 +616,14 @@ describe('bidders created by newBidder', function () {
598
616
 
599
617
  expect(addBidResponseStub.callCount).to.equal(0);
600
618
  expect(doneStub.calledOnce).to.equal(true);
619
+ expect(callBidderErrorStub.calledOnce).to.equal(true);
620
+ expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE);
621
+ expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock);
622
+ expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST);
623
+ sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, {
624
+ error: xhrErrorMock,
625
+ bidderRequest: MOCK_BIDS_REQUEST
626
+ });
601
627
  });
602
628
 
603
629
  it('should call spec.getUserSyncs() with no responses', function () {
@@ -616,6 +642,40 @@ describe('bidders created by newBidder', function () {
616
642
  expect(spec.getUserSyncs.calledOnce).to.equal(true);
617
643
  expect(spec.getUserSyncs.firstCall.args[1]).to.deep.equal([]);
618
644
  expect(doneStub.calledOnce).to.equal(true);
645
+ expect(callBidderErrorStub.calledOnce).to.equal(true);
646
+ expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE);
647
+ expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock);
648
+ expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST);
649
+ sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, {
650
+ error: xhrErrorMock,
651
+ bidderRequest: MOCK_BIDS_REQUEST
652
+ });
653
+ });
654
+
655
+ it('should call spec.getUserSyncs() with no responses', function () {
656
+ const bidder = newBidder(spec);
657
+
658
+ spec.isBidRequestValid.returns(true);
659
+ spec.buildRequests.returns({
660
+ method: 'POST',
661
+ url: 'test.url.com',
662
+ data: {}
663
+ });
664
+ spec.getUserSyncs.returns([]);
665
+
666
+ bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
667
+
668
+ expect(spec.getUserSyncs.calledOnce).to.equal(true);
669
+ expect(spec.getUserSyncs.firstCall.args[1]).to.deep.equal([]);
670
+ expect(doneStub.calledOnce).to.equal(true);
671
+ expect(callBidderErrorStub.calledOnce).to.equal(true);
672
+ expect(callBidderErrorStub.firstCall.args[0]).to.equal(CODE);
673
+ expect(callBidderErrorStub.firstCall.args[1]).to.equal(xhrErrorMock);
674
+ expect(callBidderErrorStub.firstCall.args[2]).to.equal(MOCK_BIDS_REQUEST);
675
+ sinon.assert.calledWith(eventEmitterStub, CONSTANTS.EVENTS.BIDDER_ERROR, {
676
+ error: xhrErrorMock,
677
+ bidderRequest: MOCK_BIDS_REQUEST
678
+ });
619
679
  });
620
680
  });
621
681
  });
@@ -98,7 +98,6 @@ var createSlotArrayScenario2 = function createSlotArrayScenario2() {
98
98
  var slot1 = new Slot(config.adUnitElementIDs[0], config.adUnitCodes[0]);
99
99
  slot1.setTargeting('pos1', '750x350');
100
100
  var slot2 = new Slot(config.adUnitElementIDs[1], config.adUnitCodes[0]);
101
- slot2.setTargeting('gender', ['male', 'female']);
102
101
  return [
103
102
  slot1,
104
103
  slot2
@@ -862,6 +861,9 @@ describe('Unit: Prebid Module', function () {
862
861
 
863
862
  it('should set googletag targeting keys after calling setTargetingForGPTAsync function', function () {
864
863
  var slots = createSlotArrayScenario2();
864
+
865
+ // explicitly setting some PBJS key value pairs to verify whether these are removed befor new keys are set
866
+
865
867
  window.googletag.pubads().setSlots(slots);
866
868
  $$PREBID_GLOBAL$$.setTargetingForGPTAsync([config.adUnitCodes[0]]);
867
869
 
@@ -869,7 +871,7 @@ describe('Unit: Prebid Module', function () {
869
871
  // googletag's targeting structure
870
872
  // googletag setTargeting will override old value if invoked with same key
871
873
 
872
- const targeting = [];
874
+ let targeting = [];
873
875
  slots[1].getTargetingKeys().map(function (key) {
874
876
  const value = slots[1].getTargeting(key);
875
877
  targeting.push([key, value]);
@@ -887,6 +889,39 @@ describe('Unit: Prebid Module', function () {
887
889
  invokedTargeting.push([key, value]);
888
890
  });
889
891
  assert.deepEqual(targeting, invokedTargeting, 'google tag targeting options not matching');
892
+
893
+ // resetPresetTargeting: initiate a new auction with no winning bids, now old targeting should be removed
894
+
895
+ resetAuction();
896
+ auction.getBidsReceived = function() { return [] };
897
+
898
+ var slots = createSlotArrayScenario2();
899
+ window.googletag.pubads().setSlots(slots);
900
+
901
+ $$PREBID_GLOBAL$$.setTargetingForGPTAsync([config.adUnitCodes[0]]);
902
+
903
+ targeting = [];
904
+ slots[1].getTargetingKeys().map(function (key) {
905
+ const value = slots[1].getTargeting(key);
906
+ targeting.push([key, value]);
907
+ });
908
+
909
+ invokedTargetingMap = {};
910
+ slots[1].spySetTargeting.args.map(function (entry) {
911
+ invokedTargetingMap[entry[0]] = entry[1];
912
+ });
913
+
914
+ var invokedTargeting = [];
915
+
916
+ Object.getOwnPropertyNames(invokedTargetingMap).map(function (key) {
917
+ const value = Array.isArray(invokedTargetingMap[key]) ? invokedTargetingMap[key] : [invokedTargetingMap[key]]; // values are always returned as array in googletag
918
+ invokedTargeting.push([key, value]);
919
+ });
920
+ assert.deepEqual(targeting, invokedTargeting, 'google tag targeting options not matching');
921
+ targeting.forEach(function(e) {
922
+ // here e[0] is key and e[1] is value in array that should be [null] as we are un-setting prebid keys in resetPresetTargeting
923
+ assert.deepEqual(e[1], [null], 'resetPresetTargeting: the value of the key ' + e[0] + ' should be [null]');
924
+ });
890
925
  });
891
926
 
892
927
  it('should set googletag targeting keys to specific slot with customSlotMatching', function () {