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

prebid / Prebid.js / 16577710755

28 Jul 2025 06:55PM UTC coverage: 96.257%. Remained the same
16577710755

push

github

807125
web-flow
programmaticx Bid Adapter: change endpoint (#13549)

* adding programmaticxOrtbBidAdapter

* adding programmaticxOrtbBidAdapter tests

* reviewing TEST_ID_SYSTEMS

* adding required test; fixing code

* adding minor changes

* fix wrong bidder code in tests

* change adapter

* change adapter

* replacing old programmaticX adapter with new code

* fix: support for placementId field

---------

Co-authored-by: saar120 <saar120@gmail.com>

39372 of 48402 branches covered (81.34%)

197 of 199 new or added lines in 3 files covered. (98.99%)

11 existing lines in 9 files now uncovered.

194859 of 202436 relevant lines covered (96.26%)

83.37 hits per line

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

98.94
/test/spec/modules/programmaticXBidAdapter_spec.js
1
import {expect} from 'chai';
2
import {
3
  spec as adapter,
4
  createDomain,
5
  storage
6
} from 'modules/programmaticXBidAdapter';
7
import * as utils from 'src/utils.js';
8
import {version} from 'package.json';
9
import {useFakeTimers} from 'sinon';
10
import {BANNER, VIDEO} from '../../../src/mediaTypes.js'
11
import {config} from '../../../src/config.js';
12
import {
13
  hashCode,
14
  extractPID,
15
  extractCID,
16
  extractSubDomain,
17
  getStorageItem,
18
  setStorageItem,
19
  tryParseJSON,
20
  getUniqueDealId,
21
} from '../../../libraries/vidazooUtils/bidderUtils.js';
22

23
export const TEST_ID_SYSTEMS = ['criteoId', 'id5id', 'netId', 'tdid', 'pubProvidedId', 'intentIqId', 'liveIntentId'];
1✔
24

25
const SUB_DOMAIN = 'exchange';
1✔
26

27
const BID = {
1✔
28
  'bidId': '2d52001cabd527',
29
  'adUnitCode': 'div-gpt-ad-12345-0',
30
  'params': {
31
    'subDomain': SUB_DOMAIN,
32
    'cId': '59db6b3b4ffaa70004f45cdc',
33
    'pId': '59ac17c192832d0011283fe3',
34
    'bidFloor': 0.1,
35
    'ext': {
36
      'param1': 'loremipsum',
37
      'param2': 'dolorsitamet'
38
    },
39
    'placementId': 'testBanner'
40
  },
41
  'placementCode': 'div-gpt-ad-1460505748561-0',
42
  'sizes': [[300, 250], [300, 600]],
43
  'bidderRequestId': '1fdb5ff1b6eaa7',
44
  'bidRequestsCount': 4,
45
  'bidderRequestsCount': 3,
46
  'bidderWinsCount': 1,
47
  'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a',
48
  'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
49
  'mediaTypes': [BANNER],
50
  'ortb2Imp': {
51
    'ext': {
52
      'gpid': '0123456789',
53
      'tid': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf'
54
    }
55
  }
56
};
57

58
const VIDEO_BID = {
1✔
59
  'bidId': '2d52001cabd527',
60
  'adUnitCode': '63550ad1ff6642d368cba59dh5884270560',
61
  'bidderRequestId': '12a8ae9ada9c13',
62
  'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee',
63
  'bidRequestsCount': 4,
64
  'bidderRequestsCount': 3,
65
  'bidderWinsCount': 1,
66
  'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
67
  'params': {
68
    'subDomain': SUB_DOMAIN,
69
    'cId': '635509f7ff6642d368cb9837',
70
    'pId': '59ac17c192832d0011283fe3',
71
    'bidFloor': 0.1,
72
    'placementId': 'testBanner'
73
  },
74
  'sizes': [[545, 307]],
75
  'mediaTypes': {
76
    'video': {
77
      'playerSize': [[545, 307]],
78
      'context': 'instream',
79
      'mimes': [
80
        'video/mp4',
81
        'application/javascript'
82
      ],
83
      'protocols': [2, 3, 5, 6],
84
      'maxduration': 60,
85
      'minduration': 0,
86
      'startdelay': 0,
87
      'linearity': 1,
88
      'api': [2],
89
      'placement': 1
90
    }
91
  },
92
  'ortb2Imp': {
93
    'ext': {
94
      'tid': '56e184c6-bde9-497b-b9b9-cf47a61381ee'
95
    }
96
  }
97
}
98

99
const ORTB2_DEVICE = {
1✔
100
  sua: {
101
    'source': 2,
102
    'platform': {
103
      'brand': 'Android',
104
      'version': ['8', '0', '0']
105
    },
106
    'browsers': [
107
      {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
108
      {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
109
      {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
110
    ],
111
    'mobile': 1,
112
    'model': 'SM-G955U',
113
    'bitness': '64',
114
    'architecture': ''
115
  },
116
  w: 980,
117
  h: 1720,
118
  dnt: 0,
119
  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',
120
  language: 'en',
121
  devicetype: 1,
122
  make: 'Apple',
123
  model: 'iPhone 12 Pro Max',
124
  os: 'iOS',
125
  osv: '17.4',
126
  ext: {fiftyonedegrees_deviceId: '17595-133085-133468-18092'},
127
};
128

129
const BIDDER_REQUEST = {
1✔
130
  'gdprConsent': {
131
    'consentString': 'consent_string',
132
    'gdprApplies': true
133
  },
134
  'gppString': 'gpp_string',
135
  'gppSid': [7],
136
  'uspConsent': 'consent_string',
137
  'refererInfo': {
138
    'page': 'https://www.greatsite.com',
139
    'ref': 'https://www.somereferrer.com'
140
  },
141
  'ortb2': {
142
    'site': {
143
      'content': {
144
        'language': 'en'
145
      }
146
    },
147
    'regs': {
148
      'gpp': 'gpp_string',
149
      'gpp_sid': [7],
150
      'coppa': 0
151
    },
152
    'device': ORTB2_DEVICE,
153
  }
154
};
155

156
const SERVER_RESPONSE = {
1✔
157
  body: {
158
    cid: 'testcid123',
159
    results: [{
160
      'ad': '<iframe>console.log("hello world")</iframe>',
161
      'price': 0.8,
162
      'creativeId': '12610997325162499419',
163
      'exp': 30,
164
      'width': 300,
165
      'height': 250,
166
      'advertiserDomains': ['securepubads.g.doubleclick.net'],
167
      'cookies': [{
168
        'src': 'https://sync.com',
169
        'type': 'iframe'
170
      }, {
171
        'src': 'https://sync.com',
172
        'type': 'img'
173
      }]
174
    }]
175
  }
176
};
177

178
const VIDEO_SERVER_RESPONSE = {
1✔
179
  body: {
180
    'cid': '635509f7ff6642d368cb9837',
181
    'results': [{
182
      'ad': '<VAST version=\"3.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"></VAST>',
183
      'advertiserDomains': ['programmaticx.ai'],
184
      'exp': 60,
185
      'width': 545,
186
      'height': 307,
187
      'mediaType': 'video',
188
      'creativeId': '12610997325162499419',
189
      'price': 2,
190
      'cookies': []
191
    }]
192
  }
193
};
194

195
const REQUEST = {
1✔
196
  data: {
197
    width: 300,
198
    height: 250,
199
    bidId: '2d52001cabd527'
200
  }
201
};
202

203
function getTopWindowQueryParams() {
204
  try {
2✔
205
    const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true});
2✔
206
    return parsedUrl.search;
2✔
207
  } catch (e) {
NEW
208
    return '';
×
209
  }
210
}
211

212
describe('programmaticXBidAdapter', function () {
1✔
213
  before(() => config.resetConfig());
1✔
214
  after(() => config.resetConfig());
1✔
215

216
  describe('validtae spec', function () {
1✔
217
    it('exists and is a function', function () {
1✔
218
      expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function');
1✔
219
    });
220

221
    it('exists and is a function', function () {
1✔
222
      expect(adapter.buildRequests).to.exist.and.to.be.a('function');
1✔
223
    });
224

225
    it('exists and is a function', function () {
1✔
226
      expect(adapter.interpretResponse).to.exist.and.to.be.a('function');
1✔
227
    });
228

229
    it('exists and is a function', function () {
1✔
230
      expect(adapter.getUserSyncs).to.exist.and.to.be.a('function');
1✔
231
    });
232

233
    it('exists and is a string', function () {
1✔
234
      expect(adapter.code).to.exist.and.to.be.a('string');
1✔
235
    });
236

237
    it('exists and contains media types', function () {
1✔
238
      expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2);
1✔
239
      expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]);
1✔
240
    });
241
  });
242

243
  describe('validate bid requests', function () {
1✔
244
    it('should require cId', function () {
1✔
245
      const isValid = adapter.isBidRequestValid({
1✔
246
        params: {
247
          pId: 'pid'
248
        }
249
      });
250
      expect(isValid).to.be.false;
1✔
251
    });
252

253
    it('should require pId', function () {
1✔
254
      const isValid = adapter.isBidRequestValid({
1✔
255
        params: {
256
          cId: 'cid'
257
        }
258
      });
259
      expect(isValid).to.be.false;
1✔
260
    });
261

262
    it('should validate correctly', function () {
1✔
263
      const isValid = adapter.isBidRequestValid({
1✔
264
        params: {
265
          cId: 'cid',
266
          pId: 'pid'
267
        }
268
      });
269
      expect(isValid).to.be.true;
1✔
270
    });
271
  });
272

273
  describe('build requests', function () {
1✔
274
    let sandbox;
275
    before(function () {
1✔
276
      $$PREBID_GLOBAL$$.bidderSettings = {
1✔
277
        programmaticX: {
278
          storageAllowed: true
279
        }
280
      };
281
      sandbox = sinon.createSandbox();
1✔
282
      sandbox.stub(Date, 'now').returns(1000);
1✔
283
    });
284

285
    it('should build video request', function () {
1✔
286
      const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
1✔
287
      config.setConfig({
1✔
288
        bidderTimeout: 3000
289
      });
290
      const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST);
1✔
291
      expect(requests).to.have.length(1);
1✔
292
      expect(requests[0]).to.deep.equal({
1✔
293
        method: 'POST',
294
        url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`,
295
        data: {
296
          adUnitCode: '63550ad1ff6642d368cba59dh5884270560',
297
          bidFloor: 0.1,
298
          bidId: '2d52001cabd527',
299
          bidderVersion: adapter.version,
300
          bidderRequestId: '12a8ae9ada9c13',
301
          cb: 1000,
302
          gdpr: 1,
303
          gdprConsent: 'consent_string',
304
          usPrivacy: 'consent_string',
305
          gppString: 'gpp_string',
306
          gppSid: [7],
307
          prebidVersion: version,
308
          transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee',
309
          bidRequestsCount: 4,
310
          bidderRequestsCount: 3,
311
          bidderWinsCount: 1,
312
          bidderTimeout: 3000,
313
          publisherId: '59ac17c192832d0011283fe3',
314
          url: 'https%3A%2F%2Fwww.greatsite.com',
315
          referrer: 'https://www.somereferrer.com',
316
          res: `${window.top.screen.width}x${window.top.screen.height}`,
317
          schain: VIDEO_BID.schain,
318
          sizes: ['545x307'],
319
          sua: {
320
            'source': 2,
321
            'platform': {
322
              'brand': 'Android',
323
              'version': ['8', '0', '0']
324
            },
325
            'browsers': [
326
              {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
327
              {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
328
              {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
329
            ],
330
            'mobile': 1,
331
            'model': 'SM-G955U',
332
            'bitness': '64',
333
            'architecture': ''
334
          },
335
          device: ORTB2_DEVICE,
336
          uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
337
          uqs: getTopWindowQueryParams(),
338
          mediaTypes: {
339
            video: {
340
              api: [2],
341
              context: 'instream',
342
              linearity: 1,
343
              maxduration: 60,
344
              mimes: [
345
                'video/mp4',
346
                'application/javascript'
347
              ],
348
              minduration: 0,
349
              placement: 1,
350
              playerSize: [[545, 307]],
351
              protocols: [2, 3, 5, 6],
352
              startdelay: 0
353
            }
354
          },
355
          gpid: '',
356
          cat: [],
357
          contentLang: 'en',
358
          contentData: [],
359
          isStorageAllowed: true,
360
          pagecat: [],
361
          placementId: "testBanner",
362
          userData: [],
363
          coppa: 0
364
        }
365
      });
366
    });
367

368
    it('should build banner request for each size', function () {
1✔
369
      const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
1✔
370
      config.setConfig({
1✔
371
        bidderTimeout: 3000
372
      });
373
      const requests = adapter.buildRequests([BID], BIDDER_REQUEST);
1✔
374
      expect(requests).to.have.length(1);
1✔
375
      expect(requests[0]).to.deep.equal({
1✔
376
        method: 'POST',
377
        url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`,
378
        data: {
379
          gdprConsent: 'consent_string',
380
          gdpr: 1,
381
          gppString: 'gpp_string',
382
          gppSid: [7],
383
          usPrivacy: 'consent_string',
384
          transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf',
385
          bidRequestsCount: 4,
386
          bidderRequestsCount: 3,
387
          bidderWinsCount: 1,
388
          bidderTimeout: 3000,
389
          bidderRequestId: '1fdb5ff1b6eaa7',
390
          sizes: ['300x250', '300x600'],
391
          sua: {
392
            'source': 2,
393
            'platform': {
394
              'brand': 'Android',
395
              'version': ['8', '0', '0']
396
            },
397
            'browsers': [
398
              {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
399
              {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
400
              {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
401
            ],
402
            'mobile': 1,
403
            'model': 'SM-G955U',
404
            'bitness': '64',
405
            'architecture': ''
406
          },
407
          device: ORTB2_DEVICE,
408
          url: 'https%3A%2F%2Fwww.greatsite.com',
409
          referrer: 'https://www.somereferrer.com',
410
          cb: 1000,
411
          bidFloor: 0.1,
412
          bidId: '2d52001cabd527',
413
          adUnitCode: 'div-gpt-ad-12345-0',
414
          publisherId: '59ac17c192832d0011283fe3',
415
          uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
416
          bidderVersion: adapter.version,
417
          prebidVersion: version,
418
          schain: BID.schain,
419
          res: `${window.top.screen.width}x${window.top.screen.height}`,
420
          mediaTypes: [BANNER],
421
          gpid: '0123456789',
422
          uqs: getTopWindowQueryParams(),
423
          'ext.param1': 'loremipsum',
424
          'ext.param2': 'dolorsitamet',
425
          cat: [],
426
          contentLang: 'en',
427
          contentData: [],
428
          isStorageAllowed: true,
429
          pagecat: [],
430
          placementId: "testBanner",
431
          userData: [],
432
          coppa: 0
433
        }
434
      });
435
    });
436

437
    after(function () {
1✔
438
      $$PREBID_GLOBAL$$.bidderSettings = {};
1✔
439
      sandbox.restore();
1✔
440
    });
441
  });
442
  describe('getUserSyncs', function () {
1✔
443
    it('should have valid user sync with iframeEnabled', function () {
1✔
444
      const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
1✔
445

446
      expect(result).to.deep.equal([{
1✔
447
        type: 'iframe',
448
        url: 'https://sync.programmaticx.ai/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=&coppa=0'
449
      }]);
450
    });
451

452
    it('should have valid user sync with cid on response', function () {
1✔
453
      const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
1✔
454
      expect(result).to.deep.equal([{
1✔
455
        type: 'iframe',
456
        url: 'https://sync.programmaticx.ai/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=&coppa=0'
457
      }]);
458
    });
459

460
    it('should have valid user sync with pixelEnabled', function () {
1✔
461
      const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]);
1✔
462

463
      expect(result).to.deep.equal([{
1✔
464
        'url': 'https://sync.programmaticx.ai/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=&coppa=0',
465
        'type': 'image'
466
      }]);
467
    });
468

469
    it('should have valid user sync with coppa 1 on response', function () {
1✔
470
      config.setConfig({
1✔
471
        coppa: 1
472
      });
473
      const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
1✔
474
      expect(result).to.deep.equal([{
1✔
475
        type: 'iframe',
476
        url: 'https://sync.programmaticx.ai/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=&coppa=1'
477
      }]);
478
    });
479

480
    it('should generate url with consent data', function () {
1✔
481
      const gdprConsent = {
1✔
482
        gdprApplies: true,
483
        consentString: 'consent_string'
484
      };
485
      const uspConsent = 'usp_string';
1✔
486
      const gppConsent = {
1✔
487
        gppString: 'gpp_string',
488
        applicableSections: [7]
489
      }
490

491
      const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE], gdprConsent, uspConsent, gppConsent);
1✔
492

493
      expect(result).to.deep.equal([{
1✔
494
        'url': 'https://sync.programmaticx.ai/api/sync/image/?cid=testcid123&gdpr=1&gdpr_consent=consent_string&us_privacy=usp_string&coppa=1&gpp=gpp_string&gpp_sid=7',
495
        'type': 'image'
496
      }]);
497
    });
498
  });
499

500
  describe('interpret response', function () {
1✔
501
    it('should return empty array when there is no response', function () {
1✔
502
      const responses = adapter.interpretResponse(null);
1✔
503
      expect(responses).to.be.empty;
1✔
504
    });
505

506
    it('should return empty array when there is no ad', function () {
1✔
507
      const responses = adapter.interpretResponse({price: 1, ad: ''});
1✔
508
      expect(responses).to.be.empty;
1✔
509
    });
510

511
    it('should return empty array when there is no price', function () {
1✔
512
      const responses = adapter.interpretResponse({price: null, ad: 'great ad'});
1✔
513
      expect(responses).to.be.empty;
1✔
514
    });
515

516
    it('should return an array of interpreted banner responses', function () {
1✔
517
      const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST);
1✔
518
      expect(responses).to.have.length(1);
1✔
519
      expect(responses[0]).to.deep.equal({
1✔
520
        requestId: '2d52001cabd527',
521
        cpm: 0.8,
522
        width: 300,
523
        height: 250,
524
        creativeId: '12610997325162499419',
525
        currency: 'USD',
526
        netRevenue: true,
527
        ttl: 30,
528
        ad: '<iframe>console.log("hello world")</iframe>',
529
        meta: {
530
          advertiserDomains: ['securepubads.g.doubleclick.net']
531
        }
532
      });
533
    });
534

535
    it('should get meta from response metaData', function () {
1✔
536
      const serverResponse = utils.deepClone(SERVER_RESPONSE);
1✔
537
      serverResponse.body.results[0].metaData = {
1✔
538
        advertiserDomains: ['programmaticx.ai'],
539
        agencyName: 'Agency Name',
540
      };
541
      const responses = adapter.interpretResponse(serverResponse, REQUEST);
1✔
542
      expect(responses[0].meta).to.deep.equal({
1✔
543
        advertiserDomains: ['programmaticx.ai'],
544
        agencyName: 'Agency Name'
545
      });
546
    });
547

548
    it('should return an array of interpreted video responses', function () {
1✔
549
      const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST);
1✔
550
      expect(responses).to.have.length(1);
1✔
551
      expect(responses[0]).to.deep.equal({
1✔
552
        requestId: '2d52001cabd527',
553
        cpm: 2,
554
        width: 545,
555
        height: 307,
556
        mediaType: 'video',
557
        creativeId: '12610997325162499419',
558
        currency: 'USD',
559
        netRevenue: true,
560
        ttl: 60,
561
        vastXml: '<VAST version=\"3.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"></VAST>',
562
        meta: {
563
          advertiserDomains: ['programmaticx.ai']
564
        }
565
      });
566
    });
567

568
    it('should take default TTL', function () {
1✔
569
      const serverResponse = utils.deepClone(SERVER_RESPONSE);
1✔
570
      delete serverResponse.body.results[0].exp;
1✔
571
      const responses = adapter.interpretResponse(serverResponse, REQUEST);
1✔
572
      expect(responses).to.have.length(1);
1✔
573
      expect(responses[0].ttl).to.equal(300);
1✔
574
    });
575
  });
576

577
  describe('user id system', function () {
1✔
578
    TEST_ID_SYSTEMS.forEach((idSystemProvider) => {
1✔
579
      const id = Date.now().toString();
7✔
580
      const bid = utils.deepClone(BID);
7✔
581

582
      const userId = (function () {
7✔
583
        switch (idSystemProvider) {
7!
584
          case 'lipb':
NEW
585
            return {lipbid: id};
×
586
          case 'id5id':
587
            return {uid: id};
1✔
588
          default:
589
            return id;
6✔
590
        }
591
      })();
592

593
      bid.userId = {
7✔
594
        [idSystemProvider]: userId
595
      };
596

597
      it(`should include 'uid.${idSystemProvider}' in request params`, function () {
7✔
598
        const requests = adapter.buildRequests([bid], BIDDER_REQUEST);
7✔
599
        expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id);
7✔
600
      });
601
    });
602
  });
603

604
  describe('alternate param names extractors', function () {
1✔
605
    it('should return undefined when param not supported', function () {
1✔
606
      const cid = extractCID({'c_id': '1'});
1✔
607
      const pid = extractPID({'p_id': '1'});
1✔
608
      const subDomain = extractSubDomain({'sub_domain': 'prebid'});
1✔
609
      expect(cid).to.be.undefined;
1✔
610
      expect(pid).to.be.undefined;
1✔
611
      expect(subDomain).to.be.undefined;
1✔
612
    });
613

614
    it('should return value when param supported', function () {
1✔
615
      const cid = extractCID({'cID': '1'});
1✔
616
      const pid = extractPID({'Pid': '2'});
1✔
617
      const subDomain = extractSubDomain({'subDOMAIN': 'prebid'});
1✔
618
      expect(cid).to.be.equal('1');
1✔
619
      expect(pid).to.be.equal('2');
1✔
620
      expect(subDomain).to.be.equal('prebid');
1✔
621
    });
622
  });
623

624
  describe('unique deal id', function () {
1✔
625
    before(function () {
1✔
626
      $$PREBID_GLOBAL$$.bidderSettings = {
1✔
627
        programmaticX: {
628
          storageAllowed: true
629
        }
630
      };
631
    });
632
    after(function () {
1✔
633
      $$PREBID_GLOBAL$$.bidderSettings = {};
1✔
634
    });
635
    const key = 'myKey';
1✔
636
    let uniqueDealId;
637
    beforeEach(() => {
1✔
638
      uniqueDealId = getUniqueDealId(storage, key, 0);
2✔
639
    })
640

641
    it('should get current unique deal id', function (done) {
1✔
642
      // waiting some time so `now` will become past
643
      setTimeout(() => {
1✔
644
        const current = getUniqueDealId(storage, key);
1✔
645
        expect(current).to.be.equal(uniqueDealId);
1✔
646
        done();
1✔
647
      }, 200);
648
    });
649

650
    it('should get new unique deal id on expiration', function (done) {
1✔
651
      setTimeout(() => {
1✔
652
        const current = getUniqueDealId(storage, key, 100);
1✔
653
        expect(current).to.not.be.equal(uniqueDealId);
1✔
654
        done();
1✔
655
      }, 200)
656
    });
657
  });
658

659
  describe('storage utils', function () {
1✔
660
    before(function () {
1✔
661
      $$PREBID_GLOBAL$$.bidderSettings = {
1✔
662
        programmaticX: {
663
          storageAllowed: true
664
        }
665
      };
666
    });
667
    after(function () {
1✔
668
      $$PREBID_GLOBAL$$.bidderSettings = {};
1✔
669
    });
670
    it('should get value from storage with create param', function () {
1✔
671
      const now = Date.now();
1✔
672
      const clock = useFakeTimers({
1✔
673
        shouldAdvanceTime: true,
674
        now
675
      });
676
      setStorageItem(storage, 'myKey', 2020);
1✔
677
      const {value, created} = getStorageItem(storage, 'myKey');
1✔
678
      expect(created).to.be.equal(now);
1✔
679
      expect(value).to.be.equal(2020);
1✔
680
      expect(typeof value).to.be.equal('number');
1✔
681
      expect(typeof created).to.be.equal('number');
1✔
682
      clock.restore();
1✔
683
    });
684

685
    it('should get external stored value', function () {
1✔
686
      const value = 'superman'
1✔
687
      window.localStorage.setItem('myExternalKey', value);
1✔
688
      const item = getStorageItem(storage, 'myExternalKey');
1✔
689
      expect(item).to.be.equal(value);
1✔
690
    });
691

692
    it('should parse JSON value', function () {
1✔
693
      const data = JSON.stringify({event: 'send'});
1✔
694
      const {event} = tryParseJSON(data);
1✔
695
      expect(event).to.be.equal('send');
1✔
696
    });
697

698
    it('should get original value on parse fail', function () {
1✔
699
      const value = 21;
1✔
700
      const parsed = tryParseJSON(value);
1✔
701
      expect(typeof parsed).to.be.equal('number');
1✔
702
      expect(parsed).to.be.equal(value);
1✔
703
    });
704
  });
705

706
  describe('createDomain test', function() {
1✔
707
    it('should return correct domain', function () {
1✔
708
      const responses = createDomain();
1✔
709
      expect(responses).to.be.equal('https://exchange.programmaticx.ai');
1✔
710
    });
711
  })
712
});
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