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

prebid / Prebid.js / 20272535632

16 Dec 2025 03:04PM UTC coverage: 96.208% (+0.002%) from 96.206%
20272535632

push

github

web-flow
netads alias added (#14271)

Co-authored-by: Gabriel Chicoye <gabriel@macbookrogab24g.lan>

41388 of 50926 branches covered (81.27%)

207099 of 215261 relevant lines covered (96.21%)

71.43 hits per line

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

98.2
/test/spec/modules/intentIqAnalyticsAdapter_spec.js
1
import { expect } from "chai";
2
import iiqAnalyticsAnalyticsAdapter from "modules/intentIqAnalyticsAdapter.js";
3
import * as utils from "src/utils.js";
4
import { server } from "test/mocks/xhr.js";
5
import { EVENTS } from "src/constants.js";
6
import * as events from "src/events.js";
7
import sinon from "sinon";
8
import {
9
  REPORTER_ID,
10
  preparePayload,
11
  restoreReportList,
12
} from "../../../modules/intentIqAnalyticsAdapter.js";
13
import {
14
  FIRST_PARTY_KEY,
15
  PREBID,
16
  VERSION,
17
  WITHOUT_IIQ,
18
  WITH_IIQ,
19
  AB_CONFIG_SOURCE,
20
} from "../../../libraries/intentIqConstants/intentIqConstants.js";
21
import * as detectBrowserUtils from "../../../libraries/intentIqUtils/detectBrowserUtils.js";
22
import {
23
  getReferrer,
24
  appendVrrefAndFui,
25
} from "../../../libraries/intentIqUtils/getRefferer.js";
26
import {
27
  gppDataHandler,
28
  uspDataHandler,
29
  gdprDataHandler,
30
} from "../../../src/consentHandler.js";
31

32
const partner = 10;
1✔
33
const defaultIdentityObject = {
1✔
34
  firstPartyData: {
35
    pcid: "f961ffb1-a0e1-4696-a9d2-a21d815bd344",
36
    pcidDate: 1762527405808,
37
    uspString: "undefined",
38
    gppString: "undefined",
39
    gdprString: "",
40
    date: Date.now(),
41
    sCal: Date.now() - 36000,
42
    isOptedOut: false,
43
    pid: "profile",
44
    dbsaved: "true",
45
    spd: "spd",
46
  },
47
  partnerData: {
48
    abTestUuid: "abTestUuid",
49
    adserverDeviceType: 1,
50
    clientType: 2,
51
    cttl: 43200000,
52
    date: Date.now(),
53
    profile: "profile",
54
    wsrvcll: true,
55
  },
56
  clientHints: {
57
    0: '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
58
    1: "?0",
59
    2: '"macOS"',
60
    3: '"arm"',
61
    4: '"64"',
62
    6: '"15.6.1"',
63
    7: "?0",
64
    8: '"Chromium";v="142.0.7444.60", "Google Chrome";v="142.0.7444.60", "Not_A Brand";v="99.0.0.0"',
65
  },
66
};
67
const version = VERSION;
1✔
68
const REPORT_ENDPOINT = "https://reports.intentiq.com/report";
1✔
69
const REPORT_ENDPOINT_GDPR = "https://reports-gdpr.intentiq.com/report";
1✔
70
const REPORT_SERVER_ADDRESS = "https://test-reports.intentiq.com/report";
1✔
71

72
const randomVal = () => Math.floor(Math.random() * 100000) + 1;
29✔
73

74
const getDefaultConfig = () => {
1✔
75
  return {
60✔
76
    partner,
77
    manualWinReportEnabled: false,
78
  }
79
}
80

81
const getWonRequest = () => ({
29✔
82
  bidderCode: "pubmatic",
83
  width: 728,
84
  height: 90,
85
  statusMessage: "Bid available",
86
  adId: "23caeb34c55da51",
87
  requestId: "87615b45ca4973",
88
  transactionId: "5e69fd76-8c86-496a-85ce-41ae55787a50",
89
  auctionId: "0cbd3a43-ff45-47b8-b002-16d3946b23bf-" + randomVal(),
90
  mediaType: "banner",
91
  source: "client",
92
  cpm: 5,
93
  currency: "USD",
94
  ttl: 300,
95
  referrer: "",
96
  adapterCode: "pubmatic",
97
  originalCpm: 5,
98
  originalCurrency: "USD",
99
  responseTimestamp: 1669644710345,
100
  requestTimestamp: 1669644710109,
101
  bidder: "testbidder",
102
  timeToRespond: 236,
103
  pbLg: "5.00",
104
  pbMg: "5.00",
105
  pbHg: "5.00",
106
  pbAg: "5.00",
107
  pbDg: "5.00",
108
  pbCg: "",
109
  size: "728x90",
110
  status: "rendered",
111
});
112

113
const enableAnalyticWithSpecialOptions = (receivedOptions) => {
1✔
114
  iiqAnalyticsAnalyticsAdapter.disableAnalytics();
19✔
115
  iiqAnalyticsAnalyticsAdapter.enableAnalytics({
19✔
116
    provider: "iiqAnalytics",
117
    options: {
118
      ...getDefaultConfig(),
119
      ...receivedOptions
120
    },
121
  });
122
};
123

124
describe("IntentIQ tests all", function () {
1✔
125
  let logErrorStub;
126
  let getWindowSelfStub;
127
  let getWindowTopStub;
128
  let getWindowLocationStub;
129
  let detectBrowserStub;
130

131
  beforeEach(function () {
1✔
132
    logErrorStub = sinon.stub(utils, "logError");
41✔
133
    sinon.stub(events, "getEvents").returns([]);
41✔
134
    iiqAnalyticsAnalyticsAdapter.initOptions = {
41✔
135
      lsValueInitialized: false,
136
      partner: null,
137
      fpid: null,
138
      userGroup: null,
139
      currentGroup: null,
140
      dataInLs: null,
141
      eidl: null,
142
      lsIdsInitialized: false,
143
      manualWinReportEnabled: false,
144
      domainName: null,
145
    };
146
    iiqAnalyticsAnalyticsAdapter.enableAnalytics({
41✔
147
      provider: "iiqAnalytics",
148
      options: getDefaultConfig()
149
    });
150
    if (iiqAnalyticsAnalyticsAdapter.track.restore) {
41!
151
      iiqAnalyticsAnalyticsAdapter.track.restore();
×
152
    }
153
    sinon.spy(iiqAnalyticsAnalyticsAdapter, "track");
41✔
154
    window[`iiq_identity_${partner}`] = defaultIdentityObject;
41✔
155
  });
156

157
  afterEach(function () {
1✔
158
    logErrorStub.restore();
41✔
159
    if (getWindowSelfStub) getWindowSelfStub.restore();
41✔
160
    if (getWindowTopStub) getWindowTopStub.restore();
41✔
161
    if (getWindowLocationStub) getWindowLocationStub.restore();
41✔
162
    if (detectBrowserStub) detectBrowserStub.restore();
41✔
163
    events.getEvents.restore();
41✔
164
    iiqAnalyticsAnalyticsAdapter.disableAnalytics();
41✔
165
    if (iiqAnalyticsAnalyticsAdapter.track.restore) {
41✔
166
      iiqAnalyticsAnalyticsAdapter.track.restore();
41✔
167
    }
168
    localStorage.clear();
41✔
169
    server.reset();
41✔
170
    delete window[`iiq_identity_${partner}`]
41✔
171
  });
172

173
  it("should send POST request with payload in request body if reportMethod is POST", function () {
1✔
174
    enableAnalyticWithSpecialOptions({
1✔
175
      reportMethod: "POST",
176
    });
177
    const wonRequest = getWonRequest();
1✔
178

179
    events.emit(EVENTS.BID_WON, wonRequest);
1✔
180

181
    const request = server.requests[0];
1✔
182
    restoreReportList();
1✔
183

184
    const expectedData = preparePayload(wonRequest);
1✔
185
    const expectedPayload = `["${btoa(JSON.stringify(expectedData))}"]`;
1✔
186

187
    expect(request.method).to.equal("POST");
1✔
188
    expect(request.requestBody).to.equal(expectedPayload);
1✔
189
  });
190

191
  it("should send GET request with payload in query string if reportMethod is NOT provided", function () {
1✔
192
    const wonRequest = getWonRequest();
1✔
193

194
    events.emit(EVENTS.BID_WON, wonRequest);
1✔
195

196
    const request = server.requests[0];
1✔
197

198
    expect(request.method).to.equal("GET");
1✔
199

200
    const url = new URL(request.url);
1✔
201
    const payloadEncoded = url.searchParams.get("payload");
1✔
202
    const decoded = JSON.parse(atob(JSON.parse(payloadEncoded)[0]));
1✔
203

204
    restoreReportList();
1✔
205
    const expected = preparePayload(wonRequest);
1✔
206

207
    expect(decoded.partnerId).to.equal(expected.partnerId);
1✔
208
    expect(decoded.adType).to.equal(expected.adType);
1✔
209
    expect(decoded.prebidAuctionId).to.equal(expected.prebidAuctionId);
1✔
210
  });
211

212
  it("IIQ Analytical Adapter bid win report", function () {
1✔
213
    getWindowLocationStub = sinon
1✔
214
      .stub(utils, "getWindowLocation")
215
      .returns({ href: "http://localhost:9876" });
216
    const expectedVrref = getWindowLocationStub().href;
1✔
217
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
218

219
    expect(server.requests.length).to.be.above(0);
1✔
220
    const request = server.requests[0];
1✔
221
    const parsedUrl = new URL(request.url);
1✔
222
    const vrref = parsedUrl.searchParams.get("vrref");
1✔
223
    expect(request.url).to.contain(
1✔
224
      REPORT_ENDPOINT + "?pid=" + partner + "&mct=1"
225
    );
226
    expect(request.url).to.contain(`&jsver=${version}`);
1✔
227
    expect(`&vrref=${decodeURIComponent(vrref)}`).to.contain(
1✔
228
      `&vrref=${expectedVrref}`
229
    );
230
    expect(request.url).to.contain("&payload=");
1✔
231
    expect(request.url).to.contain(
1✔
232
      "iiqid=f961ffb1-a0e1-4696-a9d2-a21d815bd344"
233
    );
234
  });
235

236
  it("should include adType in payload when present in BID_WON event", function () {
1✔
237
    getWindowLocationStub = sinon
1✔
238
      .stub(utils, "getWindowLocation")
239
      .returns({ href: "http://localhost:9876/" });
240
    const bidWonEvent = { ...getWonRequest(), mediaType: "video" };
1✔
241

242
    events.emit(EVENTS.BID_WON, bidWonEvent);
1✔
243

244
    const request = server.requests[0];
1✔
245
    const urlParams = new URL(request.url);
1✔
246
    const payloadEncoded = urlParams.searchParams.get("payload");
1✔
247
    const payloadDecoded = JSON.parse(atob(JSON.parse(payloadEncoded)[0]));
1✔
248

249
    expect(server.requests.length).to.be.above(0);
1✔
250
    expect(payloadDecoded).to.have.property("adType", bidWonEvent.mediaType);
1✔
251
  });
252

253
  it("should include adType in payload when present in reportExternalWin event", function () {
1✔
254
    enableAnalyticWithSpecialOptions({ manualWinReportEnabled: true });
1✔
255
    getWindowLocationStub = sinon
1✔
256
      .stub(utils, "getWindowLocation")
257
      .returns({ href: "http://localhost:9876/" });
258
    const externalWinEvent = { cpm: 1, currency: "USD", adType: "banner" };
1✔
259

260
    events.emit(EVENTS.BID_REQUESTED);
1✔
261

262
    window[`intentIqAnalyticsAdapter_${partner}`].reportExternalWin(
1✔
263
      externalWinEvent
264
    );
265

266
    const request = server.requests[0];
1✔
267
    const urlParams = new URL(request.url);
1✔
268
    const payloadEncoded = urlParams.searchParams.get("payload");
1✔
269
    const payloadDecoded = JSON.parse(atob(JSON.parse(payloadEncoded)[0]));
1✔
270

271
    expect(server.requests.length).to.be.above(0);
1✔
272
    expect(payloadDecoded).to.have.property("adType", externalWinEvent.adType);
1✔
273
  });
274

275
  it("should send report to report-gdpr address if gdpr is detected", function () {
1✔
276
    const gppStub = sinon
1✔
277
      .stub(gppDataHandler, "getConsentData")
278
      .returns({ gppString: '{"key1":"value1","key2":"value2"}' });
279
    const uspStub = sinon
1✔
280
      .stub(uspDataHandler, "getConsentData")
281
      .returns("1NYN");
282
    const gdprStub = sinon
1✔
283
      .stub(gdprDataHandler, "getConsentData")
284
      .returns({ consentString: "gdprConsent" });
285

286
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
287

288
    expect(server.requests.length).to.be.above(0);
1✔
289
    const request = server.requests[0];
1✔
290

291
    expect(request.url).to.contain(REPORT_ENDPOINT_GDPR);
1✔
292
    gppStub.restore();
1✔
293
    uspStub.restore();
1✔
294
    gdprStub.restore();
1✔
295
  });
296

297
  it("should initialize with default configurations", function () {
1✔
298
    expect(iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized).to.be
1✔
299
      .false;
300
  });
301

302
  it("should handle BID_WON event with group configuration from local storage", function () {
1✔
303
    window[`iiq_identity_${partner}`].firstPartyData = {
1✔
304
      ...window[`iiq_identity_${partner}`].firstPartyData,
305
      group: "B",
306
    };
307

308
    const expectedVrref = encodeURIComponent("http://localhost:9876/");
1✔
309

310
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
311

312
    expect(server.requests.length).to.be.above(0);
1✔
313
    const request = server.requests[0];
1✔
314
    expect(request.url).to.contain(
1✔
315
      "https://reports.intentiq.com/report?pid=" + partner + "&mct=1"
316
    );
317
    expect(request.url).to.contain(`&jsver=${version}`);
1✔
318
    expect(request.url).to.contain(`&vrref=${expectedVrref}`);
1✔
319
  });
320

321
  it("should handle BID_WON event with default group configuration", function () {
1✔
322
    const wonRequest = getWonRequest();
1✔
323

324
    events.emit(EVENTS.BID_WON, wonRequest);
1✔
325

326
    expect(server.requests.length).to.be.above(0);
1✔
327
    const request = server.requests[0];
1✔
328
    restoreReportList();
1✔
329
    const dataToSend = preparePayload(wonRequest);
1✔
330
    const base64String = btoa(JSON.stringify(dataToSend));
1✔
331
    const payload = encodeURIComponent(JSON.stringify([base64String]));
1✔
332
    const expectedUrl = appendVrrefAndFui(
1✔
333
      REPORT_ENDPOINT +
334
        `?pid=${partner}&mct=1&iiqid=${defaultIdentityObject.firstPartyData.pcid}&agid=${REPORTER_ID}&jsver=${version}&source=pbjs&uh=&gdpr=0&spd=spd`,
335
      iiqAnalyticsAnalyticsAdapter.initOptions.domainName
336
    );
337
    const urlWithPayload = expectedUrl + `&payload=${payload}`;
1✔
338

339
    expect(request.url).to.equal(urlWithPayload);
1✔
340
    expect(dataToSend.pcid).to.equal(defaultIdentityObject.firstPartyData.pcid);
1✔
341
  });
342

343
  it("should send CMP data in report if available", function () {
1✔
344
    const uspData = "1NYN";
1✔
345
    const gppData = { gppString: '{"key1":"value1","key2":"value2"}' };
1✔
346
    const gdprData = { consentString: "gdprConsent" };
1✔
347

348
    const gppStub = sinon
1✔
349
      .stub(gppDataHandler, "getConsentData")
350
      .returns(gppData);
351
    const uspStub = sinon
1✔
352
      .stub(uspDataHandler, "getConsentData")
353
      .returns(uspData);
354
    const gdprStub = sinon
1✔
355
      .stub(gdprDataHandler, "getConsentData")
356
      .returns(gdprData);
357

358
    getWindowLocationStub = sinon
1✔
359
      .stub(utils, "getWindowLocation")
360
      .returns({ href: "http://localhost:9876/" });
361

362
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
363

364
    expect(server.requests.length).to.be.above(0);
1✔
365
    const request = server.requests[0];
1✔
366

367
    expect(request.url).to.contain(
1✔
368
      `&us_privacy=${encodeURIComponent(uspData)}`
369
    );
370
    expect(request.url).to.contain(
1✔
371
      `&gpp=${encodeURIComponent(gppData.gppString)}`
372
    );
373
    expect(request.url).to.contain(
1✔
374
      `&gdpr_consent=${encodeURIComponent(gdprData.consentString)}`
375
    );
376
    expect(request.url).to.contain(`&gdpr=1`);
1✔
377
    gppStub.restore();
1✔
378
    uspStub.restore();
1✔
379
    gdprStub.restore();
1✔
380
  });
381

382
  it("should not send request if manualWinReportEnabled is true", function () {
1✔
383
    iiqAnalyticsAnalyticsAdapter.initOptions.manualWinReportEnabled = true;
1✔
384
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
385
    expect(server.requests.length).to.equal(0);
1✔
386
  });
387

388
  it("should handle initialization values from local storage", function () {
1✔
389
    window[`iiq_identity_${partner}`].actualABGroup = WITHOUT_IIQ;
1✔
390

391
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
392
    expect(iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup).to.equal(
1✔
393
      WITHOUT_IIQ
394
    );
395
    expect(iiqAnalyticsAnalyticsAdapter.initOptions.fpid).to.be.not.null;
1✔
396
  });
397

398
  it("should handle reportExternalWin", function () {
1✔
399
    events.emit(EVENTS.BID_REQUESTED);
1✔
400
    iiqAnalyticsAnalyticsAdapter.initOptions.manualWinReportEnabled = false;
1✔
401
    expect(
1✔
402
      window[`intentIqAnalyticsAdapter_${partner}`].reportExternalWin
403
    ).to.be.a("function");
404
    expect(
1✔
405
      window[`intentIqAnalyticsAdapter_${partner}`].reportExternalWin({
406
        cpm: 1,
407
        currency: "USD",
408
      })
409
    ).to.equal(false);
410
  });
411

412
  it("should return window.location.href when window.self === window.top", function () {
1✔
413
    // Stub helper functions
414
    getWindowSelfStub = sinon.stub(utils, "getWindowSelf").returns(window);
1✔
415
    getWindowTopStub = sinon.stub(utils, "getWindowTop").returns(window);
1✔
416
    getWindowLocationStub = sinon
1✔
417
      .stub(utils, "getWindowLocation")
418
      .returns({ href: "http://localhost:9876/" });
419

420
    const referrer = getReferrer();
1✔
421
    expect(referrer).to.equal("http://localhost:9876/");
1✔
422
  });
423

424
  it("should return window.top.location.href when window.self !== window.top and access is successful", function () {
1✔
425
    // Stub helper functions to simulate iframe
426
    getWindowSelfStub = sinon.stub(utils, "getWindowSelf").returns({});
1✔
427
    getWindowTopStub = sinon
1✔
428
      .stub(utils, "getWindowTop")
429
      .returns({ location: { href: "http://example.com/" } });
430

431
    const referrer = getReferrer();
1✔
432

433
    expect(referrer).to.equal("http://example.com/");
1✔
434
  });
435

436
  it("should return an empty string and log an error when accessing window.top.location.href throws an error", function () {
1✔
437
    // Stub helper functions to simulate error
438
    getWindowSelfStub = sinon.stub(utils, "getWindowSelf").returns({});
1✔
439
    getWindowTopStub = sinon
1✔
440
      .stub(utils, "getWindowTop")
441
      .throws(new Error("Access denied"));
442

443
    const referrer = getReferrer();
1✔
444
    expect(referrer).to.equal("");
1✔
445
    expect(logErrorStub.calledOnce).to.be.true;
1✔
446
    expect(logErrorStub.firstCall.args[0]).to.contain(
1✔
447
      "Error accessing location: Error: Access denied"
448
    );
449
  });
450

451
  it("should not send request if the browser is in blacklist (chrome)", function () {
1✔
452
    enableAnalyticWithSpecialOptions({
1✔
453
      browserBlackList: "ChrOmE"
454
    })
455
    detectBrowserStub = sinon
1✔
456
      .stub(detectBrowserUtils, "detectBrowser")
457
      .returns("chrome");
458

459
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
460

461
    expect(server.requests.length).to.equal(0);
1✔
462
  });
463

464
  it("should send request if the browser is not in blacklist (safari)", function () {
1✔
465
    enableAnalyticWithSpecialOptions({
1✔
466
      browserBlackList: "chrome,firefox"
467
    })
468

469
    detectBrowserStub = sinon
1✔
470
      .stub(detectBrowserUtils, "detectBrowser")
471
      .returns("safari");
472

473
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
474

475
    expect(server.requests.length).to.be.above(0);
1✔
476
    const request = server.requests[0];
1✔
477
    expect(request.url).to.contain(
1✔
478
      `https://reports.intentiq.com/report?pid=${partner}&mct=1`
479
    );
480
    expect(request.url).to.contain(`&jsver=${version}`);
1✔
481
    expect(request.url).to.contain(
1✔
482
      `&vrref=${encodeURIComponent("http://localhost:9876/")}`
483
    );
484
    expect(request.url).to.contain("&payload=");
1✔
485
    expect(request.url).to.contain(
1✔
486
      "iiqid=f961ffb1-a0e1-4696-a9d2-a21d815bd344"
487
    );
488
  });
489

490
  it("should send request in reportingServerAddress no gdpr", function () {
1✔
491
    detectBrowserStub = sinon
1✔
492
      .stub(detectBrowserUtils, "detectBrowser")
493
      .returns("safari");
494
    enableAnalyticWithSpecialOptions({
1✔
495
      reportingServerAddress: REPORT_SERVER_ADDRESS,
496
      browserBlackList: "chrome,firefox"
497
    });
498

499
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
500

501
    expect(server.requests.length).to.be.above(0);
1✔
502
    const request = server.requests[0];
1✔
503
    expect(request.url).to.contain(REPORT_SERVER_ADDRESS);
1✔
504
  });
505

506
  it("should include source parameter in report URL", function () {
1✔
507
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
508
    const request = server.requests[0];
1✔
509

510
    expect(server.requests.length).to.be.above(0);
1✔
511
    expect(request.url).to.include(`&source=${PREBID}`);
1✔
512
  });
513

514
  it("should send additionalParams in report if valid and small enough", function () {
1✔
515
    enableAnalyticWithSpecialOptions({
1✔
516
      additionalParams: [
517
        {
518
          parameterName: "general",
519
          parameterValue: "Lee",
520
          destination: [0, 0, 1],
521
        },
522
      ]
523
    })
524

525
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
526

527
    const request = server.requests[0];
1✔
528
    expect(request.url).to.include("general=Lee");
1✔
529
  });
530

531
  it("should not send additionalParams in report if value is too large", function () {
1✔
532
    const longVal = "x".repeat(5000000);
1✔
533

534
    enableAnalyticWithSpecialOptions({
1✔
535
      additionalParams: [
536
        {
537
          parameterName: "general",
538
          parameterValue: longVal,
539
          destination: [0, 0, 1],
540
        },
541
      ]
542
    })
543

544
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
545

546
    const request = server.requests[0];
1✔
547
    expect(request.url).not.to.include("general");
1✔
548
  });
549

550
  it("should include spd parameter from LS in report URL", function () {
1✔
551
    const spdObject = { foo: "bar", value: 42 };
1✔
552
    const expectedSpdEncoded = encodeURIComponent(JSON.stringify(spdObject));
1✔
553
    window[`iiq_identity_${partner}`].firstPartyData.spd =
1✔
554
      JSON.stringify(spdObject);
555

556
    getWindowLocationStub = sinon
1✔
557
      .stub(utils, "getWindowLocation")
558
      .returns({ href: "http://localhost:9876/" });
559

560
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
561

562
    const request = server.requests[0];
1✔
563

564
    expect(server.requests.length).to.be.above(0);
1✔
565
    expect(request.url).to.include(`&spd=${expectedSpdEncoded}`);
1✔
566
  });
567

568
  it("should include spd parameter string from LS in report URL", function () {
1✔
569
    const spdData = "server provided data";
1✔
570
    const expectedSpdEncoded = encodeURIComponent(spdData);
1✔
571
    window[`iiq_identity_${partner}`].firstPartyData.spd = spdData;
1✔
572

573
    getWindowLocationStub = sinon
1✔
574
      .stub(utils, "getWindowLocation")
575
      .returns({ href: "http://localhost:9876/" });
576

577
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
578

579
    const request = server.requests[0];
1✔
580

581
    expect(server.requests.length).to.be.above(0);
1✔
582
    expect(request.url).to.include(`&spd=${expectedSpdEncoded}`);
1✔
583
  });
584

585
  describe("GAM prediction reporting", function () {
1✔
586
    function createMockGAM() {
587
      const listeners = {};
2✔
588
      return {
2✔
589
        cmd: [],
590
        pubads: () => ({
1✔
591
          addEventListener: (name, cb) => {
592
            listeners[name] = cb;
1✔
593
          },
594
        }),
595
        _listeners: listeners,
596
      };
597
    }
598

599
    it("should subscribe to GAM and send report on slotRenderEnded without prior bidWon", function () {
1✔
600
      const gam = createMockGAM();
1✔
601

602
      enableAnalyticWithSpecialOptions({
1✔
603
        gamObjectReference: gam
604
      })
605

606
      // enable subscription by LS flag
607
      window[`iiq_identity_${partner}`].partnerData.gpr = true;
1✔
608

609
      // provide recent auctionEnd with matching bid to enrich payload
610
      events.getEvents.restore();
1✔
611
      sinon.stub(events, "getEvents").returns([
1✔
612
        {
613
          eventType: "auctionEnd",
614
          args: {
615
            auctionId: "auc-1",
616
            adUnitCodes: ["ad-unit-1"],
617
            bidsReceived: [
618
              {
619
                bidder: "pubmatic",
620
                adUnitCode: "ad-unit-1",
621
                cpm: 1,
622
                currency: "USD",
623
                originalCpm: 1,
624
                originalCurrency: "USD",
625
                status: "rendered",
626
              },
627
            ],
628
          },
629
        },
630
      ]);
631

632
      // trigger adapter to subscribe
633
      events.emit(EVENTS.BID_REQUESTED);
1✔
634

635
      // execute GAM cmd to register listener
636
      gam.cmd.forEach((fn) => fn());
1✔
637

638
      // simulate slotRenderEnded
639
      const slot = {
1✔
640
        getSlotElementId: () => "ad-unit-1",
1✔
641
        getAdUnitPath: () => "/123/foo",
1✔
642
        getTargetingKeys: () => ["hb_bidder", "hb_adid"],
1✔
643
        getTargeting: (k) =>
644
          k === "hb_bidder" ? ["pubmatic"] : k === "hb_adid" ? ["ad123"] : [],
2!
645
      };
646
      if (gam._listeners["slotRenderEnded"]) {
1✔
647
        gam._listeners["slotRenderEnded"]({ isEmpty: false, slot });
1✔
648
      }
649

650
      expect(server.requests.length).to.be.above(0);
1✔
651
    });
652

653
    it("should NOT send report if a matching bidWon already exists", function () {
1✔
654
      const gam = createMockGAM();
1✔
655

656
      localStorage.setItem(
1✔
657
        FIRST_PARTY_KEY + "_" + partner,
658
        JSON.stringify({ gpr: true })
659
      );
660

661
      // provide prior bidWon matching placementId and hb_adid
662
      events.getEvents.restore();
1✔
663
      sinon
1✔
664
        .stub(events, "getEvents")
665
        .returns([
666
          { eventType: "bidWon", args: { adId: "ad123" }, id: "ad-unit-1" },
667
        ]);
668

669
      events.emit(EVENTS.BID_REQUESTED);
1✔
670
      gam.cmd.forEach((fn) => fn());
1✔
671

672
      const slot = {
1✔
673
        getSlotElementId: () => "ad-unit-1",
×
674
        getAdUnitPath: () => "/123/foo",
×
675
        getTargetingKeys: () => ["hb_bidder", "hb_adid"],
×
676
        getTargeting: (k) =>
677
          k === "hb_bidder" ? ["pubmatic"] : k === "hb_adid" ? ["ad123"] : [],
×
678
      };
679

680
      const initialRequests = server.requests.length;
1✔
681
      if (gam._listeners["slotRenderEnded"]) {
1!
682
        gam._listeners["slotRenderEnded"]({ isEmpty: false, slot });
×
683
      }
684
      expect(server.requests.length).to.equal(initialRequests);
1✔
685
    });
686
  });
687

688
  const testCasesVrref = [
1✔
689
    {
690
      description: "domainName matches window.top.location.href",
691
      getWindowSelf: {},
692
      getWindowTop: { location: { href: "http://example.com/page" } },
693
      getWindowLocation: { href: "http://example.com/page" },
694
      domainName: "example.com",
695
      expectedVrref: encodeURIComponent("http://example.com/page"),
696
      shouldContainFui: false,
697
    },
698
    {
699
      description: "domainName does not match window.top.location.href",
700
      getWindowSelf: {},
701
      getWindowTop: { location: { href: "http://anotherdomain.com/page" } },
702
      getWindowLocation: { href: "http://anotherdomain.com/page" },
703
      domainName: "example.com",
704
      expectedVrref: encodeURIComponent("example.com"),
705
      shouldContainFui: false,
706
    },
707
    {
708
      description: "domainName is missing, only fui=1 is returned",
709
      getWindowSelf: {},
710
      getWindowTop: { location: { href: "" } },
711
      getWindowLocation: { href: "" },
712
      domainName: null,
713
      expectedVrref: "",
714
      shouldContainFui: true,
715
    },
716
    {
717
      description: "domainName is missing",
718
      getWindowSelf: {},
719
      getWindowTop: { location: { href: "http://example.com/page" } },
720
      getWindowLocation: { href: "http://example.com/page" },
721
      domainName: null,
722
      expectedVrref: encodeURIComponent("http://example.com/page"),
723
      shouldContainFui: false,
724
    },
725
  ];
726

727
  testCasesVrref.forEach(
1✔
728
    ({
729
      description,
730
      getWindowSelf,
731
      getWindowTop,
732
      getWindowLocation,
733
      domainName,
734
      expectedVrref,
735
      shouldContainFui,
736
    }) => {
4✔
737
      it(`should append correct vrref when ${description}`, function () {
4✔
738
        getWindowSelfStub = sinon
4✔
739
          .stub(utils, "getWindowSelf")
740
          .returns(getWindowSelf);
741
        getWindowTopStub = sinon
4✔
742
          .stub(utils, "getWindowTop")
743
          .returns(getWindowTop);
744
        getWindowLocationStub = sinon
4✔
745
          .stub(utils, "getWindowLocation")
746
          .returns(getWindowLocation);
747

748
        const url = "https://reports.intentiq.com/report?pid=10";
4✔
749
        const modifiedUrl = appendVrrefAndFui(url, domainName);
4✔
750
        const urlObj = new URL(modifiedUrl);
4✔
751

752
        const vrref = encodeURIComponent(
4✔
753
          urlObj.searchParams.get("vrref") || ""
5✔
754
        );
755
        const fui = urlObj.searchParams.get("fui");
4✔
756

757
        expect(vrref).to.equal(expectedVrref);
4✔
758
        expect(urlObj.searchParams.has("fui")).to.equal(shouldContainFui);
4✔
759
        if (shouldContainFui) {
4✔
760
          expect(fui).to.equal("1");
1✔
761
        }
762
      });
763
    }
764
  );
765

766
  const adUnitConfigTests = [
1✔
767
    {
768
      adUnitConfig: 1,
769
      description: "should extract adUnitCode first (adUnitConfig = 1)",
770
      event: { adUnitCode: "adUnitCode-123", placementId: "placementId-456" },
771
      expectedPlacementId: "adUnitCode-123",
772
    },
773
    {
774
      adUnitConfig: 1,
775
      description:
776
        "should extract placementId if there is no adUnitCode (adUnitConfig = 1)",
777
      event: { placementId: "placementId-456" },
778
      expectedPlacementId: "placementId-456",
779
    },
780
    {
781
      adUnitConfig: 2,
782
      description: "should extract placementId first (adUnitConfig = 2)",
783
      event: { adUnitCode: "adUnitCode-123", placementId: "placementId-456" },
784
      expectedPlacementId: "placementId-456",
785
    },
786
    {
787
      adUnitConfig: 2,
788
      description:
789
        "should extract adUnitCode if there is no placementId (adUnitConfig = 2)",
790
      event: { adUnitCode: "adUnitCode-123" },
791
      expectedPlacementId: "adUnitCode-123",
792
    },
793
    {
794
      adUnitConfig: 3,
795
      description: "should extract only adUnitCode (adUnitConfig = 3)",
796
      event: { adUnitCode: "adUnitCode-123", placementId: "placementId-456" },
797
      expectedPlacementId: "adUnitCode-123",
798
    },
799
    {
800
      adUnitConfig: 4,
801
      description: "should extract only placementId (adUnitConfig = 4)",
802
      event: { adUnitCode: "adUnitCode-123", placementId: "placementId-456" },
803
      expectedPlacementId: "placementId-456",
804
    },
805
    {
806
      adUnitConfig: 1,
807
      description:
808
        "should return empty placementId if neither adUnitCode or placementId exist",
809
      event: {},
810
      expectedPlacementId: "",
811
    },
812
    {
813
      adUnitConfig: 1,
814
      description:
815
        "should extract placementId from params array if no top-level adUnitCode or placementId exist (adUnitConfig = 1)",
816
      event: {
817
        params: [{ someKey: "value" }, { placementId: "nested-placementId" }],
818
      },
819
      expectedPlacementId: "nested-placementId",
820
    },
821
  ];
822

823
  adUnitConfigTests.forEach(
1✔
824
    ({ adUnitConfig, description, event, expectedPlacementId }) => {
8✔
825
      it(description, function () {
8✔
826
        enableAnalyticWithSpecialOptions({ adUnitConfig });
8✔
827

828
        const testEvent = { ...getWonRequest(), ...event };
8✔
829
        events.emit(EVENTS.BID_WON, testEvent);
8✔
830

831
        const request = server.requests[0];
8✔
832
        const urlParams = new URL(request.url);
8✔
833
        const encodedPayload = urlParams.searchParams.get("payload");
8✔
834
        const decodedPayload = JSON.parse(atob(JSON.parse(encodedPayload)[0]));
8✔
835

836
        expect(server.requests.length).to.be.above(0);
8✔
837
        expect(encodedPayload).to.exist;
8✔
838
        expect(decodedPayload).to.have.property(
8✔
839
          "placementId",
840
          expectedPlacementId
841
        );
842
      });
843
    }
844
  );
845

846
  it("should include ABTestingConfigurationSource in payload when provided", function () {
1✔
847
    const ABTestingConfigurationSource = "percentage";
1✔
848
    enableAnalyticWithSpecialOptions({ ABTestingConfigurationSource });
1✔
849

850
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
851

852
    const request = server.requests[0];
1✔
853
    const urlParams = new URL(request.url);
1✔
854
    const encodedPayload = urlParams.searchParams.get("payload");
1✔
855
    const decodedPayload = JSON.parse(atob(JSON.parse(encodedPayload)[0]));
1✔
856

857
    expect(server.requests.length).to.be.above(0);
1✔
858
    expect(decodedPayload).to.have.property(
1✔
859
      "ABTestingConfigurationSource",
860
      ABTestingConfigurationSource
861
    );
862
  });
863

864
  it("should not include ABTestingConfigurationSource in payload when not provided", function () {
1✔
865
    enableAnalyticWithSpecialOptions({});
1✔
866

867
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
868

869
    const request = server.requests[0];
1✔
870
    const urlParams = new URL(request.url);
1✔
871
    const encodedPayload = urlParams.searchParams.get("payload");
1✔
872
    const decodedPayload = JSON.parse(atob(JSON.parse(encodedPayload)[0]));
1✔
873

874
    expect(server.requests.length).to.be.above(0);
1✔
875
    expect(decodedPayload).to.not.have.property("ABTestingConfigurationSource");
1✔
876
  });
877

878
  it("should use group from provided options when ABTestingConfigurationSource is 'group'", function () {
1✔
879
    const providedGroup = WITHOUT_IIQ;
1✔
880
    // Ensure actualABGroup is not set so group from options is used
881
    delete window[`iiq_identity_${partner}`].actualABGroup;
1✔
882

883
    enableAnalyticWithSpecialOptions({
1✔
884
      group: providedGroup,
885
      ABTestingConfigurationSource: AB_CONFIG_SOURCE.GROUP,
886
    });
887

888
    events.emit(EVENTS.BID_WON, getWonRequest());
1✔
889

890
    const request = server.requests[0];
1✔
891
    const urlParams = new URL(request.url);
1✔
892
    const encodedPayload = urlParams.searchParams.get("payload");
1✔
893
    const decodedPayload = JSON.parse(atob(JSON.parse(encodedPayload)[0]));
1✔
894

895
    expect(server.requests.length).to.be.above(0);
1✔
896
    // Verify that the group from options is used in the payload
897
    expect(decodedPayload).to.have.property("abGroup", providedGroup);
1✔
898
  });
899
});
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