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

prebid / Prebid.js / 18594521186

17 Oct 2025 01:40PM UTC coverage: 96.238% (-0.001%) from 96.239%
18594521186

push

github

web-flow
Semantiq RTD module: fix incorrect property name (#14027)

Co-authored-by: Alexandr Kim <alexandr.kim@audienzz.ch>

52437 of 64151 branches covered (81.74%)

1 of 1 new or added line in 1 file covered. (100.0%)

401 existing lines in 53 files now uncovered.

200307 of 208138 relevant lines covered (96.24%)

125.2 hits per line

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

99.35
/test/spec/modules/atsAnalyticsAdapter_spec.js
1
import atsAnalyticsAdapter, {parseBrowser, analyticsUrl, bidRequestedHandler} from '../../../modules/atsAnalyticsAdapter.js';
2
import { expect } from 'chai';
3
import adapterManager from 'src/adapterManager.js';
4
import {server} from '../../mocks/xhr.js';
5

6
import {getCoreStorageManager, getStorageManager} from '../../../src/storageManager.js';
7

8
import {EVENTS} from 'src/constants.js';
9
import {getGlobal} from '../../../src/prebidGlobal.js';
10

11
const utils = require('src/utils');
1✔
12
const events = require('src/events');
1✔
13

14
const storage = getCoreStorageManager();
1✔
15
let sandbox;
16
let clock;
17
const now = new Date();
1✔
18

19
describe('ats analytics adapter', function () {
1✔
20
  beforeEach(function () {
1✔
21
    sinon.stub(events, 'getEvents').returns([]);
22✔
22
    storage.setCookie('_lr_env_src_ats', 'true', 'Thu, 01 Jan 1970 00:00:01 GMT');
22✔
23
    sandbox = sinon.createSandbox();
22✔
24
    clock = sandbox.useFakeTimers(now.getTime());
22✔
25
  });
26

27
  afterEach(function () {
1✔
28
    events.getEvents.restore();
22✔
29
    atsAnalyticsAdapter.getUserAgent.restore();
22✔
30
    atsAnalyticsAdapter.disableAnalytics();
22✔
31
    Math.random.restore();
22✔
32
    sandbox.restore();
22✔
33
    clock.restore();
22✔
34
  });
35

36
  describe('track', function () {
1✔
37
    it('builds and sends request and response data', function () {
1✔
38
      sinon.stub(Math, 'random').returns(0.99);
1✔
39
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
40

41
      now.setTime(now.getTime() + 3600000);
1✔
42
      storage.setCookie('_lr_env_src_ats', 'true', now.toUTCString());
1✔
43
      storage.setCookie('_lr_sampling_rate', '10', now.toUTCString());
1✔
44

45
      this.timeout(2100);
1✔
46

47
      const initOptions = {
1✔
48
        pid: '10433394'
49
      };
50
      const auctionTimestamp = 1496510254326;
1✔
51

52
      // prepare general auction - request
53
      const bidRequest = {
1✔
54
        'bidderCode': 'appnexus',
55
        'auctionStart': 1580739265161,
56
        'bids': [{
57
          'bidder': 'appnexus',
58
          'params': {
59
            'placementId': '10433394'
60
          },
61
          'userId': {
62
            'idl_env': 'AmThEbO1ssIWjrNdU4noT4ZFBILSVBBYHbipOYt_JP40e5nZdXns2g'
63
          },
64
          'adUnitCode': 'div-gpt-ad-1438287399331-0',
65
          'transactionId': '2f481ff1-8d20-4c28-8e36-e384e9e3eec6',
66
          'sizes': '300x250,300x600',
67
          'bidId': '30c77d079cdf17'
68
        }],
69
        'refererInfo': {
70
          'referer': 'https://example.com/dev'
71
        },
72
        'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
73
      };
74
      // prepare general auction - response
75
      const bidResponse = {
1✔
76
        'height': 250,
77
        'statusMessage': 'Bid available',
78
        'adId': '2eddfdc0c791dc',
79
        'mediaType': 'banner',
80
        'source': 'client',
81
        'requestId': '30c77d079cdf17',
82
        'cpm': 0.5,
83
        'creativeId': 29681110,
84
        'currency': 'USD',
85
        'netRevenue': true,
86
        'ttl': 300,
87
        'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
88
        'responseTimestamp': 1580739791978,
89
        'requestTimestamp': 1580739265164,
90
        'bidder': 'appnexus',
91
        'adUnitCode': 'div-gpt-ad-1438287399331-0',
92
        'timeToRespond': 2510,
93
        'size': '300x250'
94
      };
95

96
      // what we expect after general auction
97
      const expectedAfterBid = {
1✔
98
        'Data': [{
99
          'has_envelope': true,
100
          'adapter_version': 3,
101
          'bidder': 'appnexus',
102
          'bid_id': '30c77d079cdf17',
103
          'auction_id': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
104
          'user_browser': parseBrowser(),
105
          'user_platform': navigator.platform,
106
          'auction_start': '2020-02-03T14:14:25.161Z',
107
          'domain': window.location.hostname,
108
          'envelope_source': true,
109
          'pid': '10433394',
110
          'response_time_stamp': '2020-02-03T14:23:11.978Z',
111
          'currency': 'USD',
112
          'cpm': 0.5,
113
          'net_revenue': true,
114
          'bid_won': true
115
        }]
116
      };
117

118
      const wonRequest = {
1✔
119
        'adId': '2eddfdc0c791dc',
120
        'mediaType': 'banner',
121
        'requestId': '30c77d079cdf17',
122
        'cpm': 0.5,
123
        'creativeId': 29681110,
124
        'currency': 'USD',
125
        'netRevenue': true,
126
        'ttl': 300,
127
        'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7',
128
        'statusMessage': 'Bid available',
129
        'responseTimestamp': 1633525319061,
130
        'requestTimestamp': 1633525319258,
131
        'bidder': 'appnexus',
132
        'adUnitCode': 'div-gpt-ad-1438287399331-0',
133
        'size': '300x250',
134
        'status': 'rendered'
135
      };
136

137
      // lets simulate that some bidders timeout
138
      const bidTimeoutArgsV1 = [
1✔
139
        {
140
          bidId: '2baa51527bd015',
141
          bidder: 'bidderOne',
142
          adUnitCode: '/19968336/header-bid-tag-0',
143
          auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f'
144
        },
145
        {
146
          bidId: '6fe3b4c2c23092',
147
          bidder: 'bidderTwo',
148
          adUnitCode: '/19968336/header-bid-tag-0',
149
          auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f'
150
        }
151
      ];
152

153
      adapterManager.registerAnalyticsAdapter({
1✔
154
        code: 'atsAnalytics',
155
        adapter: atsAnalyticsAdapter
156
      });
157

158
      adapterManager.enableAnalytics({
1✔
159
        provider: 'atsAnalytics',
160
        options: initOptions
161
      });
162

163
      // Step 1: Send auction init event
164
      events.emit(EVENTS.AUCTION_INIT, {
1✔
165
        timestamp: auctionTimestamp
166
      });
167
      // Step 2: Send bid requested event
168
      events.emit(EVENTS.BID_REQUESTED, bidRequest);
1✔
169

170
      // Step 3: Send bid response event
171
      events.emit(EVENTS.BID_RESPONSE, bidResponse);
1✔
172

173
      // Step 4: Send bid time out event
174
      events.emit(EVENTS.BID_TIMEOUT, bidTimeoutArgsV1);
1✔
175

176
      // Step 5: Send auction end event
177
      events.emit(EVENTS.AUCTION_END, {});
1✔
178
      // Step 6: Send bid won event
179
      events.emit(EVENTS.BID_WON, wonRequest);
1✔
180

181
      // Stub getAllWinningBids before auction end processing
182
      const globalObj = getGlobal();
1✔
183
      if (typeof globalObj.getAllWinningBids !== 'function') {
1!
UNCOV
184
        globalObj.getAllWinningBids = function() { return []; };
×
185
      }
186
      sandbox.stub(globalObj, 'getAllWinningBids').returns([wonRequest]);
1✔
187

188
      clock.tick(2000);
1✔
189

190
      const requests = server.requests.filter(req => {
1✔
191
        return req.url.indexOf(analyticsUrl) > -1;
1✔
192
      });
193

194
      expect(requests.length).to.equal(1);
1✔
195

196
      const realAfterBid = JSON.parse(requests[0].requestBody);
1✔
197

198
      // Step 7: assert real data after bid and expected data
199
      expect(realAfterBid['Data']).to.deep.equal(expectedAfterBid['Data']);
1✔
200

201
      // check that the publisher ID is configured via options
202
      expect(atsAnalyticsAdapter.context.pid).to.equal(initOptions.pid);
1✔
203
    })
204
    it('check browser is safari', function () {
1✔
205
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
206
      sinon.stub(Math, 'random').returns(0.99);
1✔
207
      const browser = parseBrowser();
1✔
208
      expect(browser).to.equal('Safari');
1✔
209
    })
210
    it('check browser is chrome', function () {
1✔
211
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/80.0.3987.95 Mobile/15E148 Safari/604.1');
1✔
212
      sinon.stub(Math, 'random').returns(0.99);
1✔
213
      const browser = parseBrowser();
1✔
214
      expect(browser).to.equal('Chrome');
1✔
215
    })
216
    it('check browser is edge', function () {
1✔
217
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43');
1✔
218
      sinon.stub(Math, 'random').returns(0.99);
1✔
219
      const browser = parseBrowser();
1✔
220
      expect(browser).to.equal('Microsoft Edge');
1✔
221
    })
222
    it('check browser is firefox', function () {
1✔
223
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (iPhone; CPU OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/23.0  Mobile/15E148 Safari/605.1.15');
1✔
224
      sinon.stub(Math, 'random').returns(0.99);
1✔
225
      const browser = parseBrowser();
1✔
226
      expect(browser).to.equal('Firefox');
1✔
227
    })
228
    it('check browser is unknown', function () {
1✔
229
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns(undefined);
1✔
230
      sinon.stub(Math, 'random').returns(0.99);
1✔
231
      const browser = parseBrowser();
1✔
232
      expect(browser).to.equal('Unknown');
1✔
233
    })
234
    it('should not fire analytics request if sampling rate is 0', function () {
1✔
235
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
236
      sinon.stub(Math, 'random').returns(0.99);
1✔
237
      const result = atsAnalyticsAdapter.shouldFireRequest(0);
1✔
238
      expect(result).to.equal(false);
1✔
239
    })
240
    it('should fire analytics request', function () {
1✔
241
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
242
      sinon.stub(Math, 'random').returns(0.99);
1✔
243
      // publisher can try to pass anything they want but we will set sampling rate to 100, which means we will have 1% of requests
244
      const result = atsAnalyticsAdapter.shouldFireRequest(8);
1✔
245
      expect(result).to.equal(true);
1✔
246
    })
247
    it('should not fire analytics request if math random is something other then 0.99', function () {
1✔
248
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
249
      sinon.stub(Math, 'random').returns(0.98);
1✔
250
      // publisher can try to pass anything they want but we will set sampling rate to 100, which means we will have 1% of requests
251
      const result = atsAnalyticsAdapter.shouldFireRequest(10);
1✔
252
      expect(result).to.equal(false);
1✔
253
    })
254

255
    it('should set cookie value to 10 for _lr_sampling_rate', function () {
1✔
256
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
257
      sinon.stub(Math, 'random').returns(0.99);
1✔
258
      atsAnalyticsAdapter.setSamplingCookie(10);
1✔
259
      const samplingRate = storage.getCookie('_lr_sampling_rate');
1✔
260
      expect(samplingRate).to.equal('10');
1✔
261
    })
262

263
    it('should set cookie value to 0 for _lr_sampling_rate', function () {
1✔
264
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
265
      sinon.stub(Math, 'random').returns(0.99);
1✔
266
      atsAnalyticsAdapter.setSamplingCookie(0);
1✔
267
      const samplingRate = storage.getCookie('_lr_sampling_rate');
1✔
268
      expect(samplingRate).to.equal('0');
1✔
269
    })
270

271
    it('enable analytics', function () {
1✔
272
      sandbox.stub(utils, 'logError');
1✔
273
      sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
1✔
274
      sinon.stub(Math, 'random').returns(0.99);
1✔
275
      atsAnalyticsAdapter.enableAnalytics({
1✔
276
        options: {}
277
      });
278
      expect(utils.logError.called).to.equal(true);
1✔
279
    })
280

281
    describe('has_envelope logic for Prebid v10.0+ compatibility', function () {
1✔
282
      beforeEach(function () {
1✔
283
        sinon.stub(atsAnalyticsAdapter, 'getUserAgent').returns('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25');
10✔
284
        sinon.stub(Math, 'random').returns(0.99);
10✔
285
        storage.setCookie('_lr_env_src_ats', 'true', 'Thu, 01 Jan 1970 00:00:01 GMT');
10✔
286

287
        // Enable analytics for testing
288
        atsAnalyticsAdapter.enableAnalytics({
10✔
289
          options: { pid: '10433394' }
290
        });
291
      });
292

293
      it('should return true when userIdAsEids contains liveramp.com source with valid uids', function () {
1✔
294
        const bidRequestArgs = {
1✔
295
          'bidderCode': 'appnexus',
296
          'auctionStart': 1580739265161,
297
          'bids': [{
298
            'bidder': 'appnexus',
299
            'bidId': '30c77d079cdf17',
300
            'userIdAsEids': [{
301
              'source': 'liveramp.com',
302
              'uids': [{'id': 'AmThEbO1ssIWjrNdU4noT4ZFBILSVBBYHbipOYt_JP40e5nZdXns2g'}]
303
            }]
304
          }],
305
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
306
        };
307

308
        const result = bidRequestedHandler(bidRequestArgs);
1✔
309
        expect(result[0].has_envelope).to.equal(true);
1✔
310
      });
311

312
      it('should return false when userIdAsEids contains liveramp source but no uids', function () {
1✔
313
        const bidRequestArgs = {
1✔
314
          'bidderCode': 'appnexus',
315
          'auctionStart': 1580739265161,
316
          'bids': [{
317
            'bidder': 'appnexus',
318
            'bidId': '30c77d079cdf17',
319
            'userIdAsEids': [{
320
              'source': 'liveramp.com',
321
              'uids': []
322
            }]
323
          }],
324
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
325
        };
326

327
        const result = bidRequestedHandler(bidRequestArgs);
1✔
328
        expect(result[0].has_envelope).to.equal(false);
1✔
329
      });
330

331
      it('should return false when userIdAsEids contains non-liveramp sources', function () {
1✔
332
        const bidRequestArgs = {
1✔
333
          'bidderCode': 'appnexus',
334
          'auctionStart': 1580739265161,
335
          'bids': [{
336
            'bidder': 'appnexus',
337
            'bidId': '30c77d079cdf17',
338
            'userIdAsEids': [{
339
              'source': 'id5-sync.com',
340
              'uids': [{'id': 'some-other-id'}]
341
            }]
342
          }],
343
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
344
        };
345

346
        const result = bidRequestedHandler(bidRequestArgs);
1✔
347
        expect(result[0].has_envelope).to.equal(false);
1✔
348
      });
349

350
      it('should return false when userIdAsEids is empty array', function () {
1✔
351
        const bidRequestArgs = {
1✔
352
          'bidderCode': 'appnexus',
353
          'auctionStart': 1580739265161,
354
          'bids': [{
355
            'bidder': 'appnexus',
356
            'bidId': '30c77d079cdf17',
357
            'userIdAsEids': []
358
          }],
359
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
360
        };
361

362
        const result = bidRequestedHandler(bidRequestArgs);
1✔
363
        expect(result[0].has_envelope).to.equal(false);
1✔
364
      });
365

366
      it('should return false when userIdAsEids is not present', function () {
1✔
367
        const bidRequestArgs = {
1✔
368
          'bidderCode': 'appnexus',
369
          'auctionStart': 1580739265161,
370
          'bids': [{
371
            'bidder': 'appnexus',
372
            'bidId': '30c77d079cdf17'
373
            // No userIdAsEids property
374
          }],
375
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
376
        };
377

378
        const result = bidRequestedHandler(bidRequestArgs);
1✔
379
        expect(result[0].has_envelope).to.equal(false);
1✔
380
      });
381

382
      it('should return false when userIdAsEids is not an array', function () {
1✔
383
        const bidRequestArgs = {
1✔
384
          'bidderCode': 'appnexus',
385
          'auctionStart': 1580739265161,
386
          'bids': [{
387
            'bidder': 'appnexus',
388
            'bidId': '30c77d079cdf17',
389
            'userIdAsEids': 'not-an-array'
390
          }],
391
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
392
        };
393

394
        const result = bidRequestedHandler(bidRequestArgs);
1✔
395
        expect(result[0].has_envelope).to.equal(false);
1✔
396
      });
397

398
      it('should return true for legacy userId.idl_env (backward compatibility)', function () {
1✔
399
        const bidRequestArgs = {
1✔
400
          'bidderCode': 'appnexus',
401
          'auctionStart': 1580739265161,
402
          'bids': [{
403
            'bidder': 'appnexus',
404
            'bidId': '30c77d079cdf17',
405
            'userId': {
406
              'idl_env': 'AmThEbO1ssIWjrNdU4noT4ZFBILSVBBYHbipOYt_JP40e5nZdXns2g'
407
            }
408
          }],
409
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
410
        };
411

412
        const result = bidRequestedHandler(bidRequestArgs);
1✔
413
        expect(result[0].has_envelope).to.equal(true);
1✔
414
      });
415

416
      it('should return false when userIdAsEids has liveramp source but uids is null', function () {
1✔
417
        const bidRequestArgs = {
1✔
418
          'bidderCode': 'appnexus',
419
          'auctionStart': 1580739265161,
420
          'bids': [{
421
            'bidder': 'appnexus',
422
            'bidId': '30c77d079cdf17',
423
            'userIdAsEids': [{
424
              'source': 'liveramp.com',
425
              'uids': null
426
            }]
427
          }],
428
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
429
        };
430

431
        const result = bidRequestedHandler(bidRequestArgs);
1✔
432
        expect(result[0].has_envelope).to.equal(false);
1✔
433
      });
434

435
      it('should return false when userIdAsEids has liveramp source but no uids property', function () {
1✔
436
        const bidRequestArgs = {
1✔
437
          'bidderCode': 'appnexus',
438
          'auctionStart': 1580739265161,
439
          'bids': [{
440
            'bidder': 'appnexus',
441
            'bidId': '30c77d079cdf17',
442
            'userIdAsEids': [{
443
              'source': 'liveramp.com'
444
              // No uids property
445
            }]
446
          }],
447
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
448
        };
449

450
        const result = bidRequestedHandler(bidRequestArgs);
1✔
451
        expect(result[0].has_envelope).to.equal(false);
1✔
452
      });
453

454
      it('should handle multiple userIdAsEids entries and find liveramp source', function () {
1✔
455
        const bidRequestArgs = {
1✔
456
          'bidderCode': 'appnexus',
457
          'auctionStart': 1580739265161,
458
          'bids': [{
459
            'bidder': 'appnexus',
460
            'bidId': '30c77d079cdf17',
461
            'userIdAsEids': [
462
              {
463
                'source': 'id5-sync.com',
464
                'uids': [{'id': 'id5-value'}]
465
              },
466
              {
467
                'source': 'liveramp.com',
468
                'uids': [{'id': 'liveramp-value'}]
469
              },
470
              {
471
                'source': 'criteo.com',
472
                'uids': [{'id': 'criteo-value'}]
473
              }
474
            ]
475
          }],
476
          'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7'
477
        };
478

479
        const result = bidRequestedHandler(bidRequestArgs);
1✔
480
        expect(result[0].has_envelope).to.equal(true);
1✔
481
      });
482
    })
483
  })
484
})
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