prebid.js 8.2.0 → 8.3.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 (157) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/adqueryBidAdapter.js +1 -1
  7. package/dist/adrelevantisBidAdapter.js +1 -1
  8. package/dist/adtelligentBidAdapter.js +1 -1
  9. package/dist/adtrgtmeBidAdapter.js +1 -1
  10. package/dist/adxcgBidAdapter.js +1 -1
  11. package/dist/adyoulikeBidAdapter.js +1 -1
  12. package/dist/ajaBidAdapter.js +1 -1
  13. package/dist/amxBidAdapter.js +1 -1
  14. package/dist/amxIdSystem.js +1 -1
  15. package/dist/appierAnalyticsAdapter.js +1 -1
  16. package/dist/appnexusBidAdapter.js +1 -1
  17. package/dist/asoBidAdapter.js +1 -1
  18. package/dist/axonixBidAdapter.js +1 -1
  19. package/dist/beopBidAdapter.js +1 -1
  20. package/dist/bidglassBidAdapter.js +1 -1
  21. package/dist/big-richmediaBidAdapter.js +1 -1
  22. package/dist/bridBidAdapter.js +1 -1
  23. package/dist/bridgewellBidAdapter.js +1 -1
  24. package/dist/brightMountainMediaBidAdapter.js +1 -1
  25. package/dist/carodaBidAdapter.js +1 -1
  26. package/dist/chtnwBidAdapter.js +1 -1
  27. package/dist/concertBidAdapter.js +1 -1
  28. package/dist/connectadBidAdapter.js +1 -1
  29. package/dist/consumableBidAdapter.js +1 -1
  30. package/dist/conversantAnalyticsAdapter.js +1 -1
  31. package/dist/conversantBidAdapter.js +1 -1
  32. package/dist/craftBidAdapter.js +1 -1
  33. package/dist/criteoBidAdapter.js +1 -1
  34. package/dist/cwireBidAdapter.js +1 -1
  35. package/dist/dependencies.json +3 -0
  36. package/dist/discoveryBidAdapter.js +1 -1
  37. package/dist/dspxBidAdapter.js +1 -1
  38. package/dist/eplanningBidAdapter.js +1 -1
  39. package/dist/euidIdSystem.js +1 -1
  40. package/dist/feedadBidAdapter.js +1 -1
  41. package/dist/finativeBidAdapter.js +1 -1
  42. package/dist/freewheel-sspBidAdapter.js +1 -1
  43. package/dist/gmosspBidAdapter.js +1 -1
  44. package/dist/goldbachBidAdapter.js +1 -1
  45. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  46. package/dist/greenbidsRtdProvider.js +1 -1
  47. package/dist/gridBidAdapter.js +1 -1
  48. package/dist/gumgumBidAdapter.js +1 -1
  49. package/dist/h12mediaBidAdapter.js +1 -1
  50. package/dist/holidBidAdapter.js +1 -1
  51. package/dist/hypelabBidAdapter.js +1 -1
  52. package/dist/id5IdSystem.js +1 -1
  53. package/dist/imdsBidAdapter.js +1 -1
  54. package/dist/improvedigitalBidAdapter.js +1 -1
  55. package/dist/insticatorBidAdapter.js +1 -1
  56. package/dist/ixBidAdapter.js +1 -1
  57. package/dist/justpremiumBidAdapter.js +1 -1
  58. package/dist/kargoBidAdapter.js +1 -1
  59. package/dist/konduitAnalyticsAdapter.js +1 -1
  60. package/dist/kueezBidAdapter.js +1 -1
  61. package/dist/kueezRtbBidAdapter.js +1 -1
  62. package/dist/kulturemediaBidAdapter.js +1 -1
  63. package/dist/lassoBidAdapter.js +1 -1
  64. package/dist/lifestreetBidAdapter.js +1 -1
  65. package/dist/livewrappedAnalyticsAdapter.js +1 -1
  66. package/dist/logicadBidAdapter.js +1 -1
  67. package/dist/loglyliftBidAdapter.js +1 -1
  68. package/dist/magniteAnalyticsAdapter.js +1 -1
  69. package/dist/malltvAnalyticsAdapter.js +1 -1
  70. package/dist/marsmediaBidAdapter.js +1 -1
  71. package/dist/mediafuseBidAdapter.js +1 -1
  72. package/dist/mediagoBidAdapter.js +1 -1
  73. package/dist/mediasquareBidAdapter.js +1 -1
  74. package/dist/mgidBidAdapter.js +1 -1
  75. package/dist/minutemediaBidAdapter.js +1 -1
  76. package/dist/minutemediaplusBidAdapter.js +1 -1
  77. package/dist/nexx360BidAdapter.js +1 -1
  78. package/dist/not-for-prod/prebid.js +132 -132
  79. package/dist/oguryBidAdapter.js +1 -1
  80. package/dist/onetagBidAdapter.js +1 -1
  81. package/dist/ooloAnalyticsAdapter.js +1 -1
  82. package/dist/optidigitalBidAdapter.js +1 -1
  83. package/dist/outbrainBidAdapter.js +1 -1
  84. package/dist/parrableIdSystem.js +1 -1
  85. package/dist/pixfutureBidAdapter.js +1 -1
  86. package/dist/prebid-core.js +1 -1
  87. package/dist/publinkIdSystem.js +1 -1
  88. package/dist/pubmaticBidAdapter.js +1 -1
  89. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  90. package/dist/pxyzBidAdapter.js +1 -1
  91. package/dist/quantcastBidAdapter.js +1 -1
  92. package/dist/readpeakBidAdapter.js +1 -1
  93. package/dist/relaidoBidAdapter.js +1 -1
  94. package/dist/retailspotBidAdapter.js +1 -1
  95. package/dist/rhythmoneBidAdapter.js +1 -1
  96. package/dist/riseBidAdapter.js +1 -1
  97. package/dist/rubiconBidAdapter.js +1 -1
  98. package/dist/seedingAllianceBidAdapter.js +1 -1
  99. package/dist/seedtagBidAdapter.js +1 -1
  100. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  101. package/dist/sharethroughBidAdapter.js +1 -1
  102. package/dist/shinezBidAdapter.js +1 -1
  103. package/dist/smaatoBidAdapter.js +1 -1
  104. package/dist/smartadserverBidAdapter.js +1 -1
  105. package/dist/smartxBidAdapter.js +1 -1
  106. package/dist/smartyadsBidAdapter.js +1 -1
  107. package/dist/smilewantedBidAdapter.js +1 -1
  108. package/dist/sonobiBidAdapter.js +1 -1
  109. package/dist/sovrnAnalyticsAdapter.js +1 -1
  110. package/dist/sovrnBidAdapter.js +1 -1
  111. package/dist/sspBCBidAdapter.js +1 -1
  112. package/dist/stvBidAdapter.js +1 -1
  113. package/dist/sublimeBidAdapter.js +1 -1
  114. package/dist/targetVideoBidAdapter.js +1 -1
  115. package/dist/teadsBidAdapter.js +1 -1
  116. package/dist/trafficgateBidAdapter.js +1 -1
  117. package/dist/trionBidAdapter.js +1 -1
  118. package/dist/tripleliftBidAdapter.js +1 -1
  119. package/dist/ttdBidAdapter.js +1 -1
  120. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  121. package/dist/uid2IdSystem.js +1 -1
  122. package/dist/underdogmediaBidAdapter.js +1 -1
  123. package/dist/undertoneBidAdapter.js +1 -1
  124. package/dist/vidazooBidAdapter.js +1 -1
  125. package/dist/videobyteBidAdapter.js +1 -1
  126. package/dist/visxBidAdapter.js +1 -1
  127. package/dist/vuukleBidAdapter.js +1 -1
  128. package/dist/widespaceBidAdapter.js +1 -1
  129. package/dist/winrBidAdapter.js +1 -1
  130. package/dist/yahoosspBidAdapter.js +1 -1
  131. package/dist/yieldmoBidAdapter.js +1 -1
  132. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  133. package/modules/adagioBidAdapter.js +2 -1
  134. package/modules/adtelligentBidAdapter.js +8 -0
  135. package/modules/beopBidAdapter.js +6 -6
  136. package/modules/beopBidAdapter.md +35 -1
  137. package/modules/cadentApertureMXBidAdapter.md +2 -2
  138. package/modules/discoveryBidAdapter.js +1 -1
  139. package/modules/holidBidAdapter.js +49 -30
  140. package/modules/ixBidAdapter.js +2 -1
  141. package/modules/livewrappedAnalyticsAdapter.js +33 -33
  142. package/modules/mediagoBidAdapter.js +1 -0
  143. package/modules/smartyadsBidAdapter.js +6 -3
  144. package/modules/sovrnBidAdapter.js +5 -0
  145. package/modules/trafficgateBidAdapter.js +126 -72
  146. package/modules/vidazooBidAdapter.js +68 -16
  147. package/package.json +1 -1
  148. package/test/spec/modules/adagioBidAdapter_spec.js +2 -1
  149. package/test/spec/modules/adtelligentBidAdapter_spec.js +8 -0
  150. package/test/spec/modules/beopBidAdapter_spec.js +18 -2
  151. package/test/spec/modules/cadentApertureMXBidAdapter_spec.js +1 -1
  152. package/test/spec/modules/holidBidAdapter_spec.js +26 -6
  153. package/test/spec/modules/ixBidAdapter_spec.js +12 -6
  154. package/test/spec/modules/smartyadsBidAdapter_spec.js +1 -1
  155. package/test/spec/modules/sovrnBidAdapter_spec.js +34 -0
  156. package/test/spec/modules/trafficgateBidAdapter_spec.js +1349 -199
  157. package/test/spec/modules/vidazooBidAdapter_spec.js +131 -0
@@ -1,223 +1,1373 @@
1
- import { expect } from 'chai'
2
- import { spec } from '../../../modules/trafficgateBidAdapter'
3
- import { deepStrictEqual, notStrictEqual, ok, strictEqual } from 'assert'
4
-
5
- describe('TrafficGateAdapter', () => {
6
- const bid = {
7
- bidId: '9ec5b177515ee2e5',
8
- bidder: 'trafficgate',
1
+ import {expect} from 'chai';
2
+ import {spec} from 'modules/trafficgateBidAdapter';
3
+ import {newBidder} from 'src/adapters/bidderFactory.js';
4
+ import {BANNER, VIDEO} from 'src/mediaTypes.js';
5
+ import {config} from 'src/config.js';
6
+ import * as utils from 'src/utils.js';
7
+ import 'src/prebid.js'
8
+ import 'modules/currency.js';
9
+ import 'modules/userId/index.js';
10
+ import 'modules/multibid/index.js';
11
+ import 'modules/priceFloors.js';
12
+ import 'modules/consentManagement.js';
13
+ import 'modules/consentManagementUsp.js';
14
+ import 'modules/schain.js';
15
+ import {deepClone} from 'src/utils.js';
16
+ import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
17
+ import {hook} from '../../../src/hook.js';
18
+
19
+ const BidRequestBuilder = function BidRequestBuilder(options) {
20
+ const defaults = {
21
+ request: {
22
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
23
+ adUnitCode: 'adunit-code',
24
+ bidder: 'trafficgate'
25
+ },
9
26
  params: {
10
- placementId: 1,
27
+ placementId: '98765',
11
28
  host: 'example'
12
29
  },
13
- mediaTypes: {
14
- banner: {
15
- sizes: [[300, 250]]
16
- }
30
+ sizes: [[300, 250], [300, 600]],
31
+ };
32
+
33
+ const request = {
34
+ ...defaults.request,
35
+ ...options
36
+ };
37
+
38
+ this.withParams = (options) => {
39
+ request.params = {
40
+ ...defaults.params,
41
+ ...options
42
+ };
43
+ return this;
44
+ };
45
+
46
+ this.build = () => request;
47
+ };
48
+
49
+ const BidderRequestBuilder = function BidderRequestBuilder(options) {
50
+ const defaults = {
51
+ bidderCode: 'trafficgate',
52
+ auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9',
53
+ bidderRequestId: '7g36s867Tr4xF90X',
54
+ timeout: 3000,
55
+ refererInfo: {
56
+ numIframes: 0,
57
+ reachedTop: true,
58
+ referer: 'http://test.io/index.html?pbjs_debug=true'
17
59
  }
18
- }
19
-
20
- describe('isBidRequestValid', () => {
21
- it('Should return true if there are bidId, params and placementId parameters present', () => {
22
- strictEqual(true, spec.isBidRequestValid(bid))
23
- })
24
-
25
- it('Should return false if at least one of parameters is not present', () => {
26
- const b = { ...bid }
27
- delete b.params.placementId
28
- strictEqual(false, spec.isBidRequestValid(b))
29
- })
30
-
31
- it('Should return false if at least one of parameters is not present', () => {
32
- const b = { ...bid }
33
- delete b.params.host
34
- strictEqual(false, spec.isBidRequestValid(b))
35
- })
36
- })
37
-
38
- describe('buildRequests', () => {
39
- const serverRequest = spec.buildRequests([bid])
40
-
41
- it('Creates a ServerRequest object with method, URL and data', () => {
42
- ok(serverRequest)
43
- ok(serverRequest.method)
44
- ok(serverRequest.url)
45
- ok(serverRequest.data)
46
- })
47
-
48
- it('Returns POST method', () => {
49
- strictEqual('POST', serverRequest.method)
50
- })
51
-
52
- it('Returns valid URL', () => {
53
- strictEqual('https://example.bc-plugin.com/?c=o&m=multi', serverRequest.url)
54
- })
55
-
56
- it('Returns valid data if array of bids is valid', () => {
57
- const { data } = serverRequest
58
- strictEqual('object', typeof data)
59
- deepStrictEqual(['language', 'secure', 'host', 'page', 'placements'], Object.keys(data))
60
- strictEqual('string', typeof data.language)
61
- strictEqual('string', typeof data.host)
62
- strictEqual('string', typeof data.page)
63
- notStrictEqual(-1, [0, 1].indexOf(data.secure))
64
-
65
- const placement = data.placements[0]
66
- deepStrictEqual(['placementId', 'bidId', 'traffic'], Object.keys(placement))
67
- strictEqual(1, placement.placementId)
68
- strictEqual('9ec5b177515ee2e5', placement.bidId)
69
- strictEqual('banner', placement.traffic)
70
- })
71
-
72
- it('Returns empty data if no valid requests are passed', () => {
73
- deepStrictEqual([], spec.buildRequests([]))
74
- })
75
- })
76
-
77
- describe('interpretResponse', () => {
78
- const validData = [
79
- {
80
- body: [{
81
- mediaType: 'banner',
82
- width: 300,
83
- height: 250,
84
- cpm: 0.4,
85
- ad: 'Test',
86
- requestId: '9ec5b177515ee2e5',
87
- ttl: 120,
88
- creativeId: '2',
89
- netRevenue: true,
90
- currency: 'USD',
91
- dealId: '1',
92
- meta: {
93
- advertiserDomains: ['test.com']
60
+ };
61
+
62
+ const request = {
63
+ ...defaults,
64
+ ...options
65
+ };
66
+
67
+ this.build = () => request;
68
+ };
69
+
70
+ describe('TrafficgateOpenxRtbAdapter', function () {
71
+ before(() => {
72
+ hook.ready();
73
+ });
74
+
75
+ const adapter = newBidder(spec);
76
+
77
+ describe('inherited functions', function () {
78
+ it('exists and is a function', function () {
79
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
80
+ });
81
+ });
82
+
83
+ describe('isBidRequestValid()', function () {
84
+ describe('when request is for a banner ad', function () {
85
+ let bannerBid;
86
+ beforeEach(function () {
87
+ bannerBid = {
88
+ bidder: 'trafficgate',
89
+ params: {},
90
+ adUnitCode: 'adunit-code',
91
+ mediaTypes: {banner: {}},
92
+ sizes: [[300, 250], [300, 600]],
93
+ bidId: '30b31c1838de1e',
94
+ bidderRequestId: '22edbae2733bf6',
95
+ auctionId: '1d1a030790a475'
96
+ };
97
+ });
98
+
99
+ it('should return false when there is placementId only', function () {
100
+ bannerBid.params = {'placementId': '98765'};
101
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
102
+ });
103
+
104
+ describe('should return false when there is a host only', function () {
105
+ beforeEach(function () {
106
+ bannerBid.params = {host: 'test-delivery-domain'}
107
+ });
108
+
109
+ it('should return false when there is no placementId and size', function () {
110
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
111
+ });
112
+
113
+ it('should return false if there is an placementId without sizes', function () {
114
+ bannerBid.params.placementId = '98765';
115
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
116
+ });
117
+
118
+ it('should return false if there is no placementId and sizes are defined', function () {
119
+ bannerBid.mediaTypes.banner.sizes = [720, 90];
120
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
121
+ });
122
+
123
+ it('should return false if no sizes are defined ', function () {
124
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
125
+ });
126
+
127
+ it('should return false if sizes empty ', function () {
128
+ bannerBid.mediaTypes.banner.sizes = [];
129
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(false);
130
+ });
131
+
132
+ it('should return true if there is placementId and sizes are defined', function () {
133
+ bannerBid.params.placementId = '98765';
134
+ bannerBid.mediaTypes.banner.sizes = [720, 90];
135
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
136
+ });
137
+ });
138
+ });
139
+
140
+ describe('when request is for a multiformat ad', function () {
141
+ describe('and request config uses mediaTypes video and banner', () => {
142
+ const multiformatBid = {
143
+ bidder: 'trafficgate',
144
+ params: {
145
+ placementId: '98765',
146
+ host: 'example'
147
+ },
148
+ adUnitCode: 'adunit-code',
149
+ mediaTypes: {
150
+ banner: {
151
+ sizes: [[300, 250]]
152
+ },
153
+ video: {
154
+ playerSize: [300, 250]
155
+ }
156
+ },
157
+ bidId: '30b31c1838de1e',
158
+ bidderRequestId: '22edbae2733bf6',
159
+ auctionId: '1d1a030790a475',
160
+ transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
161
+ };
162
+ it('should return true multisize when required params found', function () {
163
+ expect(spec.isBidRequestValid(multiformatBid)).to.equal(true);
164
+ });
165
+ });
166
+ });
167
+
168
+ describe('when request is for a video ad', function () {
169
+ describe('and request config uses mediaTypes', () => {
170
+ const videoBidWithMediaTypes = {
171
+ bidder: 'trafficgate',
172
+ params: {
173
+ placementId: '98765',
174
+ host: 'example'
175
+ },
176
+ adUnitCode: 'adunit-code',
177
+ mediaTypes: {
178
+ video: {
179
+ playerSize: [640, 480]
180
+ }
181
+ },
182
+ bidId: '30b31c1838de1e',
183
+ bidderRequestId: '22edbae2733bf6',
184
+ auctionId: '1d1a030790a475',
185
+ transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
186
+ };
187
+ it('should return false when isBannerBid', function () {
188
+ expect(spec.isBannerBid(videoBidWithMediaTypes)).to.equal(false);
189
+ });
190
+
191
+ it('should return true when required params found', function () {
192
+ expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(true);
193
+ });
194
+
195
+ it('should return false when required params are not passed', function () {
196
+ let videoBidWithMediaTypes = Object.assign({}, videoBidWithMediaTypes);
197
+ videoBidWithMediaTypes.params = {};
198
+ expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(false);
199
+ });
200
+ });
201
+ describe('and request config uses both host and platform', () => {
202
+ const videoBidWithHostAndPlacement = {
203
+ bidder: 'trafficgate',
204
+ params: {
205
+ placementId: '98765',
206
+ host: 'example'
207
+ },
208
+ adUnitCode: 'adunit-code',
209
+ mediaTypes: {
210
+ video: {
211
+ playerSize: [640, 480]
212
+ }
213
+ },
214
+ bidId: '30b31c1838de1e',
215
+ bidderRequestId: '22edbae2733bf6',
216
+ auctionId: '1d1a030790a475',
217
+ transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e'
218
+ };
219
+ it('should return false when isBannerBid', function () {
220
+ expect(spec.isBannerBid(videoBidWithHostAndPlacement)).to.equal(false);
221
+ });
222
+
223
+ it('should return true when required params found', function () {
224
+ expect(spec.isBidRequestValid(videoBidWithHostAndPlacement)).to.equal(true);
225
+ });
226
+
227
+ it('should return false when required params are not passed', function () {
228
+ let videoBidWithMediaTypes = Object.assign({}, videoBidWithHostAndPlacement);
229
+ videoBidWithMediaTypes.params = {};
230
+ expect(spec.isBidRequestValid(videoBidWithMediaTypes)).to.equal(false);
231
+ });
232
+ });
233
+ describe('and request config uses mediaType', () => {
234
+ const videoBidWithMediaType = {
235
+ 'bidder': 'trafficgate',
236
+ 'params': {
237
+ 'placementId': '98765',
238
+ 'host': 'example'
239
+ },
240
+ 'adUnitCode': 'adunit-code',
241
+ 'mediaType': 'video',
242
+ 'sizes': [640, 480],
243
+ 'bidId': '30b31c1838de1e',
244
+ 'bidderRequestId': '22edbae2733bf6',
245
+ 'auctionId': '1d1a030790a475',
246
+ 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
247
+ };
248
+ it('should return true when required params found', function () {
249
+ expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(true);
250
+ });
251
+
252
+ it('should return false when required params are not passed', function () {
253
+ let videoBidWithMediaType = Object.assign({}, videoBidWithMediaType);
254
+ delete videoBidWithMediaType.params;
255
+ videoBidWithMediaType.params = {};
256
+ expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(false);
257
+ });
258
+ });
259
+ });
260
+ });
261
+
262
+ describe('buildRequests()', function () {
263
+ let bidRequestsWithMediaTypes;
264
+ let bidRequestsWithPlatform;
265
+ let mockBidderRequest;
266
+
267
+ beforeEach(function () {
268
+ mockBidderRequest = {refererInfo: {}};
269
+
270
+ bidRequestsWithMediaTypes = [{
271
+ bidder: 'trafficgate',
272
+ params: {
273
+ placementId: '11',
274
+ host: 'example',
275
+ },
276
+ adUnitCode: '/adunit-code/test-path',
277
+ mediaTypes: {
278
+ banner: {
279
+ sizes: [[300, 250], [300, 600]]
94
280
  }
95
- }]
96
- },
97
- {
98
- body: [{
99
- vastUrl: 'example.com',
100
- mediaType: 'video',
101
- cpm: 0.5,
102
- requestId: '9ec5b177515ee2e5',
103
- ttl: 120,
104
- creativeId: '2',
105
- netRevenue: true,
106
- currency: 'USD',
107
- dealId: '1',
108
- meta: {
109
- advertiserDomains: ['test.com']
281
+ },
282
+ bidId: 'test-bid-id-1',
283
+ bidderRequestId: 'test-bid-request-1',
284
+ auctionId: 'test-auction-1',
285
+ transactionId: 'test-transactionId-1',
286
+ ortb2Imp: {
287
+ ext: {
288
+ ae: 2
110
289
  }
111
- }]
112
- },
113
- {
114
- body: [{
115
- mediaType: 'native',
116
- clickUrl: 'example.com',
117
- title: 'Test',
118
- image: 'example.com',
119
- creativeId: '2',
120
- impressionTrackers: ['example.com'],
121
- ttl: 120,
122
- cpm: 0.4,
123
- requestId: '9ec5b177515ee2e5',
124
- netRevenue: true,
125
- currency: 'USD',
126
- meta: {
127
- advertiserDomains: ['test.com']
290
+ }
291
+ }, {
292
+ bidder: 'trafficgate',
293
+ params: {
294
+ placementId: '22',
295
+ host: 'example',
296
+ },
297
+ adUnitCode: 'adunit-code',
298
+ mediaTypes: {
299
+ video: {
300
+ playerSize: [640, 480]
128
301
  }
129
- }]
130
- }
131
- ]
302
+ },
303
+ bidId: 'test-bid-id-2',
304
+ bidderRequestId: 'test-bid-request-2',
305
+ auctionId: 'test-auction-2',
306
+ transactionId: 'test-transactionId-2'
307
+ }];
308
+ });
132
309
 
133
- for (const obj of validData) {
134
- const { mediaType } = obj.body[0]
310
+ context('common requests checks', function() {
311
+ it('should be able to handle multiformat requests', () => {
312
+ const multiformat = utils.deepClone(bidRequestsWithMediaTypes[0]);
313
+ multiformat.mediaTypes.video = {
314
+ context: 'outstream',
315
+ playerSize: [640, 480]
316
+ }
317
+ const requests = spec.buildRequests([multiformat], mockBidderRequest);
318
+ const outgoingFormats = requests.flatMap(rq => rq.data.imp.flatMap(imp => ['banner', 'video'].filter(k => imp[k] != null)));
319
+ const expected = FEATURES.VIDEO ? ['banner', 'video'] : ['banner']
320
+ expect(outgoingFormats).to.have.members(expected);
321
+ })
135
322
 
136
- it(`Should interpret ${mediaType} response`, () => {
137
- const response = spec.interpretResponse(obj)
323
+ it('should send bid request to trafficgate url via POST', function () {
324
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
325
+ expect(request[0].url).to.equal('https://example.bc-plugin.com/prebidjs');
326
+ expect(request[0].method).to.equal('POST');
327
+ });
138
328
 
139
- expect(response).to.be.an('array')
140
- strictEqual(1, response.length)
329
+ it('should send delivery domain, if available', function () {
330
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
331
+ expect(request[0].data.imp[0].ext.bidder.host).to.equal(bidRequestsWithMediaTypes[0].params.host);
332
+ expect(request[1].data.imp[0].ext.bidder.host).to.equal(bidRequestsWithMediaTypes[1].params.host);
333
+ });
141
334
 
142
- const copy = { ...obj.body[0] }
143
- deepStrictEqual(copy, response[0])
144
- })
145
- }
335
+ it('should send placementId', function () {
336
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
337
+ expect(request[0].data.imp[0].ext.bidder.placementId).to.equal(bidRequestsWithMediaTypes[0].params.placementId);
338
+ expect(request[1].data.imp[0].ext.bidder.placementId).to.equal(bidRequestsWithMediaTypes[1].params.placementId);
339
+ });
340
+
341
+ describe('floors', function () {
342
+ it('should send out custom floors on bids that have customFloors, no currency as account currency is used', function () {
343
+ const bidRequest = Object.assign({},
344
+ bidRequestsWithMediaTypes[0],
345
+ {
346
+ params: {
347
+ placementId: '98765',
348
+ host: 'example',
349
+ customFloor: 1.500
350
+ }
351
+ }
352
+ );
146
353
 
147
- for (const obj of validData) {
148
- it(`Should interpret response has meta.advertiserDomains`, () => {
149
- const response = spec.interpretResponse(obj)
354
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
355
+ expect(request[0].data.imp[0].bidfloor).to.equal(bidRequest.params.customFloor);
356
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined);
357
+ });
150
358
 
151
- expect(response[0]['meta']['advertiserDomains']).to.be.an('array')
152
- expect(response[0]['meta']['advertiserDomains'][0]).to.be.an('string')
359
+ context('with floors module', function () {
360
+ let adServerCurrencyStub;
361
+
362
+ beforeEach(function () {
363
+ adServerCurrencyStub = sinon
364
+ .stub(config, 'getConfig')
365
+ .withArgs('currency.adServerCurrency')
366
+ });
367
+
368
+ afterEach(function () {
369
+ config.getConfig.restore();
370
+ });
371
+
372
+ it('should send out floors on bids in USD', function () {
373
+ const bidRequest = Object.assign({},
374
+ bidRequestsWithMediaTypes[0],
375
+ {
376
+ getFloor: () => {
377
+ return {
378
+ currency: 'USD',
379
+ floor: 9.99
380
+ }
381
+ }
382
+ }
383
+ );
384
+
385
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
386
+ expect(request[0].data.imp[0].bidfloor).to.equal(9.99);
387
+ expect(request[0].data.imp[0].bidfloorcur).to.equal('USD');
388
+ });
389
+
390
+ it('should send not send floors', function () {
391
+ adServerCurrencyStub.returns('EUR');
392
+ const bidRequest = Object.assign({},
393
+ bidRequestsWithMediaTypes[0],
394
+ {
395
+ getFloor: () => {
396
+ return {
397
+ currency: 'BTC',
398
+ floor: 9.99
399
+ }
400
+ }
401
+ }
402
+ );
403
+
404
+ const request = spec.buildRequests([bidRequest], mockBidderRequest);
405
+ expect(request[0].data.imp[0].bidfloor).to.equal(undefined)
406
+ expect(request[0].data.imp[0].bidfloorcur).to.equal(undefined)
407
+ });
408
+ })
153
409
  })
410
+
411
+ describe('FPD', function() {
412
+ let bidRequests;
413
+ const mockBidderRequest = {refererInfo: {}};
414
+
415
+ beforeEach(function () {
416
+ bidRequests = [{
417
+ bidder: 'trafficgate',
418
+ params: {
419
+ placementId: '98765-banner',
420
+ host: 'example'
421
+ },
422
+ adUnitCode: 'adunit-code',
423
+ mediaTypes: {
424
+ banner: {
425
+ sizes: [[300, 250], [300, 600]]
426
+ }
427
+ },
428
+ bidId: 'test-bid-id',
429
+ bidderRequestId: 'test-bidder-request-id',
430
+ auctionId: 'test-auction-id',
431
+ transactionId: 'test-transaction-id-1'
432
+ }, {
433
+ bidder: 'trafficgate',
434
+ mediaTypes: {
435
+ video: {
436
+ playerSize: [640, 480]
437
+ }
438
+ },
439
+ params: {
440
+ placementId: '98765-video',
441
+ host: 'example'
442
+ },
443
+ 'adUnitCode': 'adunit-code',
444
+
445
+ bidId: 'test-bid-id',
446
+ bidderRequestId: 'test-bidder-request-id',
447
+ auctionId: 'test-auction-id',
448
+ transactionId: 'test-transaction-id-2'
449
+ }];
450
+ });
451
+
452
+ it('ortb2.site should be merged in the request', function() {
453
+ const request = spec.buildRequests(bidRequests, {
454
+ ...mockBidderRequest,
455
+ 'ortb2': {
456
+ site: {
457
+ domain: 'page.example.com',
458
+ cat: ['IAB2'],
459
+ sectioncat: ['IAB2-2']
460
+ }
461
+ }
462
+ });
463
+ let data = request[0].data;
464
+ expect(data.site.domain).to.equal('page.example.com');
465
+ expect(data.site.cat).to.deep.equal(['IAB2']);
466
+ expect(data.site.sectioncat).to.deep.equal(['IAB2-2']);
467
+ });
468
+
469
+ it('ortb2.user should be merged in the request', function() {
470
+ const request = spec.buildRequests(bidRequests, {
471
+ ...mockBidderRequest,
472
+ 'ortb2': {
473
+ user: {
474
+ yob: 1985
475
+ }
476
+ }
477
+ });
478
+ let data = request[0].data;
479
+ expect(data.user.yob).to.equal(1985);
480
+ });
481
+
482
+ describe('ortb2Imp', function() {
483
+ describe('ortb2Imp.ext.data.pbadslot', function() {
484
+ beforeEach(function () {
485
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
486
+ delete bidRequests[0].ortb2Imp;
487
+ }
488
+ });
489
+
490
+ it('should not send if imp[].ext.data object is invalid', function() {
491
+ bidRequests[0].ortb2Imp = {
492
+ ext: {}
493
+ };
494
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
495
+ let data = request[0].data;
496
+ expect(data.imp[0].ext).to.not.have.property('data');
497
+ });
498
+
499
+ it('should not send if imp[].ext.data.pbadslot is undefined', function() {
500
+ bidRequests[0].ortb2Imp = {
501
+ ext: {
502
+ data: {
503
+ }
504
+ }
505
+ };
506
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
507
+ let data = request[0].data;
508
+ if (data.imp[0].ext.data) {
509
+ expect(data.imp[0].ext.data).to.not.have.property('pbadslot');
510
+ } else {
511
+ expect(data.imp[0].ext).to.not.have.property('data');
512
+ }
513
+ });
514
+
515
+ it('should send if imp[].ext.data.pbadslot is string', function() {
516
+ bidRequests[0].ortb2Imp = {
517
+ ext: {
518
+ data: {
519
+ pbadslot: 'abcd'
520
+ }
521
+ }
522
+ };
523
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
524
+ let data = request[0].data;
525
+ expect(data.imp[0].ext.data).to.have.property('pbadslot');
526
+ expect(data.imp[0].ext.data.pbadslot).to.equal('abcd');
527
+ });
528
+ });
529
+
530
+ describe('ortb2Imp.ext.data.adserver', function() {
531
+ beforeEach(function () {
532
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
533
+ delete bidRequests[0].ortb2Imp;
534
+ }
535
+ });
536
+
537
+ it('should not send if imp[].ext.data object is invalid', function() {
538
+ bidRequests[0].ortb2Imp = {
539
+ ext: {}
540
+ };
541
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
542
+ let data = request[0].data;
543
+ expect(data.imp[0].ext).to.not.have.property('data');
544
+ });
545
+
546
+ it('should not send if imp[].ext.data.adserver is undefined', function() {
547
+ bidRequests[0].ortb2Imp = {
548
+ ext: {
549
+ data: {
550
+ }
551
+ }
552
+ };
553
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
554
+ let data = request[0].data;
555
+ if (data.imp[0].ext.data) {
556
+ expect(data.imp[0].ext.data).to.not.have.property('adserver');
557
+ } else {
558
+ expect(data.imp[0].ext).to.not.have.property('data');
559
+ }
560
+ });
561
+
562
+ it('should send', function() {
563
+ let adSlotValue = 'abc';
564
+ bidRequests[0].ortb2Imp = {
565
+ ext: {
566
+ data: {
567
+ adserver: {
568
+ name: 'GAM',
569
+ adslot: adSlotValue
570
+ }
571
+ }
572
+ }
573
+ };
574
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
575
+ let data = request[0].data;
576
+ expect(data.imp[0].ext.data.adserver.name).to.equal('GAM');
577
+ expect(data.imp[0].ext.data.adserver.adslot).to.equal(adSlotValue);
578
+ });
579
+ });
580
+
581
+ describe('ortb2Imp.ext.data.other', function() {
582
+ beforeEach(function () {
583
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
584
+ delete bidRequests[0].ortb2Imp;
585
+ }
586
+ });
587
+
588
+ it('should not send if imp[].ext.data object is invalid', function() {
589
+ bidRequests[0].ortb2Imp = {
590
+ ext: {}
591
+ };
592
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
593
+ let data = request[0].data;
594
+ expect(data.imp[0].ext).to.not.have.property('data');
595
+ });
596
+
597
+ it('should not send if imp[].ext.data.other is undefined', function() {
598
+ bidRequests[0].ortb2Imp = {
599
+ ext: {
600
+ data: {
601
+ }
602
+ }
603
+ };
604
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
605
+ let data = request[0].data;
606
+ if (data.imp[0].ext.data) {
607
+ expect(data.imp[0].ext.data).to.not.have.property('other');
608
+ } else {
609
+ expect(data.imp[0].ext).to.not.have.property('data');
610
+ }
611
+ });
612
+
613
+ it('ortb2Imp.ext.data.other', function() {
614
+ bidRequests[0].ortb2Imp = {
615
+ ext: {
616
+ data: {
617
+ other: 1234
618
+ }
619
+ }
620
+ };
621
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
622
+ let data = request[0].data;
623
+ expect(data.imp[0].ext.data.other).to.equal(1234);
624
+ });
625
+ });
626
+ });
627
+
628
+ describe('with user agent client hints', function () {
629
+ it('should add device.sua if available', function () {
630
+ const bidderRequestWithUserAgentClientHints = { refererInfo: {},
631
+ ortb2: {
632
+ device: {
633
+ sua: {
634
+ source: 2,
635
+ platform: {
636
+ brand: 'macOS',
637
+ version: [ '12', '4', '0' ]
638
+ },
639
+ browsers: [
640
+ {
641
+ brand: 'Chromium',
642
+ version: [ '106', '0', '5249', '119' ]
643
+ },
644
+ {
645
+ brand: 'Google Chrome',
646
+ version: [ '106', '0', '5249', '119' ]
647
+ },
648
+ {
649
+ brand: 'Not;A=Brand',
650
+ version: [ '99', '0', '0', '0' ]
651
+ }],
652
+ mobile: 0,
653
+ model: 'Pro',
654
+ bitness: '64',
655
+ architecture: 'x86'
656
+ }
657
+ }
658
+ }};
659
+
660
+ let request = spec.buildRequests(bidRequests, bidderRequestWithUserAgentClientHints);
661
+ expect(request[0].data.device.sua).to.exist;
662
+ expect(request[0].data.device.sua).to.deep.equal(bidderRequestWithUserAgentClientHints.ortb2.device.sua);
663
+ const bidderRequestWithoutUserAgentClientHints = {refererInfo: {}, ortb2: {}};
664
+ request = spec.buildRequests(bidRequests, bidderRequestWithoutUserAgentClientHints);
665
+ expect(request[0].data.device?.sua).to.not.exist;
666
+ });
667
+ });
668
+ });
669
+
670
+ context('when there is a consent management framework', function () {
671
+ let bidRequests;
672
+ let mockConfig;
673
+ let bidderRequest;
674
+
675
+ beforeEach(function () {
676
+ bidRequests = [{
677
+ bidder: 'trafficgate',
678
+ params: {
679
+ placementId: '98765-banner',
680
+ host: 'example'
681
+ },
682
+ adUnitCode: 'adunit-code',
683
+ mediaTypes: {
684
+ banner: {
685
+ sizes: [[300, 250], [300, 600]]
686
+ }
687
+ },
688
+ bidId: 'test-bid-id',
689
+ bidderRequestId: 'test-bidder-request-id',
690
+ auctionId: 'test-auction-id',
691
+ transactionId: 'test-transaction-id-1'
692
+ }, {
693
+ bidder: 'trafficgate',
694
+ mediaTypes: {
695
+ video: {
696
+ playerSize: [640, 480]
697
+ }
698
+ },
699
+ params: {
700
+ placementId: '98765-video',
701
+ host: 'example'
702
+ },
703
+ 'adUnitCode': 'adunit-code',
704
+
705
+ bidId: 'test-bid-id',
706
+ bidderRequestId: 'test-bidder-request-id',
707
+ auctionId: 'test-auction-id',
708
+ transactionId: 'test-transaction-id-2'
709
+ }];
710
+ });
711
+
712
+ describe('us_privacy', function () {
713
+ beforeEach(function () {
714
+ bidderRequest = {
715
+ uspConsent: '1YYN',
716
+ refererInfo: {}
717
+ };
718
+
719
+ sinon.stub(config, 'getConfig').callsFake((key) => {
720
+ return utils.deepAccess(mockConfig, key);
721
+ });
722
+ });
723
+
724
+ afterEach(function () {
725
+ config.getConfig.restore();
726
+ });
727
+
728
+ it('should send a signal to specify that US Privacy applies to this request', function () {
729
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
730
+ expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN');
731
+ expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN');
732
+ });
733
+
734
+ it('should not send the regs object, when consent string is undefined', function () {
735
+ delete bidderRequest.uspConsent;
736
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
737
+ expect(request[0].data.regs?.us_privacy).to.not.exist;
738
+ });
739
+ });
740
+
741
+ describe('GDPR', function () {
742
+ beforeEach(function () {
743
+ bidderRequest = {
744
+ gdprConsent: {
745
+ consentString: 'test-gdpr-consent-string',
746
+ addtlConsent: 'test-addtl-consent-string',
747
+ gdprApplies: true
748
+ },
749
+ refererInfo: {}
750
+ };
751
+
752
+ mockConfig = {
753
+ consentManagement: {
754
+ cmpApi: 'iab',
755
+ timeout: 1111,
756
+ allowAuctionWithoutConsent: 'cancel'
757
+ }
758
+ };
759
+
760
+ sinon.stub(config, 'getConfig').callsFake((key) => {
761
+ return utils.deepAccess(mockConfig, key);
762
+ });
763
+ });
764
+
765
+ afterEach(function () {
766
+ config.getConfig.restore();
767
+ });
768
+
769
+ it('should send a signal to specify that GDPR applies to this request', function () {
770
+ bidderRequest.bids = bidRequests;
771
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
772
+ expect(request[0].data.regs.ext.gdpr).to.equal(1);
773
+ expect(request[1].data.regs.ext.gdpr).to.equal(1);
774
+ });
775
+
776
+ it('should send the consent string', function () {
777
+ bidderRequest.bids = bidRequests;
778
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
779
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
780
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
781
+ });
782
+
783
+ it('should send the addtlConsent string', function () {
784
+ bidderRequest.bids = bidRequests;
785
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
786
+ expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
787
+ expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
788
+ });
789
+
790
+ it('should send a signal to specify that GDPR does not apply to this request', function () {
791
+ bidderRequest.gdprConsent.gdprApplies = false;
792
+ bidderRequest.bids = bidRequests;
793
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
794
+ expect(request[0].data.regs.ext.gdpr).to.equal(0);
795
+ expect(request[1].data.regs.ext.gdpr).to.equal(0);
796
+ });
797
+
798
+ it('when GDPR application is undefined, should not send a signal to specify whether GDPR applies to this request, ' +
799
+ 'but can send consent data, ', function () {
800
+ delete bidderRequest.gdprConsent.gdprApplies;
801
+ bidderRequest.bids = bidRequests;
802
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
803
+ expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok;
804
+ expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
805
+ expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
806
+ });
807
+
808
+ it('when consent string is undefined, should not send the consent string, ', function () {
809
+ delete bidderRequest.gdprConsent.consentString;
810
+ bidderRequest.bids = bidRequests;
811
+ const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
812
+ expect(request[0].data.imp[0].ext.consent).to.equal(undefined);
813
+ expect(request[1].data.imp[0].ext.consent).to.equal(undefined);
814
+ });
815
+ });
816
+ });
817
+
818
+ context('coppa', function() {
819
+ it('when there are no coppa param settings, should not send a coppa flag', function () {
820
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
821
+ expect(request[0].data.regs?.coppa).to.be.not.ok;
822
+ });
823
+
824
+ it('should send a coppa flag there is when there is coppa param settings in the bid requests', function () {
825
+ let mockConfig = {
826
+ coppa: true
827
+ };
828
+
829
+ sinon.stub(config, 'getConfig').callsFake((key) => {
830
+ return utils.deepAccess(mockConfig, key);
831
+ });
832
+
833
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
834
+ expect(request[0].data.regs.coppa).to.equal(1);
835
+ });
836
+
837
+ it('should send a coppa flag there is when there is coppa param settings in the bid params', function () {
838
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
839
+ request.params = {coppa: true};
840
+ expect(request[0].data.regs.coppa).to.equal(1);
841
+ });
842
+
843
+ after(function () {
844
+ config.getConfig.restore()
845
+ });
846
+ });
847
+
848
+ context('do not track (DNT)', function() {
849
+ let doNotTrackStub;
850
+
851
+ beforeEach(function () {
852
+ doNotTrackStub = sinon.stub(utils, 'getDNT');
853
+ });
854
+ afterEach(function() {
855
+ doNotTrackStub.restore();
856
+ });
857
+
858
+ it('when there is a do not track, should send a dnt', function () {
859
+ doNotTrackStub.returns(1);
860
+
861
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
862
+ expect(request[0].data.device.dnt).to.equal(1);
863
+ });
864
+
865
+ it('when there is not do not track, don\'t send dnt', function () {
866
+ doNotTrackStub.returns(0);
867
+
868
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
869
+ expect(request[0].data.device.dnt).to.equal(0);
870
+ });
871
+
872
+ it('when there is no defined do not track, don\'t send dnt', function () {
873
+ doNotTrackStub.returns(null);
874
+
875
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, syncAddFPDToBidderRequest(mockBidderRequest));
876
+ expect(request[0].data.device.dnt).to.equal(0);
877
+ });
878
+ });
879
+
880
+ context('supply chain (schain)', function () {
881
+ let bidRequests;
882
+ let schainConfig;
883
+ const supplyChainNodePropertyOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
884
+
885
+ beforeEach(function () {
886
+ schainConfig = {
887
+ ver: '1.0',
888
+ complete: 1,
889
+ nodes: [
890
+ {
891
+ asi: 'exchange1.com',
892
+ sid: '1234',
893
+ hp: 1,
894
+ rid: 'bid-request-1',
895
+ name: 'publisher',
896
+ domain: 'publisher.com'
897
+ // omitted ext
898
+ },
899
+ {
900
+ asi: 'exchange2.com',
901
+ sid: 'abcd',
902
+ hp: 1,
903
+ rid: 'bid-request-2',
904
+ // name field missing
905
+ domain: 'intermediary.com'
906
+ },
907
+ {
908
+ asi: 'exchange3.com',
909
+ sid: '4321',
910
+ hp: 1,
911
+ // request id
912
+ // name field missing
913
+ domain: 'intermediary-2.com'
914
+ }
915
+ ]
916
+ };
917
+
918
+ bidRequests = [{
919
+ bidder: 'trafficgate',
920
+ params: {
921
+ placementId: '11',
922
+ host: 'example'
923
+ },
924
+ adUnitCode: '/adunit-code/test-path',
925
+ mediaTypes: {
926
+ banner: {
927
+ sizes: [[300, 250], [300, 600]]
928
+ }
929
+ },
930
+ bidId: 'test-bid-id-1',
931
+ bidderRequestId: 'test-bid-request-1',
932
+ auctionId: 'test-auction-1',
933
+ schain: schainConfig
934
+ }];
935
+ });
936
+
937
+ it('should send a supply chain object', function () {
938
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
939
+ expect(request[0].data.source.ext.schain).to.equal(schainConfig);
940
+ });
941
+
942
+ it('should send the supply chain object with the right version', function () {
943
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
944
+ expect(request[0].data.source.ext.schain.ver).to.equal(schainConfig.ver);
945
+ });
946
+
947
+ it('should send the supply chain object with the right complete value', function () {
948
+ const request = spec.buildRequests(bidRequests, mockBidderRequest);
949
+ expect(request[0].data.source.ext.schain.complete).to.equal(schainConfig.complete);
950
+ });
951
+ });
952
+
953
+ context('when there are userid providers', function () {
954
+ const userIdAsEids = [
955
+ {
956
+ source: 'adserver.org',
957
+ uids: [{
958
+ id: 'some-random-id-value',
959
+ atype: 1,
960
+ ext: {
961
+ rtiPartner: 'TDID'
962
+ }
963
+ }]
964
+ },
965
+ {
966
+ source: 'id5-sync.com',
967
+ uids: [{
968
+ id: 'some-random-id-value',
969
+ atype: 1
970
+ }]
971
+ },
972
+ {
973
+ source: 'sharedid.org',
974
+ uids: [{
975
+ id: 'some-random-id-value',
976
+ atype: 1,
977
+ ext: {
978
+ third: 'some-random-id-value'
979
+ }
980
+ }]
981
+ }
982
+ ];
983
+
984
+ it(`should send the user id under the extended ids`, function () {
985
+ const bidRequestsWithUserId = [{
986
+ bidder: 'trafficgate',
987
+ params: {
988
+ placementId: '11',
989
+ host: 'example'
990
+ },
991
+ userId: {
992
+ },
993
+ adUnitCode: 'adunit-code',
994
+ mediaTypes: {
995
+ banner: {
996
+ sizes: [[300, 250], [300, 600]]
997
+ }
998
+ },
999
+ bidId: 'test-bid-id-1',
1000
+ bidderRequestId: 'test-bid-request-1',
1001
+ auctionId: 'test-auction-1',
1002
+ userIdAsEids: userIdAsEids
1003
+ }];
1004
+ // enrich bid request with userId key/value
1005
+
1006
+ const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest);
1007
+ expect(request[0].data.user.ext.eids).to.equal(userIdAsEids);
1008
+ });
1009
+
1010
+ it(`when no user ids are available, it should not send any extended ids`, function () {
1011
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1012
+ expect(request[0].data).to.not.have.any.keys('user');
1013
+ });
1014
+ });
1015
+
1016
+ context('FLEDGE', function() {
1017
+ it('when FLEDGE is enabled, should send whatever is set in ortb2imp.ext.ae in all bid requests', function () {
1018
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, {
1019
+ ...mockBidderRequest,
1020
+ fledgeEnabled: true
1021
+ });
1022
+ expect(request[0].data.imp[0].ext.ae).to.equal(2);
1023
+ });
1024
+ });
1025
+ });
1026
+
1027
+ context('banner', function () {
1028
+ it('should send bid request with a mediaTypes specified with banner type', function () {
1029
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1030
+ expect(request[0].data.imp[0]).to.have.any.keys(BANNER);
1031
+ });
1032
+ });
1033
+
1034
+ if (FEATURES.VIDEO) {
1035
+ context('video', function () {
1036
+ it('should send bid request with a mediaTypes specified with video type', function () {
1037
+ const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
1038
+ expect(request[1].data.imp[0]).to.have.any.keys(VIDEO);
1039
+ });
1040
+
1041
+ it('Update imp.video with OpenRTB options from mimeTypes and params', function() {
1042
+ const bid01 = new BidRequestBuilder({
1043
+ adUnitCode: 'adunit-code-01',
1044
+ mediaTypes: {
1045
+ banner: { sizes: [[300, 250]] },
1046
+ video: {
1047
+ context: 'outstream',
1048
+ playerSize: [[300, 250]],
1049
+ mimes: ['video/mp4'],
1050
+ protocols: [8]
1051
+ }
1052
+ },
1053
+ }).withParams({
1054
+ // options in video, will merge
1055
+ video: {
1056
+ skip: 1,
1057
+ skipafter: 4,
1058
+ minduration: 10,
1059
+ maxduration: 30
1060
+ }
1061
+ }).build();
1062
+
1063
+ const bidderRequest = new BidderRequestBuilder().build();
1064
+ const expected = {
1065
+ mimes: ['video/mp4'],
1066
+ skip: 1,
1067
+ skipafter: 4,
1068
+ minduration: 10,
1069
+ maxduration: 30,
1070
+ placement: 4,
1071
+ protocols: [8],
1072
+ w: 300,
1073
+ h: 250
1074
+ };
1075
+ const requests = spec.buildRequests([bid01], bidderRequest);
1076
+ expect(requests).to.have.lengthOf(2);
1077
+ expect(requests[1].data.imp[0].video).to.deep.equal(expected);
1078
+ });
1079
+ });
154
1080
  }
1081
+ });
155
1082
 
156
- const invalidData = [
157
- {
158
- body: [{
159
- width: 300,
160
- cpm: 0.4,
161
- ad: 'Test',
162
- requestId: '9ec5b177515ee2e5',
163
- ttl: 120,
164
- creativeId: '2',
165
- netRevenue: true,
166
- currency: 'USD',
167
- dealId: '1'
168
- }]
1083
+ describe('interpretResponse()', function () {
1084
+ let bidRequestConfigs;
1085
+ let bidRequest;
1086
+ let bidResponse;
1087
+ let bid;
1088
+
1089
+ context('when there is an nbr response', function () {
1090
+ let bids;
1091
+ beforeEach(function () {
1092
+ bidRequestConfigs = [{
1093
+ bidder: 'trafficgate',
1094
+ params: {
1095
+ placementId: '98765',
1096
+ host: 'example'
1097
+ },
1098
+ adUnitCode: 'adunit-code',
1099
+ mediaTypes: {
1100
+ banner: {
1101
+ sizes: [[300, 250], [300, 600]],
1102
+ },
1103
+ },
1104
+ bidId: 'test-bid-id',
1105
+ bidderRequestId: 'test-bidder-request-id',
1106
+ auctionId: 'test-auction-id'
1107
+ }];
1108
+
1109
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1110
+
1111
+ bidResponse = {nbr: 0}; // Unknown error
1112
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1113
+ });
1114
+
1115
+ it('should not return any bids', function () {
1116
+ expect(bids.length).to.equal(0);
1117
+ });
1118
+ });
1119
+
1120
+ context('when no seatbid in response', function () {
1121
+ let bids;
1122
+ beforeEach(function () {
1123
+ bidRequestConfigs = [{
1124
+ bidder: 'trafficgate',
1125
+ params: {
1126
+ placementId: '98765',
1127
+ host: 'example'
1128
+ },
1129
+ adUnitCode: 'adunit-code',
1130
+ mediaTypes: {
1131
+ banner: {
1132
+ sizes: [[300, 250], [300, 600]],
1133
+ },
1134
+ },
1135
+ bidId: 'test-bid-id',
1136
+ bidderRequestId: 'test-bidder-request-id',
1137
+ auctionId: 'test-auction-id'
1138
+ }];
1139
+
1140
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1141
+
1142
+ bidResponse = {ext: {}, id: 'test-bid-id'};
1143
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1144
+ });
1145
+
1146
+ it('should not return any bids', function () {
1147
+ expect(bids.length).to.equal(0);
1148
+ });
1149
+ });
1150
+
1151
+ context('when there is no response', function () {
1152
+ let bids;
1153
+ beforeEach(function () {
1154
+ bidRequestConfigs = [{
1155
+ bidder: 'trafficgate',
1156
+ params: {
1157
+ placementId: '98765',
1158
+ host: 'example'
1159
+ },
1160
+ adUnitCode: 'adunit-code',
1161
+ mediaTypes: {
1162
+ banner: {
1163
+ sizes: [[300, 250], [300, 600]],
1164
+ },
1165
+ },
1166
+ bidId: 'test-bid-id',
1167
+ bidderRequestId: 'test-bidder-request-id',
1168
+ auctionId: 'test-auction-id'
1169
+ }];
1170
+
1171
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1172
+
1173
+ bidResponse = ''; // Unknown error
1174
+ bids = spec.interpretResponse({body: bidResponse}, bidRequest);
1175
+ });
1176
+
1177
+ it('should not return any bids', function () {
1178
+ expect(bids.length).to.equal(0);
1179
+ });
1180
+ });
1181
+
1182
+ const SAMPLE_BID_REQUESTS = [{
1183
+ bidder: 'trafficgate',
1184
+ params: {
1185
+ placementId: '98765',
1186
+ host: 'example'
169
1187
  },
170
- {
171
- body: [{
172
- mediaType: 'video',
173
- cpm: 0.5,
174
- requestId: '9ec5b177515ee2e5',
175
- ttl: 120,
176
- creativeId: '2',
177
- netRevenue: true,
178
- currency: 'USD',
179
- dealId: '1'
180
- }]
1188
+ adUnitCode: 'adunit-code',
1189
+ mediaTypes: {
1190
+ banner: {
1191
+ sizes: [[300, 250], [300, 600]],
1192
+ },
181
1193
  },
182
- {
183
- body: [{
184
- mediaType: 'native',
185
- clickUrl: 'example.com',
186
- title: 'Test',
187
- impressionTrackers: ['example.com'],
188
- ttl: 120,
189
- requestId: '9ec5b177515ee2e5',
190
- creativeId: '2',
191
- netRevenue: true,
192
- currency: 'USD',
1194
+ bidId: 'test-bid-id',
1195
+ bidderRequestId: 'test-bidder-request-id',
1196
+ auctionId: 'test-auction-id'
1197
+ }];
1198
+
1199
+ const SAMPLE_BID_RESPONSE = {
1200
+ seatbid: [{
1201
+ bid: [{
1202
+ impid: 'test-bid-id',
1203
+ price: 3.5,
1204
+ w: 300,
1205
+ h: 250,
1206
+ crid: 'test-creative-id',
1207
+ dealid: 'test-deal-id',
1208
+ adm: 'test-ad-markup',
1209
+ adomain: ['brand.com'],
1210
+ ext: {
1211
+ networkId: 123,
1212
+ advertiserDomains: ['domain.com'],
1213
+ }
193
1214
  }]
194
- }
195
- ]
1215
+ }],
1216
+ cur: 'USD'
1217
+ };
196
1218
 
197
- for (const obj of invalidData) {
198
- const { mediaType } = obj.body[0]
1219
+ context('when there is a response, the common response properties', function () {
1220
+ beforeEach(function () {
1221
+ bidRequestConfigs = deepClone(SAMPLE_BID_REQUESTS);
1222
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1223
+ bidResponse = deepClone(SAMPLE_BID_RESPONSE);
199
1224
 
200
- it(`Should return an empty array if invalid ${mediaType} response is passed `, () => {
201
- const response = spec.interpretResponse(obj)
1225
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1226
+ });
202
1227
 
203
- expect(response).to.be.an('array')
204
- strictEqual(0, response.length)
205
- })
206
- }
1228
+ it('should return a price', function () {
1229
+ expect(bid.cpm).to.equal(bidResponse.seatbid[0].bid[0].price);
1230
+ });
207
1231
 
208
- it('Should return an empty array if invalid response is passed', () => {
209
- const response = spec.interpretResponse({
210
- body: [{
211
- ttl: 120,
212
- creativeId: '2',
213
- netRevenue: true,
214
- currency: 'USD',
215
- dealId: '1'
216
- }]
217
- })
1232
+ it('should return a request id', function () {
1233
+ expect(bid.requestId).to.equal(bidResponse.seatbid[0].bid[0].impid);
1234
+ });
1235
+
1236
+ it('should return width and height for the creative', function () {
1237
+ expect(bid.width).to.equal(bidResponse.seatbid[0].bid[0].w);
1238
+ expect(bid.height).to.equal(bidResponse.seatbid[0].bid[0].h);
1239
+ });
218
1240
 
219
- expect(response).to.be.an('array')
220
- strictEqual(0, response.length)
221
- })
222
- })
223
- })
1241
+ it('should return a creativeId', function () {
1242
+ expect(bid.creativeId).to.equal(bidResponse.seatbid[0].bid[0].crid);
1243
+ });
1244
+
1245
+ it('should return an ad', function () {
1246
+ expect(bid.ad).to.equal(bidResponse.seatbid[0].bid[0].adm);
1247
+ });
1248
+
1249
+ it('should return a deal id if it exists', function () {
1250
+ expect(bid.dealId).to.equal(bidResponse.seatbid[0].bid[0].dealid);
1251
+ });
1252
+
1253
+ it('should have a time-to-live of 5 minutes', function () {
1254
+ expect(bid.ttl).to.equal(300);
1255
+ });
1256
+
1257
+ it('should always return net revenue', function () {
1258
+ expect(bid.netRevenue).to.equal(true);
1259
+ });
1260
+
1261
+ it('should return a currency', function () {
1262
+ expect(bid.currency).to.equal(bidResponse.cur);
1263
+ });
1264
+
1265
+ it('should return a networkId', function () {
1266
+ expect(bid.meta.networkId).to.equal(bidResponse.seatbid[0].bid[0].ext.networkId);
1267
+ });
1268
+
1269
+ it('should return adomain', function () {
1270
+ expect(bid.meta.advertiserDomains).to.equal(bidResponse.seatbid[0].bid[0].ext.advertiserDomains);
1271
+ });
1272
+ });
1273
+
1274
+ context('when the response is a banner', function() {
1275
+ beforeEach(function () {
1276
+ bidRequestConfigs = [{
1277
+ bidder: 'trafficgate',
1278
+ params: {
1279
+ placementId: '98765',
1280
+ host: 'example'
1281
+ },
1282
+ adUnitCode: 'adunit-code',
1283
+ mediaTypes: {
1284
+ banner: {
1285
+ sizes: [[300, 250], [300, 600]],
1286
+ },
1287
+ },
1288
+ bidId: 'test-bid-id',
1289
+ bidderRequestId: 'test-bidder-request-id',
1290
+ auctionId: 'test-auction-id'
1291
+ }];
1292
+
1293
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1294
+
1295
+ bidResponse = {
1296
+ seatbid: [{
1297
+ bid: [{
1298
+ impid: 'test-bid-id',
1299
+ price: 2,
1300
+ w: 300,
1301
+ h: 250,
1302
+ crid: 'test-creative-id',
1303
+ dealid: 'test-deal-id',
1304
+ adm: 'test-ad-markup'
1305
+ }]
1306
+ }],
1307
+ cur: 'AUS'
1308
+ };
1309
+
1310
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1311
+ });
1312
+
1313
+ it('should return the proper mediaType', function () {
1314
+ it('should return a creativeId', function () {
1315
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
1316
+ });
1317
+ });
1318
+ });
1319
+
1320
+ if (FEATURES.VIDEO) {
1321
+ context('when the response is a video', function() {
1322
+ beforeEach(function () {
1323
+ bidRequestConfigs = [{
1324
+ bidder: 'trafficgate',
1325
+ params: {
1326
+ placementId: '98765',
1327
+ host: 'example'
1328
+ },
1329
+ adUnitCode: 'adunit-code',
1330
+ mediaTypes: {
1331
+ video: {
1332
+ playerSize: [[640, 360], [854, 480]],
1333
+ },
1334
+ },
1335
+ bidId: 'test-bid-id',
1336
+ bidderRequestId: 'test-bidder-request-id',
1337
+ auctionId: 'test-auction-id'
1338
+ }];
1339
+
1340
+ bidRequest = spec.buildRequests(bidRequestConfigs, {refererInfo: {}})[0];
1341
+
1342
+ bidResponse = {
1343
+ seatbid: [{
1344
+ bid: [{
1345
+ impid: 'test-bid-id',
1346
+ price: 2,
1347
+ w: 854,
1348
+ h: 480,
1349
+ crid: 'test-creative-id',
1350
+ dealid: 'test-deal-id',
1351
+ adm: 'test-ad-markup',
1352
+ }]
1353
+ }],
1354
+ cur: 'AUS'
1355
+ };
1356
+ });
1357
+
1358
+ it('should return the proper mediaType', function () {
1359
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1360
+ expect(bid.mediaType).to.equal(Object.keys(bidRequestConfigs[0].mediaTypes)[0]);
1361
+ });
1362
+
1363
+ it('should return the proper mediaType', function () {
1364
+ const winUrl = 'https//my.win.url';
1365
+ bidResponse.seatbid[0].bid[0].nurl = winUrl
1366
+ bid = spec.interpretResponse({body: bidResponse}, bidRequest)[0];
1367
+
1368
+ expect(bid.vastUrl).to.equal(winUrl);
1369
+ });
1370
+ });
1371
+ }
1372
+ });
1373
+ });