• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / 16326535370

16 Jul 2025 05:46PM UTC coverage: 96.261% (+0.002%) from 96.259%
16326535370

push

github

web-flow
Yandex bid adapter: added lurl support (#13619)

* Yandex bid adapter: added lurl support

* Yandex bid adapter: added lurl support

* Yandex bid adapter: added lurl support

* rumbleBidAdapter_spec.js linter fix

39345 of 48348 branches covered (81.38%)

11 of 11 new or added lines in 3 files covered. (100.0%)

3 existing lines in 3 files now uncovered.

194193 of 201735 relevant lines covered (96.26%)

83.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.21
/test/spec/modules/teadsBidAdapter_spec.js
1
import { expect } from 'chai';
2
import * as autoplay from 'libraries/autoplayDetection/autoplay.js';
3
import { spec, storage } from 'modules/teadsBidAdapter.js';
4
import { newBidder } from 'src/adapters/bidderFactory.js';
5

6
const ENDPOINT = 'https://a.teads.tv/hb/bid-request';
1✔
7
const AD_SCRIPT = '<script type="text/javascript" class="teads" async="true" src="https://a.teads.tv/hb/getAdSettings"></script>"';
1✔
8

9
describe('teadsBidAdapter', () => {
1✔
10
  const adapter = newBidder(spec);
1✔
11
  let sandbox;
12

13
  beforeEach(function () {
1✔
14
    sandbox = sinon.createSandbox();
72✔
15
  });
16

17
  afterEach(function () {
1✔
18
    sandbox.restore();
72✔
19
  });
20

21
  describe('inherited functions', () => {
1✔
22
    it('exists and is a function', () => {
1✔
23
      expect(adapter.callBids).to.exist.and.to.be.a('function');
1✔
24
    });
25
  });
26

27
  describe('isBidRequestValid', function() {
1✔
28
    const bid = {
1✔
29
      'bidder': 'teads',
30
      'params': {
31
        'placementId': 10433394,
32
        'pageId': 1234
33
      },
34
      'adUnitCode': 'adunit-code',
35
      'sizes': [[300, 250], [300, 600]],
36
      'bidId': '30b31c1838de1e',
37
      'bidderRequestId': '22edbae2733bf6',
38
      'auctionId': '1d1a030790a475',
39
      'creativeId': 'er2ee'
40
    };
41

42
    it('should return true when required params found', function() {
1✔
43
      expect(spec.isBidRequestValid(bid)).to.equal(true);
1✔
44
    });
45

46
    it('should return false when pageId is not valid (letters)', function() {
1✔
47
      const invalidBid = Object.assign({}, bid);
1✔
48
      delete invalidBid.params;
1✔
49
      invalidBid.params = {
1✔
50
        'placementId': 1234,
51
        'pageId': 'ABCD'
52
      };
53

54
      expect(spec.isBidRequestValid(invalidBid)).to.equal(false);
1✔
55
    });
56

57
    it('should return false when placementId is not valid (letters)', function() {
1✔
58
      const invalidBid = Object.assign({}, bid);
1✔
59
      delete invalidBid.params;
1✔
60
      invalidBid.params = {
1✔
61
        'placementId': 'FCP',
62
        'pageId': 1234
63
      };
64

65
      expect(spec.isBidRequestValid(invalidBid)).to.equal(false);
1✔
66
    });
67

68
    it('should return false when placementId < 0 or pageId < 0', function() {
1✔
69
      const invalidBid = Object.assign({}, bid);
1✔
70
      delete invalidBid.params;
1✔
71
      invalidBid.params = {
1✔
72
        'placementId': -1,
73
        'pageId': -1
74
      };
75

76
      expect(spec.isBidRequestValid(invalidBid)).to.equal(false);
1✔
77
    });
78

79
    it('should return false when required params are not passed', function() {
1✔
80
      const invalidBid = Object.assign({}, bid);
1✔
81
      delete invalidBid.params;
1✔
82

83
      invalidBid.params = {
1✔
84
        'placementId': 0
85
      };
86

87
      expect(spec.isBidRequestValid(invalidBid)).to.equal(false);
1✔
88
    });
89
  });
90

91
  describe('buildRequests', function() {
1✔
92
    const bidRequests = [
1✔
93
      {
94
        'bidder': 'teads',
95
        'params': {
96
          'placementId': 10433394,
97
          'pageId': 1234
98
        },
99
        'adUnitCode': 'adunit-code',
100
        'sizes': [[300, 250], [300, 600]],
101
        'bidId': '30b31c1838de1e',
102
        'bidderRequestId': '22edbae2733bf6',
103
        'auctionId': '1d1a030790a475',
104
        'creativeId': 'er2ee',
105
        'deviceWidth': 1680
106
      }
107
    ];
108

109
    const bidderRequestDefault = {
1✔
110
      'auctionId': '1d1a030790a475',
111
      'bidderRequestId': '22edbae2733bf6',
112
      'timeout': 3000
113
    };
114

115
    it('should send bid request to ENDPOINT via POST', function() {
1✔
116
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
117

118
      expect(request.url).to.equal(ENDPOINT);
1✔
119
      expect(request.method).to.equal('POST');
1✔
120
    });
121

122
    it('should not send auctionId in bid request ', function() {
1✔
123
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
124
      const payload = JSON.parse(request.data);
1✔
125

126
      expect(payload.data[0].auctionId).to.not.exist
1✔
127
    });
128

129
    it('should send US Privacy to endpoint', function() {
1✔
130
      const usPrivacy = 'OHHHFCP1'
1✔
131
      const bidderRequest = {
1✔
132
        'auctionId': '1d1a030790a475',
133
        'bidderRequestId': '22edbae2733bf6',
134
        'timeout': 3000,
135
        'uspConsent': usPrivacy
136
      };
137

138
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
139
      const payload = JSON.parse(request.data);
1✔
140

141
      expect(payload.us_privacy).to.exist;
1✔
142
      expect(payload.us_privacy).to.equal(usPrivacy);
1✔
143
    });
144

145
    it('should send GPP values to endpoint when available and valid', function () {
1✔
146
      const consentString = 'DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN';
1✔
147
      const applicableSectionIds = [7, 8];
1✔
148
      const bidderRequest = {
1✔
149
        'auctionId': '1d1a030790a475',
150
        'bidderRequestId': '22edbae2733bf6',
151
        'timeout': 3000,
152
        'gppConsent': {
153
          'gppString': consentString,
154
          'applicableSections': applicableSectionIds
155
        }
156
      };
157

158
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
159
      const payload = JSON.parse(request.data);
1✔
160

161
      expect(payload.gpp).to.exist;
1✔
162
      expect(payload.gpp.consentString).to.equal(consentString);
1✔
163
      expect(payload.gpp.applicableSectionIds).to.have.members(applicableSectionIds);
1✔
164
    });
165

166
    it('should send default GPP values to endpoint when available but invalid', function () {
1✔
167
      const bidderRequest = {
1✔
168
        'auctionId': '1d1a030790a475',
169
        'bidderRequestId': '22edbae2733bf6',
170
        'timeout': 3000,
171
        'gppConsent': {
172
          'gppString': undefined,
173
          'applicableSections': ['a']
174
        }
175
      };
176

177
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
178
      const payload = JSON.parse(request.data);
1✔
179

180
      expect(payload.gpp).to.exist;
1✔
181
      expect(payload.gpp.consentString).to.equal('');
1✔
182
      expect(payload.gpp.applicableSectionIds).to.have.members([]);
1✔
183
    });
184

185
    it('should not set the GPP object in the request sent to the endpoint when not present', function () {
1✔
186
      const bidderRequest = {
1✔
187
        'auctionId': '1d1a030790a475',
188
        'bidderRequestId': '22edbae2733bf6',
189
        'timeout': 3000
190
      };
191

192
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
193
      const payload = JSON.parse(request.data);
1✔
194

195
      expect(payload.gpp).to.not.exist;
1✔
196
    });
197

198
    it('should send GDPR to endpoint', function() {
1✔
199
      const consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A==';
1✔
200
      const bidderRequest = {
1✔
201
        'auctionId': '1d1a030790a475',
202
        'bidderRequestId': '22edbae2733bf6',
203
        'timeout': 3000,
204
        'gdprConsent': {
205
          'consentString': consentString,
206
          'gdprApplies': true,
207
          'vendorData': {
208
            'isServiceSpecific': true
209
          },
210
          'apiVersion': 2
211
        }
212
      };
213

214
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
215
      const payload = JSON.parse(request.data);
1✔
216

217
      expect(payload.gdpr_iab).to.exist;
1✔
218
      expect(payload.gdpr_iab.consent).to.equal(consentString);
1✔
219
      expect(payload.gdpr_iab.status).to.equal(12);
1✔
220
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
221
    });
222

223
    it('should add videoPlcmt to payload', function () {
1✔
224
      const bidRequestWithVideoPlcmt = Object.assign({}, bidRequests[0], {
1✔
225
        mediaTypes: {
226
          video: {
227
            plcmt: 1
228
          }
229
        }
230
      });
231

232
      const request = spec.buildRequests([bidRequestWithVideoPlcmt], bidderRequestDefault);
1✔
233
      const payload = JSON.parse(request.data);
1✔
234

235
      expect(payload.data[0].videoPlcmt).to.exist;
1✔
236
      expect(payload.data[0].videoPlcmt).to.equal(1);
1✔
237
    });
238

239
    it('should not add videoPlcmt to payload if empty', function () {
1✔
240
      const bidRequestWithNullVideoPlcmt = Object.assign({}, bidRequests[0], {
1✔
241
        mediaTypes: {
242
          video: {
243
            plcmt: null
244
          }
245
        }
246
      });
247

248
      const bidRequestWithEmptyVideoPlcmt = Object.assign({}, bidRequests[0], {
1✔
249
        mediaTypes: {
250
          video: {
251
            plcmt: ''
252
          }
253
        }
254
      });
255

256
      const request1 = spec.buildRequests([bidRequestWithNullVideoPlcmt], bidderRequestDefault);
1✔
257
      const request2 = spec.buildRequests([bidRequestWithEmptyVideoPlcmt], bidderRequestDefault);
1✔
258
      const payload1 = JSON.parse(request1.data);
1✔
259
      const payload2 = JSON.parse(request2.data);
1✔
260

261
      expect(payload1.data[0].videoPlcmt).to.not.exist;
1✔
262
      expect(payload2.data[0].videoPlcmt).to.not.exist;
1✔
263
    });
264

265
    it('should not add videoPlcmt to payload if it is not in bid request', function () {
1✔
266
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
267
      const payload = JSON.parse(request.data);
1✔
268

269
      expect(payload.data[0].videoPlcmt).to.not.exist;
1✔
270
    });
271

272
    it('should add referer info to payload', function () {
1✔
273
      const bidRequest = Object.assign({}, bidRequests[0])
1✔
274
      const bidderRequest = {
1✔
275
        refererInfo: {
276
          page: 'https://example.com/page.html',
277
          reachedTop: true,
278
          numIframes: 2
279
        }
280
      }
281
      const request = spec.buildRequests([bidRequest], bidderRequest);
1✔
282
      const payload = JSON.parse(request.data);
1✔
283

284
      expect(payload.referrer).to.exist;
1✔
285
      expect(payload.referrer).to.deep.equal('https://example.com/page.html')
1✔
286
    });
287

288
    it('should add networkBandwidth info to payload', function () {
1✔
289
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
290
      const payload = JSON.parse(request.data);
1✔
291

292
      const bandwidth = window.navigator && window.navigator.connection && window.navigator.connection.downlink;
1!
293

294
      expect(payload.networkBandwidth).to.exist;
1✔
295

296
      if (bandwidth) {
1!
297
        expect(payload.networkBandwidth).to.deep.equal(bandwidth.toString());
×
298
      } else {
299
        expect(payload.networkBandwidth).to.deep.equal('');
1✔
300
      }
301
    });
302

303
    it('should add networkQuality info to payload', function () {
1✔
304
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
305
      const payload = JSON.parse(request.data);
1✔
306

307
      const networkQuality = window.navigator && window.navigator.connection && window.navigator.connection.effectiveType;
1!
308

309
      expect(payload.networkQuality).to.exist;
1✔
310

311
      if (networkQuality) {
1!
312
        expect(payload.networkQuality).to.deep.equal(networkQuality.toString());
×
313
      } else {
314
        expect(payload.networkQuality).to.deep.equal('');
1✔
315
      }
316
    })
317

318
    it('should add domComplexity info to payload', function () {
1✔
319
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
320
      const payload = JSON.parse(request.data);
1✔
321

322
      const domComplexity = document?.querySelectorAll('*')?.length;
1✔
323

324
      expect(payload.domComplexity).to.exist;
1✔
325

326
      if (domComplexity) {
1!
327
        expect(payload.domComplexity).to.deep.equal(domComplexity);
1✔
328
      } else {
329
        expect(payload.domComplexity).to.deep.equal(-1);
×
330
      }
331
    })
332

333
    it('should add pageReferrer info to payload', function () {
1✔
334
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
335
      const payload = JSON.parse(request.data);
1✔
336

337
      expect(payload.pageReferrer).to.exist;
1✔
338
      expect(payload.pageReferrer).to.deep.equal(document.referrer);
1✔
339
    });
340

341
    it('should add width info to payload', function () {
1✔
342
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
343
      const payload = JSON.parse(request.data);
1✔
344
      const deviceWidth = screen.width
1✔
345

346
      expect(payload.deviceWidth).to.exist;
1✔
347
      expect(payload.deviceWidth).to.deep.equal(deviceWidth);
1✔
348
    });
349

350
    it('should add height info to payload', function () {
1✔
351
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
352
      const payload = JSON.parse(request.data);
1✔
353
      const deviceHeight = screen.height
1✔
354

355
      expect(payload.deviceHeight).to.exist;
1✔
356
      expect(payload.deviceHeight).to.deep.equal(deviceHeight);
1✔
357
    });
358

359
    it('should add pixelRatio info to payload', function () {
1✔
360
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
361
      const payload = JSON.parse(request.data);
1✔
362
      const pixelRatio = window.top.devicePixelRatio
1✔
363

364
      expect(payload.devicePixelRatio).to.exist;
1✔
365
      expect(payload.devicePixelRatio).to.deep.equal(pixelRatio);
1✔
366
    });
367

368
    it('should add screenOrientation info to payload', function () {
1✔
369
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
370
      const payload = JSON.parse(request.data);
1✔
371
      const screenOrientation = window.top.screen.orientation?.type
1✔
372

373
      if (screenOrientation) {
1!
374
        expect(payload.screenOrientation).to.exist;
×
375
        expect(payload.screenOrientation).to.deep.equal(screenOrientation);
×
376
      } else expect(payload.screenOrientation).to.not.exist;
1✔
377
    });
378

379
    it('should add historyLength info to payload', function () {
1✔
380
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
381
      const payload = JSON.parse(request.data);
1✔
382

383
      expect(payload.historyLength).to.exist;
1✔
384
      expect(payload.historyLength).to.deep.equal(window.top.history.length);
1✔
385
    });
386

387
    it('should add viewportHeight info to payload', function () {
1✔
388
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
389
      const payload = JSON.parse(request.data);
1✔
390

391
      expect(payload.viewportHeight).to.exist;
1✔
392
      expect(payload.viewportHeight).to.deep.equal(window.top.visualViewport.height);
1✔
393
    });
394

395
    it('should add viewportWidth info to payload', function () {
1✔
396
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
397
      const payload = JSON.parse(request.data);
1✔
398

399
      expect(payload.viewportWidth).to.exist;
1✔
400
      expect(payload.viewportWidth).to.deep.equal(window.top.visualViewport.width);
1✔
401
    });
402

403
    it('should add viewportHeight info to payload', function () {
1✔
404
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
405
      const payload = JSON.parse(request.data);
1✔
406

407
      expect(payload.viewportHeight).to.exist;
1✔
408
      expect(payload.viewportHeight).to.deep.equal(window.top.visualViewport.height);
1✔
409
    });
410

411
    it('should add ortb2 device data to payload', function () {
1✔
412
      const ortb2DeviceBidderRequest = {
1✔
413
        ...bidderRequestDefault,
414
        ...{
415
          ortb2: {
416
            device: {
417
              w: 980,
418
              h: 1720,
419
              dnt: 0,
420
              ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/125.0.6422.80 Mobile/15E148 Safari/604.1',
421
              language: 'en',
422
              devicetype: 1,
423
              make: 'Apple',
424
              model: 'iPhone 12 Pro Max',
425
              os: 'iOS',
426
              osv: '17.4',
427
              ext: {fiftyonedegrees_deviceId: '17595-133085-133468-18092'},
428
            },
429
          },
430
        },
431
      };
432
      const request = spec.buildRequests(bidRequests, ortb2DeviceBidderRequest);
1✔
433
      const payload = JSON.parse(request.data);
1✔
434

435
      expect(payload.device).to.deep.equal(ortb2DeviceBidderRequest.ortb2.device);
1✔
436
    });
437

438
    it('should add hardwareConcurrency info to payload', function () {
1✔
439
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
440
      const payload = JSON.parse(request.data);
1✔
441
      const hardwareConcurrency = window.top.navigator?.hardwareConcurrency
1✔
442

443
      if (hardwareConcurrency) {
1!
444
        expect(payload.hardwareConcurrency).to.exist;
1✔
445
        expect(payload.hardwareConcurrency).to.deep.equal(hardwareConcurrency);
1✔
446
      } else expect(payload.hardwareConcurrency).to.not.exist
×
447
    });
448

449
    it('should add deviceMemory info to payload', function () {
1✔
450
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
451
      const payload = JSON.parse(request.data);
1✔
452
      const deviceMemory = window.top.navigator.deviceMemory
1✔
453

454
      if (deviceMemory) {
1!
455
        expect(payload.deviceMemory).to.exist;
×
456
        expect(payload.deviceMemory).to.deep.equal(deviceMemory);
×
457
      } else expect(payload.deviceMemory).to.not.exist;
1✔
458
    });
459

460
    describe('pageTitle', function () {
1✔
461
      it('should add pageTitle info to payload based on document title', function () {
1✔
462
        const testText = 'This is a title';
1✔
463
        sandbox.stub(window.top.document, 'title').value(testText);
1✔
464

465
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
466
        const payload = JSON.parse(request.data);
1✔
467

468
        expect(payload.pageTitle).to.exist;
1✔
469
        expect(payload.pageTitle).to.deep.equal(testText);
1✔
470
      });
471

472
      it('should add pageTitle info to payload based on open-graph title', function () {
1✔
473
        const testText = 'This is a title from open-graph';
1✔
474
        sandbox.stub(window.top.document, 'title').value('');
1✔
475
        sandbox.stub(window.top.document, 'querySelector').withArgs('meta[property="og:title"]').returns({ content: testText });
1✔
476

477
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
478
        const payload = JSON.parse(request.data);
1✔
479

480
        expect(payload.pageTitle).to.exist;
1✔
481
        expect(payload.pageTitle).to.deep.equal(testText);
1✔
482
      });
483

484
      it('should add pageTitle info to payload sliced on 300 first characters', function () {
1✔
485
        const testText = Array(500).join('a');
1✔
486
        sandbox.stub(window.top.document, 'title').value(testText);
1✔
487

488
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
489
        const payload = JSON.parse(request.data);
1✔
490

491
        expect(payload.pageTitle).to.exist;
1✔
492
        expect(payload.pageTitle).to.have.length(300);
1✔
493
      });
494

495
      it('should add pageTitle info to payload when fallbacking from window.top', function () {
1✔
496
        const testText = 'This is a fallback title';
1✔
497
        sandbox.stub(window.top.document, 'querySelector').throws();
1✔
498
        sandbox.stub(document, 'title').value(testText);
1✔
499

500
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
501
        const payload = JSON.parse(request.data);
1✔
502

503
        expect(payload.pageTitle).to.exist;
1✔
504
        expect(payload.pageTitle).to.deep.equal(testText);
1✔
505
      });
506
    });
507

508
    describe('pageDescription', function () {
1✔
509
      it('should add pageDescription info to payload based on open-graph description', function () {
1✔
510
        const testText = 'This is a description';
1✔
511
        sandbox.stub(window.top.document, 'querySelector').withArgs('meta[name="description"]').returns({ content: testText });
1✔
512

513
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
514
        const payload = JSON.parse(request.data);
1✔
515

516
        expect(payload.pageDescription).to.exist;
1✔
517
        expect(payload.pageDescription).to.deep.equal(testText);
1✔
518
      });
519

520
      it('should add pageDescription info to payload based on open-graph description', function () {
1✔
521
        const testText = 'This is a description from open-graph';
1✔
522
        sandbox.stub(window.top.document, 'querySelector').withArgs('meta[property="og:description"]').returns({ content: testText });
1✔
523

524
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
525
        const payload = JSON.parse(request.data);
1✔
526

527
        expect(payload.pageDescription).to.exist;
1✔
528
        expect(payload.pageDescription).to.deep.equal(testText);
1✔
529
      });
530

531
      it('should add pageDescription info to payload sliced on 300 first characters', function () {
1✔
532
        const testText = Array(500).join('a');
1✔
533
        sandbox.stub(window.top.document, 'querySelector').withArgs('meta[name="description"]').returns({ content: testText });
1✔
534

535
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
536
        const payload = JSON.parse(request.data);
1✔
537

538
        expect(payload.pageDescription).to.exist;
1✔
539
        expect(payload.pageDescription).to.have.length(300);
1✔
540
      });
541

542
      it('should add pageDescription info to payload when fallbacking from window.top', function () {
1✔
543
        const testText = 'This is a fallback description';
1✔
544
        sandbox.stub(window.top.document, 'querySelector').throws();
1✔
545
        sandbox.stub(document, 'querySelector').withArgs('meta[name="description"]').returns({ content: testText });
1✔
546

547
        const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
548
        const payload = JSON.parse(request.data);
1✔
549

550
        expect(payload.pageDescription).to.exist;
1✔
551
        expect(payload.pageDescription).to.deep.equal(testText);
1✔
552
      });
553
    });
554

555
    it('should add timeToFirstByte info to payload', function () {
1✔
556
      const request = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
557
      const payload = JSON.parse(request.data);
1✔
558
      const performance = window.performance || window.webkitPerformance || window.msPerformance || window.mozPerformance;
1!
559

560
      const ttfbExpectedV2 = performance &&
1!
561
        typeof performance.getEntriesByType === 'function' &&
562
        Object.prototype.toString.call(performance.getEntriesByType) === '[object Function]' &&
563
        performance.getEntriesByType('navigation')[0] &&
564
        performance.getEntriesByType('navigation')[0].responseStart &&
565
        performance.getEntriesByType('navigation')[0].requestStart &&
566
        performance.getEntriesByType('navigation')[0].responseStart > 0 &&
567
        performance.getEntriesByType('navigation')[0].requestStart > 0 &&
568
        Math.round(
569
          performance.getEntriesByType('navigation')[0].responseStart - performance.getEntriesByType('navigation')[0].requestStart
570
        );
571

572
      expect(payload.timeToFirstByte).to.exist;
1✔
573

574
      if (ttfbExpectedV2) {
1!
UNCOV
575
        expect(payload.timeToFirstByte).to.deep.equal(ttfbExpectedV2.toString());
×
576
      } else {
577
        const ttfbWithTimingV1 = performance &&
1✔
578
            performance.timing.responseStart &&
579
            performance.timing.requestStart &&
580
            performance.timing.responseStart > 0 &&
581
            performance.timing.requestStart > 0 &&
582
            performance.timing.responseStart - performance.timing.requestStart;
583
        const ttfbExpectedV1 = ttfbWithTimingV1 ? ttfbWithTimingV1.toString() : '';
1!
584

585
        expect(payload.timeToFirstByte).to.deep.equal(ttfbExpectedV1);
1✔
586
      }
587
    });
588

589
    it('should send GDPR to endpoint with 11 status', function() {
1✔
590
      const consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A==';
1✔
591
      const bidderRequest = {
1✔
592
        'auctionId': '1d1a030790a475',
593
        'bidderRequestId': '22edbae2733bf6',
594
        'timeout': 3000,
595
        'gdprConsent': {
596
          'consentString': consentString,
597
          'gdprApplies': true,
598
          'vendorData': {
599
            'isServiceSpecific': false,
600
          },
601
          'apiVersion': 2
602
        }
603
      };
604

605
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
606
      const payload = JSON.parse(request.data);
1✔
607

608
      expect(payload.gdpr_iab).to.exist;
1✔
609
      expect(payload.gdpr_iab.consent).to.equal(consentString);
1✔
610
      expect(payload.gdpr_iab.status).to.equal(11);
1✔
611
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
612
    });
613

614
    it('should send GDPR TCF2 to endpoint with 12 status', function() {
1✔
615
      const consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A==';
1✔
616
      const bidderRequest = {
1✔
617
        'auctionId': '1d1a030790a475',
618
        'bidderRequestId': '22edbae2733bf6',
619
        'timeout': 3000,
620
        'gdprConsent': {
621
          'consentString': consentString,
622
          'gdprApplies': true,
623
          'vendorData': {
624
            'isServiceSpecific': true
625
          },
626
          'apiVersion': 2
627
        }
628
      };
629

630
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
631
      const payload = JSON.parse(request.data);
1✔
632

633
      expect(payload.gdpr_iab).to.exist;
1✔
634
      expect(payload.gdpr_iab.consent).to.equal(consentString);
1✔
635
      expect(payload.gdpr_iab.status).to.equal(12);
1✔
636
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
637
    });
638

639
    it('should send GDPR to endpoint with 22 status', function() {
1✔
640
      const bidderRequest = {
1✔
641
        'auctionId': '1d1a030790a475',
642
        'bidderRequestId': '22edbae2733bf6',
643
        'timeout': 3000,
644
        'gdprConsent': {
645
          'consentString': undefined,
646
          'gdprApplies': undefined,
647
          'vendorData': undefined,
648
          'apiVersion': 2
649
        }
650
      };
651

652
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
653
      const payload = JSON.parse(request.data);
1✔
654

655
      expect(payload.gdpr_iab).to.exist;
1✔
656
      expect(payload.gdpr_iab.consent).to.equal('');
1✔
657
      expect(payload.gdpr_iab.status).to.equal(22);
1✔
658
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
659
    });
660

661
    it('should send GDPR to endpoint with 0 status', function() {
1✔
662
      const consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A==';
1✔
663
      const bidderRequest = {
1✔
664
        'auctionId': '1d1a030790a475',
665
        'bidderRequestId': '22edbae2733bf6',
666
        'timeout': 3000,
667
        'gdprConsent': {
668
          'consentString': consentString,
669
          'gdprApplies': false,
670
          'vendorData': {
671
            'hasGlobalScope': false
672
          },
673
          'apiVersion': 2
674
        }
675
      };
676

677
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
678
      const payload = JSON.parse(request.data);
1✔
679

680
      expect(payload.gdpr_iab).to.exist;
1✔
681
      expect(payload.gdpr_iab.consent).to.equal(consentString);
1✔
682
      expect(payload.gdpr_iab.status).to.equal(0);
1✔
683
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
684
    });
685

686
    it('should send GDPR to endpoint with 0 status when gdprApplies = false (vendorData = undefined)', function() {
1✔
687
      const bidderRequest = {
1✔
688
        'auctionId': '1d1a030790a475',
689
        'bidderRequestId': '22edbae2733bf6',
690
        'timeout': 3000,
691
        'gdprConsent': {
692
          'consentString': undefined,
693
          'gdprApplies': false,
694
          'vendorData': undefined,
695
          'apiVersion': 2
696
        }
697
      };
698

699
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
700
      const payload = JSON.parse(request.data);
1✔
701

702
      expect(payload.gdpr_iab).to.exist;
1✔
703
      expect(payload.gdpr_iab.consent).to.equal('');
1✔
704
      expect(payload.gdpr_iab.status).to.equal(0);
1✔
705
      expect(payload.gdpr_iab.apiVersion).to.equal(2);
1✔
706
    });
707

708
    it('should send GDPR to endpoint with 12 status when apiVersion = 0', function() {
1✔
709
      const consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A==';
1✔
710
      const bidderRequest = {
1✔
711
        'auctionId': '1d1a030790a475',
712
        'bidderRequestId': '22edbae2733bf6',
713
        'timeout': 3000,
714
        'gdprConsent': {
715
          'consentString': consentString,
716
          'gdprApplies': true,
717
          'vendorData': {
718
            'isServiceSpecific': true
719
          },
720
          'apiVersion': 0
721
        }
722
      };
723

724
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
725
      const payload = JSON.parse(request.data);
1✔
726

727
      expect(payload.gdpr_iab).to.exist;
1✔
728
      expect(payload.gdpr_iab.consent).to.equal(consentString);
1✔
729
      expect(payload.gdpr_iab.status).to.equal(12);
1✔
730
      expect(payload.gdpr_iab.apiVersion).to.equal(0);
1✔
731
    });
732

733
    it('should use good mediaTypes video playerSizes', function() {
1✔
734
      const mediaTypesPlayerSize = {
1✔
735
        'mediaTypes': {
736
          'video': {
737
            'playerSize': [32, 34]
738
          }
739
        }
740
      };
741
      checkMediaTypesSizes(mediaTypesPlayerSize, '32x34');
1✔
742
    });
743

744
    it('should add schain info to payload if available', function () {
1✔
745
      const bidRequest = Object.assign({}, bidRequests[0], {
1✔
746
        ortb2: {
747
          source: {
748
            ext: {
749
              schain: {
750
                ver: '1.0',
751
                complete: 1,
752
                nodes: [{
753
                  asi: 'example.com',
754
                  sid: '00001',
755
                  hp: 1
756
                }]
757
              }
758
            }
759
          }
760
        }
761
      });
762

763
      const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
764
      const payload = JSON.parse(request.data);
1✔
765

766
      expect(payload.schain).to.exist;
1✔
767
      expect(payload.schain).to.deep.equal({
1✔
768
        ver: '1.0',
769
        complete: 1,
770
        nodes: [{
771
          asi: 'example.com',
772
          sid: '00001',
773
          hp: 1
774
        }]
775
      });
776
    });
777

778
    it('should add userAgentClientHints info to payload if available', function () {
1✔
779
      const bidRequest = Object.assign({}, bidRequests[0], {
1✔
780
        ortb2: {
781
          device: {
782
            sua: {
783
              source: 2,
784
              platform: {
785
                brand: 'macOS',
786
                version: [ '12', '4', '0' ]
787
              },
788
              browsers: [
789
                {
790
                  brand: 'Chromium',
791
                  version: [ '106', '0', '5249', '119' ]
792
                },
793
                {
794
                  brand: 'Google Chrome',
795
                  version: [ '106', '0', '5249', '119' ]
796
                },
797
                {
798
                  brand: 'Not;A=Brand',
799
                  version: [ '99', '0', '0', '0' ]
800
                }
801
              ],
802
              mobile: 0,
803
              model: '',
804
              bitness: '64',
805
              architecture: 'x86'
806
            }
807
          }
808
        }
809
      });
810

811
      const requestWithUserAgentClientHints = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
812
      const payload = JSON.parse(requestWithUserAgentClientHints.data);
1✔
813

814
      expect(payload.userAgentClientHints).to.exist;
1✔
815
      expect(payload.userAgentClientHints).to.deep.equal({
1✔
816
        source: 2,
817
        platform: {
818
          brand: 'macOS',
819
          version: [ '12', '4', '0' ]
820
        },
821
        browsers: [
822
          {
823
            brand: 'Chromium',
824
            version: [ '106', '0', '5249', '119' ]
825
          },
826
          {
827
            brand: 'Google Chrome',
828
            version: [ '106', '0', '5249', '119' ]
829
          },
830
          {
831
            brand: 'Not;A=Brand',
832
            version: [ '99', '0', '0', '0' ]
833
          }
834
        ],
835
        mobile: 0,
836
        model: '',
837
        bitness: '64',
838
        architecture: 'x86'
839
      }
840
      );
841

842
      const defaultRequest = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
843
      expect(JSON.parse(defaultRequest.data).userAgentClientHints).to.not.exist;
1✔
844
    });
845

846
    it('should use good mediaTypes video sizes', function() {
1✔
847
      const mediaTypesVideoSizes = {
1✔
848
        'mediaTypes': {
849
          'video': {
850
            'sizes': [12, 14]
851
          }
852
        }
853
      };
854
      checkMediaTypesSizes(mediaTypesVideoSizes, '12x14');
1✔
855
    });
856

857
    it('should use good mediaTypes banner sizes', function() {
1✔
858
      const mediaTypesBannerSize = {
1✔
859
        'mediaTypes': {
860
          'banner': {
861
            'sizes': [46, 48]
862
          }
863
        }
864
      };
865
      checkMediaTypesSizes(mediaTypesBannerSize, '46x48');
1✔
866
    });
867

868
    it('should use good mediaTypes for both video and banner sizes', function() {
1✔
869
      const hybridMediaTypes = {
1✔
870
        'mediaTypes': {
871
          'banner': {
872
            'sizes': [46, 48]
873
          },
874
          'video': {
875
            'sizes': [[50, 34], [45, 45]]
876
          }
877
        }
878
      };
879
      checkMediaTypesSizes(hybridMediaTypes, ['46x48', '50x34', '45x45']);
1✔
880
    });
881

882
    const toEid = (sourceId, value) => ({
18✔
883
      source: sourceId,
884
      uids: [{id: value}]
885
    })
886

887
    describe('User IDs', function () {
1✔
888
      const baseBidRequest = {
1✔
889
        'bidder': 'teads',
890
        'params': {
891
          'placementId': 10433394,
892
          'pageId': 1234
893
        },
894
        'adUnitCode': 'adunit-code',
895
        'sizes': [[300, 250], [300, 600]],
896
        'bidId': '30b31c1838de1e',
897
        'bidderRequestId': '22edbae2733bf6',
898
        'auctionId': '1d1a030790a475',
899
        'creativeId': 'er2ee',
900
        'deviceWidth': 1680
901
      };
902

903
      const userIdModules = {
1✔
904
        unifiedId2: toEid('uidapi.com', 'unifiedId2-id'),
905
        liveRampId: toEid('liveramp.com', 'liveRampId-id'),
906
        lotamePanoramaId: toEid('crwdcntrl.net', 'lotamePanoramaId-id'),
907
        id5Id: toEid('id5-sync.com', 'id5Id-id'),
908
        criteoId: toEid('criteo.com', 'criteoId-id'),
909
        yahooConnectId: toEid('yahoo.com', 'yahooConnectId-id'),
910
        quantcastId: toEid('quantcast.com', 'quantcastId-id'),
911
        epsilonPublisherLinkId: toEid('epsilon.com', 'epsilonPublisherLinkId-id'),
912
        publisherFirstPartyViewerId: toEid('pubcid.org', 'publisherFirstPartyViewerId-id'),
913
        merkleId: toEid('merkleinc.com', 'merkleId-id'),
914
        kinessoId: toEid('kpuid.com', 'kinessoId-id')
915
      };
916

917
      describe('User Id Modules', function () {
1✔
918
        it(`should not add param to payload if user id system is not enabled`, function () {
1✔
919
          const bidRequest = {
1✔
920
            ...baseBidRequest,
921
            userIdAsEids: [] // no property -> assumption that the system is disabled
922
          };
923

924
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
925
          const payload = JSON.parse(request.data);
1✔
926

927
          for (const userId in userIdModules) {
1✔
928
            expect(payload, userId).not.to.have.property(userId);
11✔
929
          }
930
          expect(payload['eids']).to.deep.equal([])
1✔
931
        });
932

933
        it(`should not add param to payload if user id field is absent`, function () {
1✔
934
          const request = spec.buildRequests([baseBidRequest], bidderRequestDefault);
1✔
935
          const payload = JSON.parse(request.data);
1✔
936

937
          for (const userId in userIdModules) {
1✔
938
            expect(payload, userId).not.to.have.property(userId);
11✔
939
          }
940
          expect(payload['eids']).to.deep.equal([])
1✔
941
        });
942

943
        it(`should not add param to payload if user id is enabled but there is no value`, function () {
1✔
944
          const userIdAsEids = [
1✔
945
            toEid('idl_env', ''),
946
            toEid('pubcid.org', 'publisherFirstPartyViewerId-id')
947
          ]
948
          const bidRequest = {
1✔
949
            ...baseBidRequest,
950
            userIdAsEids
951
          };
952

953
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
954
          const payload = JSON.parse(request.data);
1✔
955

956
          expect(payload).not.to.have.property('liveRampId');
1✔
957
          expect(payload['publisherFirstPartyViewerId']).to.equal('publisherFirstPartyViewerId-id');
1✔
958
          expect(payload['eids']).to.deep.equal(userIdAsEids)
1✔
959
        });
960

961
        it(`should add userId param to payload for each enabled user id system`, function () {
1✔
962
          const userIdAsEidsObject = Object.values(userIdModules);
1✔
963

964
          const bidRequest = {
1✔
965
            ...baseBidRequest,
966
            userIdAsEids: userIdAsEidsObject
967
          };
968

969
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
970
          const payload = JSON.parse(request.data);
1✔
971

972
          expect(payload['unifiedId2']).to.equal('unifiedId2-id');
1✔
973
          expect(payload['liveRampId']).to.equal('liveRampId-id');
1✔
974
          expect(payload['lotamePanoramaId']).to.equal('lotamePanoramaId-id');
1✔
975
          expect(payload['id5Id']).to.equal('id5Id-id');
1✔
976
          expect(payload['criteoId']).to.equal('criteoId-id');
1✔
977
          expect(payload['yahooConnectId']).to.equal('yahooConnectId-id');
1✔
978
          expect(payload['quantcastId']).to.equal('quantcastId-id');
1✔
979
          expect(payload['epsilonPublisherLinkId']).to.equal('epsilonPublisherLinkId-id');
1✔
980
          expect(payload['publisherFirstPartyViewerId']).to.equal('publisherFirstPartyViewerId-id');
1✔
981
          expect(payload['merkleId']).to.equal('merkleId-id');
1✔
982
          expect(payload['kinessoId']).to.equal('kinessoId-id');
1✔
983
          expect(payload['eids']).to.deep.equal(Object.values(userIdModules))
1✔
984
        });
985
      })
986

987
      describe('First-party cookie Teads ID', function () {
1✔
988
        it('should not add firstPartyCookieTeadsId param to payload if cookies are not enabled' +
1✔
989
            ' and teads user id not available', function () {
990
          sandbox.stub(storage, 'cookiesAreEnabled').returns(false);
1✔
991

992
          const bidRequest = {
1✔
993
            ...baseBidRequest,
994
            userIdAsEids: [
995
              toEid('pubcid.org', 'publisherFirstPartyViewerId-id')
996
            ]
997
          };
998

999
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1000
          const payload = JSON.parse(request.data);
1✔
1001

1002
          expect(payload).not.to.have.property('firstPartyCookieTeadsId');
1✔
1003
        });
1004

1005
        it('should not add firstPartyCookieTeadsId param to payload if cookies are enabled ' +
1✔
1006
            'but first-party cookie and teads user id are not available', function () {
1007
          sandbox.stub(storage, 'cookiesAreEnabled').returns(true);
1✔
1008
          sandbox.stub(storage, 'getCookie').withArgs('_tfpvi').returns(undefined);
1✔
1009

1010
          const bidRequest = {
1✔
1011
            ...baseBidRequest,
1012
            userIdAsEids: [
1013
              toEid('pubcid.org', 'publisherFirstPartyViewerId-id')
1014
            ]
1015
          };
1016

1017
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1018
          const payload = JSON.parse(request.data);
1✔
1019

1020
          expect(payload).not.to.have.property('firstPartyCookieTeadsId');
1✔
1021
        });
1022

1023
        it('should add firstPartyCookieTeadsId from cookie if it\'s available ' +
1✔
1024
            'and teads user id is not', function () {
1025
          sandbox.stub(storage, 'cookiesAreEnabled').returns(true);
1✔
1026
          sandbox.stub(storage, 'getCookie').withArgs('_tfpvi').returns('my-teads-id');
1✔
1027

1028
          const bidRequest = {
1✔
1029
            ...baseBidRequest,
1030
            userIdAsEids: [
1031
              toEid('pubcid.org', 'publisherFirstPartyViewerId-id')
1032
            ]
1033
          };
1034

1035
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1036

1037
          const payload = JSON.parse(request.data);
1✔
1038

1039
          expect(payload.firstPartyCookieTeadsId).to.equal('my-teads-id');
1✔
1040
        });
1041

1042
        it('should add firstPartyCookieTeadsId from user id module if it\'s available ' +
1✔
1043
            'even if cookie is available too', function () {
1044
          sandbox.stub(storage, 'cookiesAreEnabled').returns(true);
1✔
1045
          sandbox.stub(storage, 'getCookie').withArgs('_tfpvi').returns('my-teads-id');
1✔
1046

1047
          const bidRequest = {
1✔
1048
            ...baseBidRequest,
1049
            userIdAsEids: [
1050
              toEid('pubcid.org', 'publisherFirstPartyViewerId-id'),
1051
              toEid('teads.com', 'teadsId-fake-id')
1052
            ]
1053
          };
1054

1055
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1056

1057
          const payload = JSON.parse(request.data);
1✔
1058

1059
          expect(payload.firstPartyCookieTeadsId).to.equal('teadsId-fake-id');
1✔
1060
        });
1061
      });
1062

1063
      describe('Outbrain Id', function () {
1✔
1064
        it('should pass null to outbrain id if it\'s not available from local storage', function () {
1✔
1065
          const bidRequest = baseBidRequest;
1✔
1066

1067
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1068

1069
          const payload = JSON.parse(request.data);
1✔
1070

1071
          expect(payload.outbrainId).to.be.null;
1✔
1072
        });
1073

1074
        it('should add outbrain id if it\'s available from local storage', function () {
1✔
1075
          sandbox.stub(storage, 'getDataFromLocalStorage').withArgs('OB-USER-TOKEN').returns('outbrain-id');
1✔
1076

1077
          const bidRequest = baseBidRequest;
1✔
1078

1079
          const request = spec.buildRequests([bidRequest], bidderRequestDefault);
1✔
1080

1081
          const payload = JSON.parse(request.data);
1✔
1082

1083
          expect(payload.outbrainId).to.equal('outbrain-id');
1✔
1084
        });
1085
      });
1086
    });
1087

1088
    describe('Global Placement Id', function () {
1✔
1089
      const bidRequests = [
1✔
1090
        {
1091
          'bidder': 'teads',
1092
          'params': {
1093
            'placementId': 10433394,
1094
            'pageId': 1234
1095
          },
1096
          'adUnitCode': 'adunit-code-1',
1097
          'sizes': [[300, 250], [300, 600]],
1098
          'bidId': '30b31c1838de1e',
1099
          'bidderRequestId': '22edbae2733bf6',
1100
          'auctionId': '1d1a030790a475',
1101
          'creativeId': 'er2ee',
1102
          'deviceWidth': 1680
1103
        },
1104
        {
1105
          'bidder': 'teads',
1106
          'params': {
1107
            'placementId': 10433395,
1108
            'pageId': 1234
1109
          },
1110
          'adUnitCode': 'adunit-code-2',
1111
          'sizes': [[300, 250], [300, 600]],
1112
          'bidId': '30b31c1838de1f',
1113
          'bidderRequestId': '22edbae2733bf6',
1114
          'auctionId': '1d1a030790a475',
1115
          'creativeId': 'er2ef',
1116
          'deviceWidth': 1680
1117
        }
1118
      ];
1119

1120
      it('should add gpid if ortb2Imp.ext.gpid is present and is non empty', function () {
1✔
1121
        const updatedBidRequests = bidRequests.map(function(bidRequest, index) {
1✔
1122
          return {
2✔
1123
            ...bidRequest,
1124
            ortb2Imp: {
1125
              ext: {
1126
                gpid: '1111/home-left-' + index
1127
              }
1128
            }
1129
          };
1130
        }
1131
        );
1132
        const request = spec.buildRequests(updatedBidRequests, bidderRequestDefault);
1✔
1133
        const payload = JSON.parse(request.data);
1✔
1134

1135
        expect(payload.data[0].gpid).to.equal('1111/home-left-0');
1✔
1136
        expect(payload.data[1].gpid).to.equal('1111/home-left-1');
1✔
1137
      });
1138

1139
      it('should not add gpid if ortb2Imp.ext.gpid is present but empty', function () {
1✔
1140
        const updatedBidRequests = bidRequests.map(bidRequest => ({
2✔
1141
          ...bidRequest,
1142
          ortb2Imp: {
1143
            ext: {
1144
              gpid: ''
1145
            }
1146
          }
1147
        }));
1148

1149
        const request = spec.buildRequests(updatedBidRequests, bidderRequestDefault);
1✔
1150
        const payload = JSON.parse(request.data);
1✔
1151

1152
        return payload.data.forEach(bid => {
1✔
1153
          expect(bid).not.to.have.property('gpid');
2✔
1154
        });
1155
      });
1156

1157
      it('should not add gpid if ortb2Imp.ext.gpid is not present', function () {
1✔
1158
        const updatedBidRequests = bidRequests.map(bidRequest => ({
2✔
1159
          ...bidRequest,
1160
          ortb2Imp: {
1161
            ext: {
1162
            }
1163
          }
1164
        }));
1165

1166
        const request = spec.buildRequests(updatedBidRequests, bidderRequestDefault);
1✔
1167
        const payload = JSON.parse(request.data);
1✔
1168

1169
        return payload.data.forEach(bid => {
1✔
1170
          expect(bid).not.to.have.property('gpid');
2✔
1171
        });
1172
      });
1173
    });
1174

1175
    function checkMediaTypesSizes(mediaTypes, expectedSizes) {
1176
      const bidRequestWithBannerSizes = Object.assign(bidRequests[0], mediaTypes);
4✔
1177
      const requestWithBannerSizes = spec.buildRequests([bidRequestWithBannerSizes], bidderRequestDefault);
4✔
1178
      const payloadWithBannerSizes = JSON.parse(requestWithBannerSizes.data);
4✔
1179

1180
      return payloadWithBannerSizes.data.forEach(bid => {
4✔
1181
        if (Array.isArray(expectedSizes)) {
4✔
1182
          expect(JSON.stringify(bid.sizes)).to.equal(JSON.stringify(expectedSizes));
1✔
1183
        } else {
1184
          expect(bid.sizes[0]).to.equal(expectedSizes);
3✔
1185
        }
1186
      });
1187
    }
1188

1189
    it('should add dsa info to payload if available', function () {
1✔
1190
      const bidRequestWithDsa = Object.assign({}, bidderRequestDefault, {
1✔
1191
        ortb2: {
1192
          regs: {
1193
            ext: {
1194
              dsa: {
1195
                dsarequired: '1',
1196
                pubrender: '2',
1197
                datatopub: '3',
1198
                transparency: [{
1199
                  domain: 'test.com',
1200
                  dsaparams: [1, 2, 3]
1201
                }]
1202
              }
1203
            }
1204
          }
1205
        }
1206
      });
1207

1208
      const requestWithDsa = spec.buildRequests(bidRequests, bidRequestWithDsa);
1✔
1209
      const payload = JSON.parse(requestWithDsa.data);
1✔
1210

1211
      expect(payload.dsa).to.exist;
1✔
1212
      expect(payload.dsa).to.deep.equal(
1✔
1213
        {
1214
          dsarequired: '1',
1215
          pubrender: '2',
1216
          datatopub: '3',
1217
          transparency: [{
1218
            domain: 'test.com',
1219
            dsaparams: [1, 2, 3]
1220
          }]
1221
        }
1222
      );
1223

1224
      const defaultRequest = spec.buildRequests(bidRequests, bidderRequestDefault);
1✔
1225
      expect(JSON.parse(defaultRequest.data).dsa).to.not.exist;
1✔
1226
    });
1227

1228
    it('should include timeout in the payload when provided', function() {
1✔
1229
      const bidderRequest = {
1✔
1230
        timeout: 3000
1231
      };
1232
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
1233
      const payload = JSON.parse(request.data);
1✔
1234

1235
      expect(payload.timeout).to.exist;
1✔
1236
      expect(payload.timeout).to.equal(3000);
1✔
1237
    });
1238

1239
    it('should set timeout to undefined in the payload when not provided', function() {
1✔
1240
      const bidderRequest = {};
1✔
1241
      const request = spec.buildRequests(bidRequests, bidderRequest);
1✔
1242
      const payload = JSON.parse(request.data);
1✔
1243

1244
      expect(payload.timeout).to.be.undefined;
1✔
1245
    });
1246
  });
1247

1248
  describe('interpretResponse', function() {
1✔
1249
    it('should get correct bid responses', function() {
1✔
1250
      const bids = {
1✔
1251
        'body': {
1252
          'responses': [{
1253
            'ad': AD_SCRIPT,
1254
            'cpm': 0.5,
1255
            'currency': 'USD',
1256
            'height': 250,
1257
            'bidId': '3ede2a3fa0db94',
1258
            'ttl': 360,
1259
            'width': 300,
1260
            'creativeId': 'er2ee',
1261
            'placementId': 34,
1262
            'needAutoplay': true
1263
          }, {
1264
            'ad': AD_SCRIPT,
1265
            'cpm': 0.5,
1266
            'currency': 'USD',
1267
            'height': 200,
1268
            'bidId': '4fef3b4gb1ec15',
1269
            'ttl': 360,
1270
            'width': 350,
1271
            'creativeId': 'fs3ff',
1272
            'placementId': 34,
1273
            'needAutoplay': false,
1274
            'dealId': 'ABC_123',
1275
            'ext': {
1276
              'dsa': {
1277
                'behalf': 'some-behalf',
1278
                'paid': 'some-paid',
1279
                'transparency': [{
1280
                  'domain': 'test.com',
1281
                  'dsaparams': [1, 2, 3]
1282
                }],
1283
                'adrender': 1
1284
              }
1285
            }
1286
          }]
1287
        }
1288
      };
1289
      const expectedResponse = [
1✔
1290
        {
1291
          'cpm': 0.5,
1292
          'width': 300,
1293
          'height': 250,
1294
          'currency': 'USD',
1295
          'netRevenue': true,
1296
          'meta': {
1297
            advertiserDomains: []
1298
          },
1299
          'ttl': 360,
1300
          'ad': AD_SCRIPT,
1301
          'requestId': '3ede2a3fa0db94',
1302
          'creativeId': 'er2ee',
1303
          'placementId': 34
1304
        }, {
1305
          'cpm': 0.5,
1306
          'width': 350,
1307
          'height': 200,
1308
          'currency': 'USD',
1309
          'netRevenue': true,
1310
          'meta': {
1311
            advertiserDomains: [],
1312
            dsa: {
1313
              behalf: 'some-behalf',
1314
              paid: 'some-paid',
1315
              transparency: [{
1316
                domain: 'test.com',
1317
                dsaparams: [1, 2, 3]
1318
              }],
1319
              adrender: 1
1320
            }
1321
          },
1322
          'ttl': 360,
1323
          'ad': AD_SCRIPT,
1324
          'requestId': '4fef3b4gb1ec15',
1325
          'creativeId': 'fs3ff',
1326
          'placementId': 34,
1327
          'dealId': 'ABC_123'
1328
        }
1329
      ]
1330
      ;
1331

1332
      const result = spec.interpretResponse(bids);
1✔
1333
      expect(result).to.eql(expectedResponse);
1✔
1334
    });
1335

1336
    it('should filter bid responses with needAutoplay:true when autoplay is disabled', function() {
1✔
1337
      const bids = {
1✔
1338
        'body': {
1339
          'responses': [{
1340
            'ad': AD_SCRIPT,
1341
            'cpm': 0.5,
1342
            'currency': 'USD',
1343
            'height': 250,
1344
            'bidId': '3ede2a3fa0db94',
1345
            'ttl': 360,
1346
            'width': 300,
1347
            'creativeId': 'er2ee',
1348
            'placementId': 34,
1349
            'needAutoplay': true
1350
          }, {
1351
            'ad': AD_SCRIPT,
1352
            'cpm': 0.5,
1353
            'currency': 'USD',
1354
            'height': 200,
1355
            'bidId': '4fef3b4gb1ec15',
1356
            'ttl': 360,
1357
            'width': 350,
1358
            'creativeId': 'fs3ff',
1359
            'placementId': 34,
1360
            'needAutoplay': false
1361
          }, {
1362
            'ad': AD_SCRIPT,
1363
            'cpm': 0.7,
1364
            'currency': 'USD',
1365
            'height': 600,
1366
            'bidId': 'a987fbc961d',
1367
            'ttl': 12,
1368
            'width': 300,
1369
            'creativeId': 'awuygfd',
1370
            'placementId': 12,
1371
            'needAutoplay': true
1372
          }]
1373
        }
1374
      };
1375
      const expectedResponse = [{
1✔
1376
        'cpm': 0.5,
1377
        'width': 350,
1378
        'height': 200,
1379
        'currency': 'USD',
1380
        'netRevenue': true,
1381
        'meta': {
1382
          advertiserDomains: [],
1383
        },
1384
        'ttl': 360,
1385
        'ad': AD_SCRIPT,
1386
        'requestId': '4fef3b4gb1ec15',
1387
        'creativeId': 'fs3ff',
1388
        'placementId': 34
1389
      }
1390
      ]
1391
      ;
1392

1393
      const isAutoplayEnabledStub = sinon.stub(autoplay, 'isAutoplayEnabled');
1✔
1394
      isAutoplayEnabledStub.returns(false);
1✔
1395
      const result = spec.interpretResponse(bids);
1✔
1396
      isAutoplayEnabledStub.restore();
1✔
1397
      expect(result).to.eql(expectedResponse);
1✔
1398
    });
1399

1400
    it('handles nobid responses', function() {
1✔
1401
      const bids = {
1✔
1402
        'body': {
1403
          'responses': []
1404
        }
1405
      };
1406

1407
      const result = spec.interpretResponse(bids);
1✔
1408
      expect(result.length).to.equal(0);
1✔
1409
    });
1410
  });
1411
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc