prebid.js 5.19.0 → 6.2.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 (161) hide show
  1. package/.babelrc.js +1 -10
  2. package/README.md +4 -2
  3. package/browsers.json +13 -37
  4. package/gulpfile.js +1 -0
  5. package/karma.conf.maker.js +1 -1
  6. package/modules/adheseBidAdapter.js +7 -2
  7. package/modules/adkernelBidAdapter.js +1 -0
  8. package/modules/adlivetechBidAdapter.md +61 -0
  9. package/modules/admixerBidAdapter.js +2 -1
  10. package/modules/adnuntiusBidAdapter.js +2 -1
  11. package/modules/adomikAnalyticsAdapter.js +10 -4
  12. package/modules/adplusBidAdapter.js +203 -0
  13. package/modules/adplusBidAdapter.md +39 -0
  14. package/modules/adyoulikeBidAdapter.js +7 -2
  15. package/modules/airgridRtdProvider.js +1 -1
  16. package/modules/appnexusBidAdapter.js +28 -5
  17. package/modules/atsAnalyticsAdapter.js +67 -46
  18. package/modules/atsAnalyticsAdapter.md +1 -0
  19. package/modules/beachfrontBidAdapter.js +14 -17
  20. package/modules/betweenBidAdapter.js +2 -1
  21. package/modules/browsiRtdProvider.js +106 -18
  22. package/modules/cleanioRtdProvider.js +192 -0
  23. package/modules/cleanioRtdProvider.md +59 -0
  24. package/modules/codefuelBidAdapter.js +1 -3
  25. package/modules/codefuelBidAdapter.md +3 -3
  26. package/modules/craftBidAdapter.js +5 -3
  27. package/modules/datablocksBidAdapter.js +3 -3
  28. package/modules/dchain.js +149 -0
  29. package/modules/dchain.md +45 -0
  30. package/modules/deepintentBidAdapter.js +1 -1
  31. package/modules/deltaprojectsBidAdapter.js +252 -0
  32. package/modules/deltaprojectsBidAdapter.md +32 -0
  33. package/modules/emx_digitalBidAdapter.js +9 -1
  34. package/modules/engageyaBidAdapter.js +68 -54
  35. package/modules/freewheel-sspBidAdapter.js +6 -0
  36. package/modules/glimpseBidAdapter.js +31 -16
  37. package/modules/goldbachBidAdapter.js +1176 -0
  38. package/modules/goldbachBidAdapter.md +151 -0
  39. package/modules/gptPreAuction.js +11 -5
  40. package/modules/gridBidAdapter.js +1 -0
  41. package/modules/gumgumBidAdapter.js +5 -1
  42. package/modules/id5IdSystem.md +6 -6
  43. package/modules/imRtdProvider.js +31 -0
  44. package/modules/intersectionRtdProvider.js +114 -0
  45. package/modules/invibesBidAdapter.js +15 -9
  46. package/modules/ipromBidAdapter.js +79 -0
  47. package/modules/ixBidAdapter.js +173 -22
  48. package/modules/jixieBidAdapter.js +8 -2
  49. package/modules/justpremiumBidAdapter.js +6 -1
  50. package/modules/limelightDigitalBidAdapter.js +2 -1
  51. package/modules/livewrappedAnalyticsAdapter.js +5 -0
  52. package/modules/luponmediaBidAdapter.js +570 -0
  53. package/modules/merkleIdSystem.js +5 -0
  54. package/modules/missenaBidAdapter.js +89 -0
  55. package/modules/multibid/index.js +3 -3
  56. package/modules/nativoBidAdapter.js +32 -2
  57. package/modules/oguryBidAdapter.js +2 -1
  58. package/modules/openxBidAdapter.js +7 -2
  59. package/modules/operaadsBidAdapter.js +21 -1
  60. package/modules/otmBidAdapter.js +146 -0
  61. package/modules/otmBidAdapter.md +27 -26
  62. package/modules/outbrainBidAdapter.js +5 -0
  63. package/modules/playwireBidAdapter.md +61 -0
  64. package/modules/prebidServerBidAdapter/index.js +3 -3
  65. package/modules/pubmaticBidAdapter.js +5 -3
  66. package/modules/relaidoBidAdapter.js +86 -65
  67. package/modules/richaudienceBidAdapter.js +1 -1
  68. package/modules/rtdModule/index.js +2 -2
  69. package/modules/saambaaBidAdapter.js +420 -0
  70. package/modules/saambaaBidAdapter.md +65 -68
  71. package/modules/seedtagBidAdapter.js +6 -0
  72. package/modules/smaatoBidAdapter.js +9 -1
  73. package/modules/smartxBidAdapter.js +17 -1
  74. package/modules/sonobiBidAdapter.js +7 -0
  75. package/modules/sortableBidAdapter.js +1 -0
  76. package/modules/sspBCBidAdapter.js +34 -3
  77. package/modules/tappxBidAdapter.js +3 -1
  78. package/modules/teadsBidAdapter.js +3 -0
  79. package/modules/trustxBidAdapter.js +18 -7
  80. package/modules/undertoneBidAdapter.js +8 -1
  81. package/modules/userId/index.js +27 -2
  82. package/modules/ventes.md +71 -0
  83. package/modules/ventesBidAdapter.js +410 -0
  84. package/modules/ventesBidAdapter.md +93 -0
  85. package/modules/vidoomyBidAdapter.js +51 -100
  86. package/modules/visxBidAdapter.js +20 -3
  87. package/modules/visxBidAdapter.md +4 -6
  88. package/modules/yahoosspBidAdapter.js +6 -6
  89. package/modules/yahoosspBidAdapter.md +1 -1
  90. package/modules/yieldlabBidAdapter.js +41 -10
  91. package/modules/yieldlabBidAdapter.md +91 -48
  92. package/modules/yieldoneBidAdapter.js +115 -11
  93. package/package.json +6 -1
  94. package/src/adapterManager.js +14 -8
  95. package/src/auction.js +14 -13
  96. package/src/targeting.js +2 -2
  97. package/src/utils.js +7 -0
  98. package/test/spec/integration/faker/googletag.js +6 -0
  99. package/test/spec/modules/adheseBidAdapter_spec.js +27 -1
  100. package/test/spec/modules/adnuntiusBidAdapter_spec.js +18 -0
  101. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  102. package/test/spec/modules/adplusBidAdapter_spec.js +213 -0
  103. package/test/spec/modules/adyoulikeBidAdapter_spec.js +26 -0
  104. package/test/spec/modules/appnexusBidAdapter_spec.js +65 -2
  105. package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
  106. package/test/spec/modules/beachfrontBidAdapter_spec.js +65 -1
  107. package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
  108. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  109. package/test/spec/modules/codefuelBidAdapter_spec.js +1 -1
  110. package/test/spec/modules/datablocksBidAdapter_spec.js +3 -3
  111. package/test/spec/modules/dchain_spec.js +329 -0
  112. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  113. package/test/spec/modules/emx_digitalBidAdapter_spec.js +10 -0
  114. package/test/spec/modules/engageyaBidAdapter_spec.js +231 -95
  115. package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
  116. package/test/spec/modules/freewheel-sspBidAdapter_spec.js +19 -0
  117. package/test/spec/modules/glimpseBidAdapter_spec.js +33 -0
  118. package/test/spec/modules/goldbachBidAdapter_spec.js +1359 -0
  119. package/test/spec/modules/gptPreAuction_spec.js +58 -4
  120. package/test/spec/modules/gumgumBidAdapter_spec.js +6 -0
  121. package/test/spec/modules/imRtdProvider_spec.js +25 -0
  122. package/test/spec/modules/intersectionRtdProvider_spec.js +141 -0
  123. package/test/spec/modules/invibesBidAdapter_spec.js +29 -4
  124. package/test/spec/modules/ipromBidAdapter_spec.js +195 -0
  125. package/test/spec/modules/ixBidAdapter_spec.js +288 -5
  126. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  127. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  128. package/test/spec/modules/konduitWrapper_spec.js +0 -1
  129. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +10 -7
  130. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +23 -4
  131. package/test/spec/modules/luponmediaBidAdapter_spec.js +412 -0
  132. package/test/spec/modules/merkleIdSystem_spec.js +18 -0
  133. package/test/spec/modules/missenaBidAdapter_spec.js +134 -0
  134. package/test/spec/modules/multibid_spec.js +31 -31
  135. package/test/spec/modules/nativoBidAdapter_spec.js +35 -18
  136. package/test/spec/modules/oguryBidAdapter_spec.js +13 -11
  137. package/test/spec/modules/openxBidAdapter_spec.js +5 -26
  138. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  139. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  140. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  141. package/test/spec/modules/prebidServerBidAdapter_spec.js +19 -2
  142. package/test/spec/modules/pubmaticBidAdapter_spec.js +1 -1
  143. package/test/spec/modules/relaidoBidAdapter_spec.js +71 -63
  144. package/test/spec/modules/seedtagBidAdapter_spec.js +3 -0
  145. package/test/spec/modules/smaatoBidAdapter_spec.js +61 -0
  146. package/test/spec/modules/smartxBidAdapter_spec.js +9 -0
  147. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  148. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  149. package/test/spec/modules/sspBCBidAdapter_spec.js +33 -3
  150. package/test/spec/modules/tappxBidAdapter_spec.js +4 -0
  151. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  152. package/test/spec/modules/trustxBidAdapter_spec.js +45 -3
  153. package/test/spec/modules/userId_spec.js +51 -0
  154. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  155. package/test/spec/modules/vidoomyBidAdapter_spec.js +32 -13
  156. package/test/spec/modules/visxBidAdapter_spec.js +121 -5
  157. package/test/spec/modules/yieldlabBidAdapter_spec.js +81 -0
  158. package/test/spec/modules/yieldoneBidAdapter_spec.js +299 -53
  159. package/test/spec/unit/core/adapterManager_spec.js +26 -7
  160. package/test/spec/unit/core/targeting_spec.js +44 -0
  161. package/wdio.conf.js +1 -1
@@ -0,0 +1,1359 @@
1
+ import { expect } from 'chai';
2
+ import { spec } from 'modules/goldbachBidAdapter.js';
3
+ import { newBidder } from 'src/adapters/bidderFactory.js';
4
+ import * as bidderFactory from 'src/adapters/bidderFactory.js';
5
+ import { auctionManager } from 'src/auctionManager.js';
6
+ import { deepClone } from 'src/utils.js';
7
+ import { config } from 'src/config.js';
8
+
9
+ const ENDPOINT = 'https://ib.adnxs.com/ut/v3/prebid';
10
+ const PRICING_ENDPOINT = 'https://templates.da-services.ch/01_universal/burda_prebid/1.0/json/sizeCPMMapping.json';
11
+
12
+ describe('GoldbachXandrAdapter', function () {
13
+ const adapter = newBidder(spec);
14
+
15
+ describe('inherited functions', function () {
16
+ it('exists and is a function', function () {
17
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
18
+ });
19
+ });
20
+
21
+ describe('isBidRequestValid', function () {
22
+ let bid = {
23
+ 'bidder': 'goldbach',
24
+ 'params': {
25
+ 'placementId': '10433394'
26
+ },
27
+ 'adUnitCode': 'adunit-code',
28
+ 'sizes': [[300, 250], [300, 600]],
29
+ 'bidId': '30b31c1838de1e',
30
+ 'bidderRequestId': '22edbae2733bf6',
31
+ 'auctionId': '1d1a030790a475',
32
+ };
33
+
34
+ it('should return true when required params found', function () {
35
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
36
+ });
37
+
38
+ it('should return true when required params found', function () {
39
+ let bid = Object.assign({}, bid);
40
+ delete bid.params;
41
+ bid.params = {
42
+ 'member': '1234',
43
+ 'invCode': 'ABCD'
44
+ };
45
+
46
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
47
+ });
48
+
49
+ it('should return false when required params are not passed', function () {
50
+ let bid = Object.assign({}, bid);
51
+ delete bid.params;
52
+ bid.params = {
53
+ 'placementId': 0
54
+ };
55
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
56
+ });
57
+ });
58
+
59
+ describe('buildRequests', function () {
60
+ let getAdUnitsStub;
61
+ let bidRequests = [
62
+ {
63
+ 'bidder': 'goldbach',
64
+ 'params': {
65
+ 'placementId': '10433394'
66
+ },
67
+ 'adUnitCode': 'adunit-code',
68
+ 'sizes': [[300, 250], [300, 600]],
69
+ 'bidId': '30b31c1838de1e',
70
+ 'bidderRequestId': '22edbae2733bf6',
71
+ 'auctionId': '1d1a030790a475',
72
+ 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843'
73
+ }
74
+ ];
75
+
76
+ beforeEach(function() {
77
+ getAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits').callsFake(function() {
78
+ return [];
79
+ });
80
+ });
81
+
82
+ afterEach(function() {
83
+ getAdUnitsStub.restore();
84
+ });
85
+
86
+ it('should parse out private sizes', function () {
87
+ let bidRequest = Object.assign({},
88
+ bidRequests[0],
89
+ {
90
+ params: {
91
+ placementId: '10433394',
92
+ privateSizes: [300, 250]
93
+ }
94
+ }
95
+ );
96
+
97
+ const request = spec.buildRequests([bidRequest])[1];
98
+ const payload = JSON.parse(request.data);
99
+
100
+ expect(payload.tags[0].private_sizes).to.exist;
101
+ expect(payload.tags[0].private_sizes).to.deep.equal([{width: 300, height: 250}]);
102
+ });
103
+
104
+ it('should add publisher_id in request', function() {
105
+ let bidRequest = Object.assign({},
106
+ bidRequests[0],
107
+ {
108
+ params: {
109
+ placementId: '10433394',
110
+ publisherId: '1231234'
111
+ }
112
+ });
113
+ const request = spec.buildRequests([bidRequest])[1];
114
+ const payload = JSON.parse(request.data);
115
+
116
+ expect(payload.tags[0].publisher_id).to.exist;
117
+ expect(payload.tags[0].publisher_id).to.deep.equal(1231234);
118
+ expect(payload.publisher_id).to.exist;
119
+ expect(payload.publisher_id).to.deep.equal(1231234);
120
+ })
121
+
122
+ it('should add source and verison to the tag', function () {
123
+ const request = spec.buildRequests(bidRequests)[1];
124
+ const payload = JSON.parse(request.data);
125
+ expect(payload.sdk).to.exist;
126
+ expect(payload.sdk).to.deep.equal({
127
+ source: 'pbjs',
128
+ version: '$prebid.version$'
129
+ });
130
+ });
131
+
132
+ it('should populate the ad_types array on all requests', function () {
133
+ let adUnits = [{
134
+ code: 'adunit-code',
135
+ mediaTypes: {
136
+ banner: {
137
+ sizes: [[300, 250], [300, 600]]
138
+ }
139
+ },
140
+ bids: [{
141
+ bidder: 'goldbach',
142
+ params: {
143
+ placementId: '10433394'
144
+ }
145
+ }],
146
+ transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843'
147
+ }];
148
+
149
+ ['banner', 'video', 'native'].forEach(type => {
150
+ getAdUnitsStub.callsFake(function(...args) {
151
+ return adUnits;
152
+ });
153
+
154
+ const bidRequest = Object.assign({}, bidRequests[0]);
155
+ bidRequest.mediaTypes = {};
156
+ bidRequest.mediaTypes[type] = {};
157
+
158
+ const request = spec.buildRequests([bidRequest])[1];
159
+ const payload = JSON.parse(request.data);
160
+
161
+ expect(payload.tags[0].ad_types).to.deep.equal([type]);
162
+
163
+ if (type === 'banner') {
164
+ delete adUnits[0].mediaTypes;
165
+ }
166
+ });
167
+ });
168
+
169
+ it('should not populate the ad_types array when adUnit.mediaTypes is undefined', function() {
170
+ const bidRequest = Object.assign({}, bidRequests[0]);
171
+ const request = spec.buildRequests([bidRequest])[1];
172
+ const payload = JSON.parse(request.data);
173
+
174
+ expect(payload.tags[0].ad_types).to.not.exist;
175
+ });
176
+
177
+ it('should populate the ad_types array on outstream requests', function () {
178
+ const bidRequest = Object.assign({}, bidRequests[0]);
179
+ bidRequest.mediaTypes = {};
180
+ bidRequest.mediaTypes.video = {context: 'outstream'};
181
+
182
+ const request = spec.buildRequests([bidRequest])[1];
183
+ const payload = JSON.parse(request.data);
184
+
185
+ expect(payload.tags[0].ad_types).to.deep.equal(['video']);
186
+ expect(payload.tags[0].hb_source).to.deep.equal(1);
187
+ });
188
+
189
+ it('sends bid request to ENDPOINT via POST', function () {
190
+ const request = spec.buildRequests(bidRequests)[1];
191
+ expect(request.url).to.equal(ENDPOINT);
192
+ expect(request.method).to.equal('POST');
193
+ });
194
+
195
+ it('sends bid request to ENDPOINT via GET', function () {
196
+ const request = spec.buildRequests(bidRequests)[0];
197
+ expect(request.url).to.equal(PRICING_ENDPOINT);
198
+ expect(request.method).to.equal('GET');
199
+ });
200
+
201
+ it('should attach valid video params to the tag', function () {
202
+ let bidRequest = Object.assign({},
203
+ bidRequests[0],
204
+ {
205
+ params: {
206
+ placementId: '10433394',
207
+ video: {
208
+ id: 123,
209
+ minduration: 100,
210
+ foobar: 'invalid'
211
+ }
212
+ }
213
+ }
214
+ );
215
+
216
+ const request = spec.buildRequests([bidRequest])[1];
217
+ const payload = JSON.parse(request.data);
218
+ expect(payload.tags[0].video).to.deep.equal({
219
+ id: 123,
220
+ minduration: 100
221
+ });
222
+ expect(payload.tags[0].hb_source).to.deep.equal(1);
223
+ });
224
+
225
+ it('should include ORTB video values when video params were not set', function() {
226
+ let bidRequest = deepClone(bidRequests[0]);
227
+ bidRequest.params = {
228
+ placementId: '1234235',
229
+ video: {
230
+ skippable: true,
231
+ playback_method: ['auto_play_sound_off', 'auto_play_sound_unknown'],
232
+ context: 'outstream'
233
+ }
234
+ };
235
+ bidRequest.mediaTypes = {
236
+ video: {
237
+ playerSize: [640, 480],
238
+ context: 'outstream',
239
+ mimes: ['video/mp4'],
240
+ skip: 0,
241
+ minduration: 5,
242
+ api: [1, 5, 6],
243
+ playbackmethod: [2, 4]
244
+ }
245
+ };
246
+
247
+ const request = spec.buildRequests([bidRequest])[1];
248
+ const payload = JSON.parse(request.data);
249
+
250
+ expect(payload.tags[0].video).to.deep.equal({
251
+ minduration: 5,
252
+ playback_method: 2,
253
+ skippable: true,
254
+ context: 4
255
+ });
256
+ expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4])
257
+ });
258
+
259
+ it('should add video property when adUnit includes a renderer', function () {
260
+ const videoData = {
261
+ mediaTypes: {
262
+ video: {
263
+ context: 'outstream',
264
+ mimes: ['video/mp4']
265
+ }
266
+ },
267
+ params: {
268
+ placementId: '10433394',
269
+ video: {
270
+ skippable: true,
271
+ playback_method: ['auto_play_sound_off']
272
+ }
273
+ }
274
+ };
275
+
276
+ let bidRequest1 = deepClone(bidRequests[0]);
277
+ bidRequest1 = Object.assign({}, bidRequest1, videoData, {
278
+ renderer: {
279
+ url: 'https://test.renderer.url',
280
+ render: function () {}
281
+ }
282
+ });
283
+
284
+ let bidRequest2 = deepClone(bidRequests[0]);
285
+ bidRequest2.adUnitCode = 'adUnit_code_2';
286
+ bidRequest2 = Object.assign({}, bidRequest2, videoData);
287
+
288
+ const request = spec.buildRequests([bidRequest1, bidRequest2])[1];
289
+ const payload = JSON.parse(request.data);
290
+ expect(payload.tags[0].video).to.deep.equal({
291
+ skippable: true,
292
+ playback_method: 2,
293
+ custom_renderer_present: true
294
+ });
295
+ expect(payload.tags[1].video).to.deep.equal({
296
+ skippable: true,
297
+ playback_method: 2
298
+ });
299
+ });
300
+
301
+ it('should attach valid user params to the tag', function () {
302
+ let bidRequest = Object.assign({},
303
+ bidRequests[0],
304
+ {
305
+ params: {
306
+ placementId: '10433394',
307
+ user: {
308
+ externalUid: '123',
309
+ segments: [123, { id: 987, value: 876 }],
310
+ foobar: 'invalid'
311
+ }
312
+ }
313
+ }
314
+ );
315
+
316
+ const request = spec.buildRequests([bidRequest])[1];
317
+ const payload = JSON.parse(request.data);
318
+
319
+ expect(payload.user).to.exist;
320
+ expect(payload.user).to.deep.equal({
321
+ external_uid: '123',
322
+ segments: [{id: 123}, {id: 987, value: 876}]
323
+ });
324
+ });
325
+
326
+ it('should attach reserve param when either bid param or getFloor function exists', function () {
327
+ let getFloorResponse = { currency: 'USD', floor: 3 };
328
+ let request, payload = null;
329
+ let bidRequest = deepClone(bidRequests[0]);
330
+
331
+ // 1 -> reserve not defined, getFloor not defined > empty
332
+ request = spec.buildRequests([bidRequest])[1];
333
+ payload = JSON.parse(request.data);
334
+
335
+ expect(payload.tags[0].reserve).to.not.exist;
336
+
337
+ // 2 -> reserve is defined, getFloor not defined > reserve is used
338
+ bidRequest.params = {
339
+ 'placementId': '10433394',
340
+ 'reserve': 0.5
341
+ };
342
+ request = spec.buildRequests([bidRequest])[1];
343
+ payload = JSON.parse(request.data);
344
+
345
+ expect(payload.tags[0].reserve).to.exist.and.to.equal(0.5);
346
+
347
+ // 3 -> reserve is defined, getFloor is defined > getFloor is used
348
+ bidRequest.getFloor = () => getFloorResponse;
349
+
350
+ request = spec.buildRequests([bidRequest])[1];
351
+ payload = JSON.parse(request.data);
352
+
353
+ expect(payload.tags[0].reserve).to.exist.and.to.equal(3);
354
+ });
355
+
356
+ it('should duplicate adpod placements into batches and set correct maxduration', function() {
357
+ let bidRequest = Object.assign({},
358
+ bidRequests[0],
359
+ {
360
+ params: { placementId: '14542875' }
361
+ },
362
+ {
363
+ mediaTypes: {
364
+ video: {
365
+ context: 'adpod',
366
+ playerSize: [640, 480],
367
+ adPodDurationSec: 300,
368
+ durationRangeSec: [15, 30],
369
+ }
370
+ }
371
+ }
372
+ );
373
+
374
+ const request = spec.buildRequests([bidRequest])[1];
375
+ const payload1 = JSON.parse(request[0].data);
376
+ const payload2 = JSON.parse(request[1].data);
377
+
378
+ // 300 / 15 = 20 total
379
+ expect(payload1.tags.length).to.equal(15);
380
+ expect(payload2.tags.length).to.equal(5);
381
+
382
+ expect(payload1.tags[0]).to.deep.equal(payload1.tags[1]);
383
+ expect(payload1.tags[0].video.maxduration).to.equal(30);
384
+
385
+ expect(payload2.tags[0]).to.deep.equal(payload1.tags[1]);
386
+ expect(payload2.tags[0].video.maxduration).to.equal(30);
387
+ });
388
+
389
+ it('should round down adpod placements when numbers are uneven', function() {
390
+ let bidRequest = Object.assign({},
391
+ bidRequests[0],
392
+ {
393
+ params: { placementId: '14542875' }
394
+ },
395
+ {
396
+ mediaTypes: {
397
+ video: {
398
+ context: 'adpod',
399
+ playerSize: [640, 480],
400
+ adPodDurationSec: 123,
401
+ durationRangeSec: [45],
402
+ }
403
+ }
404
+ }
405
+ );
406
+
407
+ const request = spec.buildRequests([bidRequest])[1];
408
+ const payload = JSON.parse(request.data);
409
+ expect(payload.tags.length).to.equal(2);
410
+ });
411
+
412
+ it('should duplicate adpod placements when requireExactDuration is set', function() {
413
+ let bidRequest = Object.assign({},
414
+ bidRequests[0],
415
+ {
416
+ params: { placementId: '14542875' }
417
+ },
418
+ {
419
+ mediaTypes: {
420
+ video: {
421
+ context: 'adpod',
422
+ playerSize: [640, 480],
423
+ adPodDurationSec: 300,
424
+ durationRangeSec: [15, 30],
425
+ requireExactDuration: true,
426
+ }
427
+ }
428
+ }
429
+ );
430
+
431
+ // 20 total placements with 15 max impressions = 2 requests
432
+ const request = spec.buildRequests([bidRequest])[1];
433
+ expect(request.length).to.equal(2);
434
+
435
+ // 20 spread over 2 requests = 15 in first request, 5 in second
436
+ const payload1 = JSON.parse(request[0].data);
437
+ const payload2 = JSON.parse(request[1].data);
438
+ expect(payload1.tags.length).to.equal(15);
439
+ expect(payload2.tags.length).to.equal(5);
440
+
441
+ // 10 placements should have max/min at 15
442
+ // 10 placemenst should have max/min at 30
443
+ const payload1tagsWith15 = payload1.tags.filter(tag => tag.video.maxduration === 15);
444
+ const payload1tagsWith30 = payload1.tags.filter(tag => tag.video.maxduration === 30);
445
+ expect(payload1tagsWith15.length).to.equal(10);
446
+ expect(payload1tagsWith30.length).to.equal(5);
447
+
448
+ // 5 placemenst with min/max at 30 were in the first request
449
+ // so 5 remaining should be in the second
450
+ const payload2tagsWith30 = payload2.tags.filter(tag => tag.video.maxduration === 30);
451
+ expect(payload2tagsWith30.length).to.equal(5);
452
+ });
453
+
454
+ it('should set durations for placements when requireExactDuration is set and numbers are uneven', function() {
455
+ let bidRequest = Object.assign({},
456
+ bidRequests[0],
457
+ {
458
+ params: { placementId: '14542875' }
459
+ },
460
+ {
461
+ mediaTypes: {
462
+ video: {
463
+ context: 'adpod',
464
+ playerSize: [640, 480],
465
+ adPodDurationSec: 105,
466
+ durationRangeSec: [15, 30, 60],
467
+ requireExactDuration: true,
468
+ }
469
+ }
470
+ }
471
+ );
472
+
473
+ const request = spec.buildRequests([bidRequest])[1];
474
+ const payload = JSON.parse(request.data);
475
+ expect(payload.tags.length).to.equal(7);
476
+
477
+ const tagsWith15 = payload.tags.filter(tag => tag.video.maxduration === 15);
478
+ const tagsWith30 = payload.tags.filter(tag => tag.video.maxduration === 30);
479
+ const tagsWith60 = payload.tags.filter(tag => tag.video.maxduration === 60);
480
+ expect(tagsWith15.length).to.equal(3);
481
+ expect(tagsWith30.length).to.equal(3);
482
+ expect(tagsWith60.length).to.equal(1);
483
+ });
484
+
485
+ it('should break adpod request into batches', function() {
486
+ let bidRequest = Object.assign({},
487
+ bidRequests[0],
488
+ {
489
+ params: { placementId: '14542875' }
490
+ },
491
+ {
492
+ mediaTypes: {
493
+ video: {
494
+ context: 'adpod',
495
+ playerSize: [640, 480],
496
+ adPodDurationSec: 225,
497
+ durationRangeSec: [5],
498
+ }
499
+ }
500
+ }
501
+ );
502
+
503
+ const request = spec.buildRequests([bidRequest])[1];
504
+ const payload1 = JSON.parse(request[0].data);
505
+ const payload2 = JSON.parse(request[1].data);
506
+ const payload3 = JSON.parse(request[2].data);
507
+
508
+ expect(payload1.tags.length).to.equal(15);
509
+ expect(payload2.tags.length).to.equal(15);
510
+ expect(payload3.tags.length).to.equal(15);
511
+ });
512
+
513
+ // it('should contain hb_source value for adpod', function() {
514
+ // let bidRequest = Object.assign({},
515
+ // bidRequests[0],
516
+ // {
517
+ // params: { placementId: '14542875' }
518
+ // },
519
+ // {
520
+ // mediaTypes: {
521
+ // video: {
522
+ // context: 'adpod',
523
+ // playerSize: [640, 480],
524
+ // adPodDurationSec: 300,
525
+ // durationRangeSec: [15, 30],
526
+ // }
527
+ // }
528
+ // }
529
+ // );
530
+ // const request = spec.buildRequests([bidRequest])[1];
531
+ // const payload = JSON.parse(request.data);
532
+ // expect(payload.tags[0].hb_source).to.deep.equal(7);
533
+ // });
534
+
535
+ it('should contain hb_source value for other media', function() {
536
+ let bidRequest = Object.assign({},
537
+ bidRequests[0],
538
+ {
539
+ mediaType: 'banner',
540
+ params: {
541
+ sizes: [[300, 250], [300, 600]],
542
+ placementId: 13144370
543
+ }
544
+ }
545
+ );
546
+ const request = spec.buildRequests([bidRequest])[1];
547
+ const payload = JSON.parse(request.data);
548
+ expect(payload.tags[0].hb_source).to.deep.equal(1);
549
+ });
550
+
551
+ it('adds brand_category_exclusion to request when set', function() {
552
+ let bidRequest = Object.assign({}, bidRequests[0]);
553
+ sinon
554
+ .stub(config, 'getConfig')
555
+ .withArgs('adpod.brandCategoryExclusion')
556
+ .returns(true);
557
+
558
+ const request = spec.buildRequests([bidRequest])[1];
559
+ const payload = JSON.parse(request.data);
560
+
561
+ expect(payload.brand_category_uniqueness).to.equal(true);
562
+
563
+ config.getConfig.restore();
564
+ });
565
+
566
+ it('should attach native params to the request', function () {
567
+ let bidRequest = Object.assign({},
568
+ bidRequests[0],
569
+ {
570
+ mediaType: 'native',
571
+ nativeParams: {
572
+ title: {required: true},
573
+ body: {required: true},
574
+ body2: {required: true},
575
+ image: {required: true, sizes: [100, 100]},
576
+ icon: {required: true},
577
+ cta: {required: false},
578
+ rating: {required: true},
579
+ sponsoredBy: {required: true},
580
+ privacyLink: {required: true},
581
+ displayUrl: {required: true},
582
+ address: {required: true},
583
+ downloads: {required: true},
584
+ likes: {required: true},
585
+ phone: {required: true},
586
+ price: {required: true},
587
+ salePrice: {required: true}
588
+ }
589
+ }
590
+ );
591
+
592
+ const request = spec.buildRequests([bidRequest])[1];
593
+ const payload = JSON.parse(request.data);
594
+
595
+ expect(payload.tags[0].native.layouts[0]).to.deep.equal({
596
+ title: {required: true},
597
+ description: {required: true},
598
+ desc2: {required: true},
599
+ main_image: {required: true, sizes: [{ width: 100, height: 100 }]},
600
+ icon: {required: true},
601
+ ctatext: {required: false},
602
+ rating: {required: true},
603
+ sponsored_by: {required: true},
604
+ privacy_link: {required: true},
605
+ displayurl: {required: true},
606
+ address: {required: true},
607
+ downloads: {required: true},
608
+ likes: {required: true},
609
+ phone: {required: true},
610
+ price: {required: true},
611
+ saleprice: {required: true},
612
+ privacy_supported: true
613
+ });
614
+ expect(payload.tags[0].hb_source).to.equal(1);
615
+ });
616
+
617
+ it('should always populated tags[].sizes with 1,1 for native if otherwise not defined', function () {
618
+ let bidRequest = Object.assign({},
619
+ bidRequests[0],
620
+ {
621
+ mediaType: 'native',
622
+ nativeParams: {
623
+ image: { required: true }
624
+ }
625
+ }
626
+ );
627
+ bidRequest.sizes = [[150, 100], [300, 250]];
628
+
629
+ let request = spec.buildRequests([bidRequest])[1];
630
+ let payload = JSON.parse(request.data);
631
+ expect(payload.tags[0].sizes).to.deep.equal([{width: 150, height: 100}, {width: 300, height: 250}]);
632
+
633
+ delete bidRequest.sizes;
634
+
635
+ request = spec.buildRequests([bidRequest])[1];
636
+ payload = JSON.parse(request.data);
637
+
638
+ expect(payload.tags[0].sizes).to.deep.equal([{width: 1, height: 1}]);
639
+ });
640
+
641
+ it('should convert keyword params to proper form and attaches to request', function () {
642
+ let bidRequest = Object.assign({},
643
+ bidRequests[0],
644
+ {
645
+ params: {
646
+ placementId: '10433394',
647
+ keywords: {
648
+ single: 'val',
649
+ singleArr: ['val'],
650
+ singleArrNum: [5],
651
+ multiValMixed: ['value1', 2, 'value3'],
652
+ singleValNum: 123,
653
+ emptyStr: '',
654
+ emptyArr: [''],
655
+ badValue: {'foo': 'bar'} // should be dropped
656
+ }
657
+ }
658
+ }
659
+ );
660
+
661
+ const request = spec.buildRequests([bidRequest])[1];
662
+ const payload = JSON.parse(request.data);
663
+
664
+ expect(payload.tags[0].keywords).to.deep.equal([{
665
+ 'key': 'single',
666
+ 'value': ['val']
667
+ }, {
668
+ 'key': 'singleArr',
669
+ 'value': ['val']
670
+ }, {
671
+ 'key': 'singleArrNum',
672
+ 'value': ['5']
673
+ }, {
674
+ 'key': 'multiValMixed',
675
+ 'value': ['value1', '2', 'value3']
676
+ }, {
677
+ 'key': 'singleValNum',
678
+ 'value': ['123']
679
+ }, {
680
+ 'key': 'emptyStr'
681
+ }, {
682
+ 'key': 'emptyArr'
683
+ }]);
684
+ });
685
+
686
+ it('should add payment rules to the request', function () {
687
+ let bidRequest = Object.assign({},
688
+ bidRequests[0],
689
+ {
690
+ params: {
691
+ placementId: '10433394',
692
+ usePaymentRule: true
693
+ }
694
+ }
695
+ );
696
+
697
+ const request = spec.buildRequests([bidRequest])[1];
698
+ const payload = JSON.parse(request.data);
699
+
700
+ expect(payload.tags[0].use_pmt_rule).to.equal(true);
701
+ });
702
+
703
+ it('should add gpid to the request', function () {
704
+ let testGpid = '/12345/my-gpt-tag-0';
705
+ let bidRequest = deepClone(bidRequests[0]);
706
+ bidRequest.ortb2Imp = { ext: { data: { pbadslot: testGpid } } };
707
+
708
+ const request = spec.buildRequests([bidRequest])[1];
709
+ const payload = JSON.parse(request.data);
710
+
711
+ expect(payload.tags[0].gpid).to.exist.and.equal(testGpid)
712
+ });
713
+
714
+ it('should add gdpr consent information to the request', function () {
715
+ let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==';
716
+ let bidderRequest = {
717
+ 'bidderCode': 'goldbach',
718
+ 'auctionId': '1d1a030790a475',
719
+ 'bidderRequestId': '22edbae2733bf6',
720
+ 'timeout': 3000,
721
+ 'gdprConsent': {
722
+ consentString: consentString,
723
+ gdprApplies: true,
724
+ addtlConsent: '1~7.12.35.62.66.70.89.93.108'
725
+ }
726
+ };
727
+ bidderRequest.bids = bidRequests;
728
+
729
+ const request = spec.buildRequests(bidRequests, bidderRequest)[1];
730
+ expect(request.options).to.deep.equal({withCredentials: true});
731
+ const payload = JSON.parse(request.data);
732
+
733
+ expect(payload.gdpr_consent).to.exist;
734
+ expect(payload.gdpr_consent.consent_string).to.exist.and.to.equal(consentString);
735
+ expect(payload.gdpr_consent.consent_required).to.exist.and.to.be.true;
736
+ expect(payload.gdpr_consent.addtl_consent).to.exist.and.to.deep.equal([7, 12, 35, 62, 66, 70, 89, 93, 108]);
737
+ });
738
+
739
+ it('should add us privacy string to payload', function() {
740
+ let consentString = '1YA-';
741
+ let bidderRequest = {
742
+ 'bidderCode': 'goldbach',
743
+ 'auctionId': '1d1a030790a475',
744
+ 'bidderRequestId': '22edbae2733bf6',
745
+ 'timeout': 3000,
746
+ 'uspConsent': consentString
747
+ };
748
+ bidderRequest.bids = bidRequests;
749
+
750
+ const request = spec.buildRequests(bidRequests, bidderRequest)[1];
751
+ const payload = JSON.parse(request.data);
752
+
753
+ expect(payload.us_privacy).to.exist;
754
+ expect(payload.us_privacy).to.exist.and.to.equal(consentString);
755
+ });
756
+
757
+ it('supports sending hybrid mobile app parameters', function () {
758
+ let appRequest = Object.assign({},
759
+ bidRequests[0],
760
+ {
761
+ params: {
762
+ placementId: '10433394',
763
+ app: {
764
+ id: 'B1O2W3M4AN.com.prebid.webview',
765
+ geo: {
766
+ lat: 40.0964439,
767
+ lng: -75.3009142
768
+ },
769
+ device_id: {
770
+ idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', // Apple advertising identifier
771
+ aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', // Android advertising identifier
772
+ md5udid: '5756ae9022b2ea1e47d84fead75220c8', // MD5 hash of the ANDROID_ID
773
+ sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', // SHA1 hash of the ANDROID_ID
774
+ windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' // Windows advertising identifier
775
+ }
776
+ }
777
+ }
778
+ }
779
+ );
780
+ const request = spec.buildRequests([appRequest])[1];
781
+ const payload = JSON.parse(request.data);
782
+ expect(payload.app).to.exist;
783
+ expect(payload.app).to.deep.equal({
784
+ appid: 'B1O2W3M4AN.com.prebid.webview'
785
+ });
786
+ expect(payload.device.device_id).to.exist;
787
+ expect(payload.device.device_id).to.deep.equal({
788
+ aaid: '38400000-8cf0-11bd-b23e-10b96e40000d',
789
+ idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE',
790
+ md5udid: '5756ae9022b2ea1e47d84fead75220c8',
791
+ sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF',
792
+ windowsadid: '750c6be243f1c4b5c9912b95a5742fc5'
793
+ });
794
+ expect(payload.device.geo).to.exist;
795
+ expect(payload.device.geo).to.deep.equal({
796
+ lat: 40.0964439,
797
+ lng: -75.3009142
798
+ });
799
+ });
800
+
801
+ it('should add referer info to payload', function () {
802
+ const bidRequest = Object.assign({}, bidRequests[0])
803
+ const bidderRequest = {
804
+ refererInfo: {
805
+ referer: 'https://example.com/page.html',
806
+ reachedTop: true,
807
+ numIframes: 2,
808
+ stack: [
809
+ 'https://example.com/page.html',
810
+ 'https://example.com/iframe1.html',
811
+ 'https://example.com/iframe2.html'
812
+ ]
813
+ }
814
+ }
815
+ const request = spec.buildRequests([bidRequest], bidderRequest)[1];
816
+ const payload = JSON.parse(request.data);
817
+
818
+ expect(payload.referrer_detection).to.exist;
819
+ expect(payload.referrer_detection).to.deep.equal({
820
+ rd_ref: 'https%3A%2F%2Fexample.com%2Fpage.html',
821
+ rd_top: true,
822
+ rd_ifs: 2,
823
+ rd_stk: bidderRequest.refererInfo.stack.map((url) => encodeURIComponent(url)).join(',')
824
+ });
825
+ });
826
+
827
+ it('should populate schain if available', function () {
828
+ const bidRequest = Object.assign({}, bidRequests[0], {
829
+ schain: {
830
+ ver: '1.0',
831
+ complete: 1,
832
+ nodes: [
833
+ {
834
+ 'asi': 'blob.com',
835
+ 'sid': '001',
836
+ 'hp': 1
837
+ }
838
+ ]
839
+ }
840
+ });
841
+
842
+ const request = spec.buildRequests([bidRequest])[1];
843
+ const payload = JSON.parse(request.data);
844
+ expect(payload.schain).to.deep.equal({
845
+ ver: '1.0',
846
+ complete: 1,
847
+ nodes: [
848
+ {
849
+ 'asi': 'blob.com',
850
+ 'sid': '001',
851
+ 'hp': 1
852
+ }
853
+ ]
854
+ });
855
+ });
856
+
857
+ it('should populate coppa if set in config', function () {
858
+ let bidRequest = Object.assign({}, bidRequests[0]);
859
+ sinon.stub(config, 'getConfig')
860
+ .withArgs('coppa')
861
+ .returns(true);
862
+
863
+ const request = spec.buildRequests([bidRequest])[1];
864
+ const payload = JSON.parse(request.data);
865
+
866
+ expect(payload.user.coppa).to.equal(true);
867
+
868
+ config.getConfig.restore();
869
+ });
870
+
871
+ it('should set the X-Is-Test customHeader if test flag is enabled', function () {
872
+ let bidRequest = Object.assign({}, bidRequests[0]);
873
+ sinon.stub(config, 'getConfig')
874
+ .withArgs('apn_test')
875
+ .returns(true);
876
+
877
+ const request = spec.buildRequests([bidRequest])[1];
878
+ expect(request.options.customHeaders).to.deep.equal({'X-Is-Test': 1});
879
+
880
+ config.getConfig.restore();
881
+ });
882
+
883
+ it('should always set withCredentials: true on the request.options', function () {
884
+ let bidRequest = Object.assign({}, bidRequests[0]);
885
+ const request = spec.buildRequests([bidRequest])[1];
886
+ expect(request.options.withCredentials).to.equal(true);
887
+ });
888
+
889
+ it('should set simple domain variant if purpose 1 consent is not given', function () {
890
+ let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==';
891
+ let bidderRequest = {
892
+ 'bidderCode': 'goldbach',
893
+ 'auctionId': '1d1a030790a475',
894
+ 'bidderRequestId': '22edbae2733bf6',
895
+ 'timeout': 3000,
896
+ 'gdprConsent': {
897
+ consentString: consentString,
898
+ gdprApplies: true,
899
+ apiVersion: 2,
900
+ vendorData: {
901
+ purpose: {
902
+ consents: {
903
+ 1: false
904
+ }
905
+ }
906
+ }
907
+ }
908
+ };
909
+ bidderRequest.bids = bidRequests;
910
+
911
+ const request = spec.buildRequests(bidRequests, bidderRequest)[1];
912
+ expect(request.url).to.equal('https://ib.adnxs-simple.com/ut/v3/prebid');
913
+ });
914
+
915
+ it('should populate eids when supported userIds are available', function () {
916
+ const bidRequest = Object.assign({}, bidRequests[0], {
917
+ userId: {
918
+ tdid: 'sample-userid',
919
+ uid2: { id: 'sample-uid2-value' },
920
+ criteoId: 'sample-criteo-userid',
921
+ netId: 'sample-netId-userid',
922
+ idl_env: 'sample-idl-userid',
923
+ flocId: {
924
+ id: 'sample-flocid-value',
925
+ version: 'chrome.1.0'
926
+ }
927
+ }
928
+ });
929
+
930
+ const request = spec.buildRequests([bidRequest])[1];
931
+ const payload = JSON.parse(request.data);
932
+ expect(payload.eids).to.deep.include({
933
+ source: 'adserver.org',
934
+ id: 'sample-userid',
935
+ rti_partner: 'TDID'
936
+ });
937
+
938
+ expect(payload.eids).to.deep.include({
939
+ source: 'criteo.com',
940
+ id: 'sample-criteo-userid',
941
+ });
942
+
943
+ expect(payload.eids).to.deep.include({
944
+ source: 'chrome.com',
945
+ id: 'sample-flocid-value'
946
+ });
947
+
948
+ expect(payload.eids).to.deep.include({
949
+ source: 'netid.de',
950
+ id: 'sample-netId-userid',
951
+ });
952
+
953
+ expect(payload.eids).to.deep.include({
954
+ source: 'liveramp.com',
955
+ id: 'sample-idl-userid'
956
+ });
957
+
958
+ expect(payload.eids).to.deep.include({
959
+ source: 'uidapi.com',
960
+ id: 'sample-uid2-value',
961
+ rti_partner: 'UID2'
962
+ });
963
+ });
964
+
965
+ it('should populate iab_support object at the root level if omid support is detected', function () {
966
+ // with bid.params.frameworks
967
+ let bidRequest_A = Object.assign({}, bidRequests[0], {
968
+ params: {
969
+ frameworks: [1, 2, 5, 6],
970
+ video: {
971
+ frameworks: [1, 2, 5, 6]
972
+ }
973
+ }
974
+ });
975
+ let request = spec.buildRequests([bidRequest_A])[1];
976
+ let payload = JSON.parse(request.data);
977
+ expect(payload.iab_support).to.be.an('object');
978
+ expect(payload.iab_support).to.deep.equal({
979
+ omidpn: 'Appnexus',
980
+ omidpv: '$prebid.version$'
981
+ });
982
+ expect(payload.tags[0].banner_frameworks).to.be.an('array');
983
+ expect(payload.tags[0].banner_frameworks).to.deep.equal([1, 2, 5, 6]);
984
+ expect(payload.tags[0].video_frameworks).to.be.an('array');
985
+ expect(payload.tags[0].video_frameworks).to.deep.equal([1, 2, 5, 6]);
986
+ expect(payload.tags[0].video.frameworks).to.not.exist;
987
+
988
+ // without bid.params.frameworks
989
+ const bidRequest_B = Object.assign({}, bidRequests[0]);
990
+ request = spec.buildRequests([bidRequest_B])[1];
991
+ payload = JSON.parse(request.data);
992
+ expect(payload.iab_support).to.not.exist;
993
+ expect(payload.tags[0].banner_frameworks).to.not.exist;
994
+ expect(payload.tags[0].video_frameworks).to.not.exist;
995
+
996
+ // with video.frameworks but it is not an array
997
+ const bidRequest_C = Object.assign({}, bidRequests[0], {
998
+ params: {
999
+ video: {
1000
+ frameworks: "'1', '2', '3', '6'"
1001
+ }
1002
+ }
1003
+ });
1004
+ request = spec.buildRequests([bidRequest_C])[1];
1005
+ payload = JSON.parse(request.data);
1006
+ expect(payload.iab_support).to.not.exist;
1007
+ expect(payload.tags[0].banner_frameworks).to.not.exist;
1008
+ expect(payload.tags[0].video_frameworks).to.not.exist;
1009
+ });
1010
+ })
1011
+
1012
+ describe('interpretResponse', function () {
1013
+ let bfStub;
1014
+ before(function() {
1015
+ bfStub = sinon.stub(bidderFactory, 'getIabSubCategory');
1016
+ });
1017
+
1018
+ after(function() {
1019
+ bfStub.restore();
1020
+ });
1021
+
1022
+ let response = {
1023
+ 'version': '3.0.0',
1024
+ 'tags': [
1025
+ {
1026
+ 'uuid': '3db3773286ee59',
1027
+ 'tag_id': 10433394,
1028
+ 'auction_id': '4534722592064951574',
1029
+ 'nobid': false,
1030
+ 'no_ad_url': 'https://lax1-ib.adnxs.com/no-ad',
1031
+ 'timeout_ms': 10000,
1032
+ 'ad_profile_id': 27079,
1033
+ 'ads': [
1034
+ {
1035
+ 'content_source': 'rtb',
1036
+ 'ad_type': 'banner',
1037
+ 'buyer_member_id': 958,
1038
+ 'creative_id': 29681110,
1039
+ 'media_type_id': 1,
1040
+ 'media_subtype_id': 1,
1041
+ 'cpm': 0.5,
1042
+ 'cpm_publisher_currency': 0.5,
1043
+ 'publisher_currency_code': '$',
1044
+ 'client_initiated_ad_counting': true,
1045
+ 'viewability': {
1046
+ 'config': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
1047
+ },
1048
+ 'rtb': {
1049
+ 'banner': {
1050
+ 'content': '<!-- Creative -->',
1051
+ 'width': 300,
1052
+ 'height': 250
1053
+ },
1054
+ 'trackers': [
1055
+ {
1056
+ 'impression_urls': [
1057
+ 'https://lax1-ib.adnxs.com/impression'
1058
+ ],
1059
+ 'video_events': {}
1060
+ }
1061
+ ]
1062
+ }
1063
+ }
1064
+ ]
1065
+ }
1066
+ ]
1067
+ };
1068
+
1069
+ it('should get correct bid response', function () {
1070
+ let expectedResponse = [
1071
+ {
1072
+ 'requestId': '3db3773286ee59',
1073
+ 'cpm': 0.5,
1074
+ 'creativeId': 29681110,
1075
+ 'dealId': undefined,
1076
+ 'width': 300,
1077
+ 'height': 250,
1078
+ 'ad': '<!-- Creative -->',
1079
+ 'mediaType': 'banner',
1080
+ 'currency': 'USD',
1081
+ 'ttl': 300,
1082
+ 'netRevenue': true,
1083
+ 'adUnitCode': 'code',
1084
+ 'appnexus': {
1085
+ 'buyerMemberId': 958
1086
+ }
1087
+ }
1088
+ ];
1089
+ let bidderRequest = {
1090
+ bids: [{
1091
+ bidId: '3db3773286ee59',
1092
+ adUnitCode: 'code'
1093
+ }]
1094
+ }
1095
+ let result = spec.interpretResponse({ body: response }, {bidderRequest});
1096
+ expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
1097
+ });
1098
+
1099
+ it('handles nobid responses', function () {
1100
+ let response = {
1101
+ 'version': '0.0.1',
1102
+ 'tags': [{
1103
+ 'uuid': '84ab500420319d',
1104
+ 'tag_id': 5976557,
1105
+ 'auction_id': '297492697822162468',
1106
+ 'nobid': true
1107
+ }]
1108
+ };
1109
+ let bidderRequest;
1110
+
1111
+ let result = spec.interpretResponse({ body: response }, {bidderRequest});
1112
+ expect(result.length).to.equal(0);
1113
+ });
1114
+
1115
+ it('handles outstream video responses', function () {
1116
+ let response = {
1117
+ 'tags': [{
1118
+ 'uuid': '84ab500420319d',
1119
+ 'ads': [{
1120
+ 'ad_type': 'video',
1121
+ 'cpm': 0.500000,
1122
+ 'notify_url': 'imptracker.com',
1123
+ 'rtb': {
1124
+ 'video': {
1125
+ 'content': '<!-- VAST Creative -->'
1126
+ }
1127
+ },
1128
+ 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
1129
+ }]
1130
+ }]
1131
+ };
1132
+ let bidderRequest = {
1133
+ bids: [{
1134
+ bidId: '84ab500420319d',
1135
+ adUnitCode: 'code',
1136
+ mediaTypes: {
1137
+ video: {
1138
+ context: 'outstream'
1139
+ }
1140
+ }
1141
+ }]
1142
+ }
1143
+
1144
+ let result = spec.interpretResponse({ body: response }, {bidderRequest});
1145
+ expect(result[0]).to.have.property('vastXml');
1146
+ expect(result[0]).to.have.property('vastImpUrl');
1147
+ expect(result[0]).to.have.property('mediaType', 'video');
1148
+ });
1149
+
1150
+ it('handles instream video responses', function () {
1151
+ let response = {
1152
+ 'tags': [{
1153
+ 'uuid': '84ab500420319d',
1154
+ 'ads': [{
1155
+ 'ad_type': 'video',
1156
+ 'cpm': 0.500000,
1157
+ 'notify_url': 'imptracker.com',
1158
+ 'rtb': {
1159
+ 'video': {
1160
+ 'asset_url': 'https://sample.vastURL.com/here/vid'
1161
+ }
1162
+ },
1163
+ 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
1164
+ }]
1165
+ }]
1166
+ };
1167
+ let bidderRequest = {
1168
+ bids: [{
1169
+ bidId: '84ab500420319d',
1170
+ adUnitCode: 'code',
1171
+ mediaTypes: {
1172
+ video: {
1173
+ context: 'instream'
1174
+ }
1175
+ }
1176
+ }]
1177
+ }
1178
+
1179
+ let result = spec.interpretResponse({ body: response }, {bidderRequest});
1180
+ expect(result[0]).to.have.property('vastUrl');
1181
+ expect(result[0]).to.have.property('vastImpUrl');
1182
+ expect(result[0]).to.have.property('mediaType', 'video');
1183
+ });
1184
+
1185
+ it('handles adpod responses', function () {
1186
+ let response = {
1187
+ 'tags': [{
1188
+ 'uuid': '84ab500420319d',
1189
+ 'ads': [{
1190
+ 'ad_type': 'video',
1191
+ 'brand_category_id': 10,
1192
+ 'cpm': 0.500000,
1193
+ 'notify_url': 'imptracker.com',
1194
+ 'rtb': {
1195
+ 'video': {
1196
+ 'asset_url': 'https://sample.vastURL.com/here/adpod',
1197
+ 'duration_ms': 30000,
1198
+ }
1199
+ },
1200
+ 'viewability': {
1201
+ 'config': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
1202
+ }
1203
+ }]
1204
+ }]
1205
+ };
1206
+
1207
+ let bidderRequest = {
1208
+ bids: [{
1209
+ bidId: '84ab500420319d',
1210
+ adUnitCode: 'code',
1211
+ mediaTypes: {
1212
+ video: {
1213
+ context: 'adpod'
1214
+ }
1215
+ }
1216
+ }]
1217
+ };
1218
+ bfStub.returns('1');
1219
+
1220
+ let result = spec.interpretResponse({ body: response }, {bidderRequest});
1221
+ expect(result[0]).to.have.property('vastUrl');
1222
+ expect(result[0].video.context).to.equal('adpod');
1223
+ expect(result[0].video.durationSeconds).to.equal(30);
1224
+ });
1225
+
1226
+ it('handles native responses', function () {
1227
+ let response1 = deepClone(response);
1228
+ response1.tags[0].ads[0].ad_type = 'native';
1229
+ response1.tags[0].ads[0].rtb.native = {
1230
+ 'title': 'Native Creative',
1231
+ 'desc': 'Cool description great stuff',
1232
+ 'desc2': 'Additional body text',
1233
+ 'ctatext': 'Do it',
1234
+ 'sponsored': 'AppNexus',
1235
+ 'icon': {
1236
+ 'width': 0,
1237
+ 'height': 0,
1238
+ 'url': 'https://cdn.adnxs.com/icon.png'
1239
+ },
1240
+ 'main_img': {
1241
+ 'width': 2352,
1242
+ 'height': 1516,
1243
+ 'url': 'https://cdn.adnxs.com/img.png'
1244
+ },
1245
+ 'link': {
1246
+ 'url': 'https://www.appnexus.com',
1247
+ 'fallback_url': '',
1248
+ 'click_trackers': ['https://nym1-ib.adnxs.com/click']
1249
+ },
1250
+ 'impression_trackers': ['https://example.com'],
1251
+ 'rating': '5',
1252
+ 'displayurl': 'https://AppNexus.com/?url=display_url',
1253
+ 'likes': '38908320',
1254
+ 'downloads': '874983',
1255
+ 'price': '9.99',
1256
+ 'saleprice': 'FREE',
1257
+ 'phone': '1234567890',
1258
+ 'address': '28 W 23rd St, New York, NY 10010',
1259
+ 'privacy_link': 'https://appnexus.com/?url=privacy_url',
1260
+ 'javascriptTrackers': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=;css_selector=.pb-click;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
1261
+ };
1262
+ let bidderRequest = {
1263
+ bids: [{
1264
+ bidId: '3db3773286ee59',
1265
+ adUnitCode: 'code'
1266
+ }]
1267
+ }
1268
+
1269
+ let result = spec.interpretResponse({ body: response1 }, {bidderRequest});
1270
+ expect(result[0].native.title).to.equal('Native Creative');
1271
+ expect(result[0].native.body).to.equal('Cool description great stuff');
1272
+ expect(result[0].native.cta).to.equal('Do it');
1273
+ expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png');
1274
+ });
1275
+
1276
+ it('supports configuring outstream renderers', function () {
1277
+ const outstreamResponse = deepClone(response);
1278
+ outstreamResponse.tags[0].ads[0].rtb.video = {};
1279
+ outstreamResponse.tags[0].ads[0].renderer_url = 'renderer.js';
1280
+
1281
+ const bidderRequest = {
1282
+ bids: [{
1283
+ bidId: '3db3773286ee59',
1284
+ renderer: {
1285
+ options: {
1286
+ adText: 'configured'
1287
+ }
1288
+ },
1289
+ mediaTypes: {
1290
+ video: {
1291
+ context: 'outstream'
1292
+ }
1293
+ }
1294
+ }]
1295
+ };
1296
+
1297
+ const result = spec.interpretResponse({ body: outstreamResponse }, {bidderRequest});
1298
+ expect(result[0].renderer.config).to.deep.equal(
1299
+ bidderRequest.bids[0].renderer.options
1300
+ );
1301
+ });
1302
+
1303
+ it('should add deal_priority and deal_code', function() {
1304
+ let responseWithDeal = deepClone(response);
1305
+ responseWithDeal.tags[0].ads[0].ad_type = 'video';
1306
+ responseWithDeal.tags[0].ads[0].deal_priority = 5;
1307
+ responseWithDeal.tags[0].ads[0].deal_code = '123';
1308
+ responseWithDeal.tags[0].ads[0].rtb.video = {
1309
+ duration_ms: 1500,
1310
+ player_width: 640,
1311
+ player_height: 340,
1312
+ };
1313
+
1314
+ let bidderRequest = {
1315
+ bids: [{
1316
+ bidId: '3db3773286ee59',
1317
+ adUnitCode: 'code',
1318
+ mediaTypes: {
1319
+ video: {
1320
+ context: 'adpod'
1321
+ }
1322
+ }
1323
+ }]
1324
+ }
1325
+ let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest});
1326
+ expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']);
1327
+ expect(result[0].video.dealTier).to.equal(5);
1328
+ });
1329
+
1330
+ it('should add advertiser id', function() {
1331
+ let responseAdvertiserId = deepClone(response);
1332
+ responseAdvertiserId.tags[0].ads[0].advertiser_id = '123';
1333
+
1334
+ let bidderRequest = {
1335
+ bids: [{
1336
+ bidId: '3db3773286ee59',
1337
+ adUnitCode: 'code'
1338
+ }]
1339
+ }
1340
+ let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest});
1341
+ expect(Object.keys(result[0].meta)).to.include.members(['advertiserId']);
1342
+ });
1343
+
1344
+ it('should add advertiserDomains', function() {
1345
+ let responseAdvertiserId = deepClone(response);
1346
+ responseAdvertiserId.tags[0].ads[0].adomain = ['123'];
1347
+
1348
+ let bidderRequest = {
1349
+ bids: [{
1350
+ bidId: '3db3773286ee59',
1351
+ adUnitCode: 'code'
1352
+ }]
1353
+ }
1354
+ let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest});
1355
+ expect(Object.keys(result[0].meta)).to.include.members(['advertiserDomains']);
1356
+ expect(Object.keys(result[0].meta.advertiserDomains)).to.deep.equal([]);
1357
+ });
1358
+ });
1359
+ });