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

prebid / Prebid.js / 16279920599

14 Jul 2025 11:12PM UTC coverage: 96.2% (-0.002%) from 96.202%
16279920599

push

github

412021
web-flow
maintenance: enforce no-global-assign in tests (#13575)

39190 of 48203 branches covered (81.3%)

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

27 existing lines in 19 files now uncovered.

192751 of 200364 relevant lines covered (96.2%)

87.93 hits per line

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

86.52
/modules/yieldoneBidAdapter.js
1
import {deepAccess, isEmpty, isStr, logWarn, parseSizesInput} from '../src/utils.js';
1✔
2
import {registerBidder} from '../src/adapters/bidderFactory.js';
3
import {Renderer} from '../src/Renderer.js';
4
import {BANNER, VIDEO} from '../src/mediaTypes.js';
5
import {getBrowser, getOS} from '../libraries/userAgentUtils/index.js';
6
import {browserTypes, osTypes} from '../libraries/userAgentUtils/userAgentTypes.enums.js';
7

8
/**
9
 * @typedef {import('../src/adapters/bidderFactory').Bid} Bid
10
 * @typedef {import('../src/adapters/bidderFactory').BidRequest} BidRequest
11
 * @typedef {import('../src/adapters/bidderFactory').BidderSpec} BidderSpec
12
 * @typedef {import('../src/adapters/bidderFactory').ServerRequest} ServerRequest
13
 * @typedef {import('../src/adapters/bidderFactory').ServerResponse} ServerResponse
14
 * @typedef {import('../src/adapters/bidderFactory').SyncOptions} SyncOptions
15
 * @typedef {import('../src/adapters/bidderFactory').UserSync} UserSync
16
 * @typedef {import('../src/auction').BidderRequest} BidderRequest
17
 */
18

19
const BIDDER_CODE = 'yieldone';
1✔
20
const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid';
1✔
21
const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync';
1✔
22
const VIDEO_PLAYER_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstview/js/dac-video-prebid.min.js';
1✔
23
const CMER_PLAYER_URL = 'https://an.cmertv.com/hb/renderer/cmertv-video-yone-prebid.min.js';
1✔
24
const VIEWABLE_PERCENTAGE_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstview/js/prebid-adformat-config.js';
1✔
25

26
const DEFAULT_VIDEO_SIZE = {w: 640, h: 360};
1✔
27

28
/** @type {BidderSpec} */
29
export const spec = {
1✔
30
  code: BIDDER_CODE,
31
  aliases: ['y1'],
32
  supportedMediaTypes: [BANNER, VIDEO],
33
  /**
34
   * Determines whether or not the given bid request is valid.
35
   * @param {BidRequest} bid The bid params to validate.
36
   * @returns {boolean} True if this is a valid bid, and false otherwise.
37
   */
38
  isBidRequestValid: function(bid) {
39
    return !!(bid.params.placementId);
3✔
40
  },
41
  /**
42
   * Make a server request from the list of BidRequests.
43
   * @param {Bid[]} validBidRequests - An array of bids.
44
   * @param {BidderRequest} bidderRequest - bidder request object.
45
   * @returns {ServerRequest|ServerRequest[]} ServerRequest Info describing the request to the server.
46
   */
47
  buildRequests: function(validBidRequests, bidderRequest) {
48
    return validBidRequests.map(bidRequest => {
17✔
49
      const params = bidRequest.params;
44✔
50
      const placementId = params.placementId;
44✔
51
      const cb = Math.floor(Math.random() * 99999999999);
44✔
52
      // TODO: is 'page' the right value here?
53
      const referrer = bidderRequest.refererInfo.page;
44✔
54
      const bidId = bidRequest.bidId;
44✔
55
      const transactionId = bidRequest.ortb2Imp?.ext?.tid;
44✔
56
      const unitCode = bidRequest.adUnitCode;
44✔
57
      const timeout = bidderRequest.timeout;
44✔
58
      const language = window.navigator.language;
44✔
59
      const screenSize = window.screen.width + 'x' + window.screen.height;
44✔
60
      const payload = {
44✔
61
        v: 'hb1',
62
        p: placementId,
63
        cb: cb,
64
        r: referrer,
65
        uid: bidId,
66
        tid: transactionId,
67
        uc: unitCode,
68
        tmax: timeout,
69
        t: 'i',
70
        language: language,
71
        screen_size: screenSize
72
      };
73

74
      const mediaType = getMediaType(bidRequest);
44✔
75
      switch (mediaType) {
44!
76
        case BANNER:
77
          payload.sz = getBannerSizes(bidRequest);
35✔
78
          break;
35✔
79
        case VIDEO:
80
          const videoSize = getVideoSize(bidRequest);
9✔
81
          payload.w = videoSize.w;
9✔
82
          payload.h = videoSize.h;
9✔
83
          break;
9✔
84
        default:
85
          break;
×
86
      }
87

88
      // LiveRampID
89
      const idlEnv = deepAccess(bidRequest, 'userId.idl_env');
44✔
90
      if (isStr(idlEnv) && !isEmpty(idlEnv)) {
44✔
91
        payload.lr_env = idlEnv;
1✔
92
      }
93

94
      // IMID
95
      const imuid = deepAccess(bidRequest, 'userId.imuid');
44✔
96
      if (isStr(imuid) && !isEmpty(imuid)) {
44✔
97
        payload.imuid = imuid;
1✔
98
      }
99

100
      // DACID
101
      const fuuid = deepAccess(bidRequest, 'userId.dacId.fuuid');
44✔
102
      const dacid = deepAccess(bidRequest, 'userId.dacId.id');
44✔
103
      if (isStr(fuuid) && !isEmpty(fuuid)) {
44✔
104
        payload.fuuid = fuuid;
1✔
105
      }
106
      if (isStr(dacid) && !isEmpty(dacid)) {
44✔
107
        payload.dac_id = dacid;
1✔
108
      }
109

110
      // ID5
111
      const id5id = deepAccess(bidRequest, 'userId.id5id.uid');
44✔
112
      if (isStr(id5id) && !isEmpty(id5id)) {
44✔
113
        payload.id5Id = id5id;
1✔
114
      }
115

116
      // UID2.0
117
      const uid2 = deepAccess(bidRequest, 'userId.uid2.id');
44✔
118
      if (isStr(uid2) && !isEmpty(uid2)) {
44✔
119
        payload.uid2id = uid2;
1✔
120
      }
121

122
      // GPID
123
      const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid');
44✔
124
      if (isStr(gpid) && !isEmpty(gpid)) {
44✔
125
        payload.gpid = gpid;
1✔
126
      }
127

128
      return {
44✔
129
        method: 'GET',
130
        url: ENDPOINT_URL,
131
        data: payload,
132
      };
133
    });
134
  },
135
  /**
136
   * Unpack the response from the server into a list of bids.
137
   * @param {ServerResponse} serverResponse - A successful response from the server.
138
   * @param {BidRequest} bidRequest
139
   * @returns {Bid[]} - An array of bids which were nested inside the server.
140
   */
141
  interpretResponse: function(serverResponse, bidRequest) {
142
    const bidResponses = [];
3✔
143
    const response = serverResponse.body;
3✔
144
    const crid = response.crid || 0;
3✔
145
    const width = response.width || 0;
3✔
146
    const height = response.height || 0;
3✔
147
    const cpm = response.cpm * 1000 || 0;
3✔
148
    if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) {
3✔
149
      const dealId = response.dealId || '';
2!
150
      const renderId = response.renderid || '';
2✔
151
      const currency = response.currency || 'JPY';
2!
152
      const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
2!
153
      const referrer = bidRequest.data.r || '';
2!
154
      const bidResponse = {
2✔
155
        requestId: response.uid,
156
        cpm: cpm,
157
        width: response.width,
158
        height: response.height,
159
        creativeId: crid,
160
        dealId: dealId,
161
        currency: currency,
162
        netRevenue: netRevenue,
163
        ttl: 60,
164
        referrer: referrer,
165
        meta: {
166
          advertiserDomains: response.adomain ? response.adomain : []
2✔
167
        },
168
      };
169

170
      if (response.adTag && renderId === 'ViewableRendering') {
2!
171
        bidResponse.mediaType = BANNER;
×
172
        const viewableScript = `
×
173
        <script src="${VIEWABLE_PERCENTAGE_URL}"></script>
174
        <script>
175
        let width =${bidResponse.width};
176
        let height =${bidResponse.height};
177
        let adTag = \`${response.adTag.replace(/\\/g, '\\\\').replace(/\//g, '\\/').replace(/'/g, "\\'").replace(/"/g, '\\"')}\`;
178
        let targetId ="${bidRequest.data.uc}";
179
        window.YONEPBViewable = {};
180
        window.YONEPBViewable.executed = false;
181
        const viewablePercentage = window.pb_conf.viewablePercentage;
182
        const viewableRange = height * 0.01 * viewablePercentage;
183
        const iframe = document.createElement('iframe');
184
        iframe.setAttribute("style", "border: 0; margin: 0 auto; left: 0; top: 0; width:" + width + "px; height:" + height + "px;");
185
        iframe.frameBorder = 0; iframe.scrolling = 'no';
186
        const inDap = document.createElement('script');
187
        inDap.innerHTML = "inDapIF = true;";
188
        iframe.appendChild(inDap);
189
        window.frameElement.parentElement.appendChild(iframe);
190
        const doc = iframe.contentWindow ? iframe.contentWindow.document : iframe.contentDocument;
191
        if(!window.parent.$sf){
192
          let target = window.top.document.getElementById(targetId);
193
          window.top.addEventListener('scroll', () => {
194
              const targetRect = target.getBoundingClientRect();
195
              if (!window.YONEPBViewable.executed && window.top.innerHeight - targetRect.top > viewableRange) {
196
                  window.YONEPBViewable.executed = true;
197
                  doc.open(); doc.write(adTag); doc.close();
198
                  window.frameElement.style.display = "none";
199
              }
200
            }, false);
201
        }else{
202
          let disp = function(){
203
            if(!window.YONEPBViewable.executed && window.parent.$sf.ext.inViewPercentage() > viewablePercentage){
204
                window.YONEPBViewable.executed = true;
205
                doc.open(); doc.write(adTag); doc.close();
206
                window.frameElement.style.display = "none";
207
            }
208
            let id = setTimeout(disp, 100);
209
            if(window.YONEPBViewable.executed){clearTimeout(id);}
210
          };
211
          disp();
212
        }
213
        </script>
214
        `;
215
        bidResponse.ad = viewableScript;
×
216
      } else if (response.adTag) {
2✔
217
        bidResponse.mediaType = BANNER;
1✔
218
        bidResponse.ad = response.adTag;
1✔
219
      } else if (response.adm) {
1✔
220
        bidResponse.mediaType = VIDEO;
1✔
221
        bidResponse.vastXml = response.adm;
1✔
222
        if (renderId === 'cmer') {
1!
223
          bidResponse.renderer = newCmerRenderer(response);
×
224
        } else {
225
          bidResponse.renderer = newRenderer(response);
1✔
226
        }
227
      }
228

229
      bidResponses.push(bidResponse);
2✔
230
    }
231
    return bidResponses;
3✔
232
  },
233
  /**
234
   * Register the user sync pixels which should be dropped after the auction.
235
   * @param {SyncOptions} syncOptions Which user syncs are allowed?
236
   * @param {ServerResponse[]} serverResponses List of server's responses.
237
   * @param {Object} gdprConsent Is the GDPR Consent object wrapping gdprApplies {boolean} and consentString {string} attributes.
238
   * @returns {UserSync[]} The user syncs which should be dropped.
239
   */
240
  getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
241
    if (syncOptions.iframeEnabled && !skipSync(gdprConsent)) {
3!
UNCOV
242
      return [{
×
243
        type: 'iframe',
244
        url: USER_SYNC_URL
245
      }];
246
    }
247
  },
248
}
249

250
/**
251
 * NOTE: server side does not yet support multiple formats.
252
 * @param  {Object} bidRequest -
253
 * @param  {boolean} [enabledOldFormat = true] - default: `true`.
254
 * @returns {string|null} - `"banner"` or `"video"` or `null`.
255
 */
256
function getMediaType(bidRequest, enabledOldFormat = true) {
44!
257
  let hasBannerType = Boolean(deepAccess(bidRequest, 'mediaTypes.banner'));
44✔
258
  let hasVideoType = Boolean(deepAccess(bidRequest, 'mediaTypes.video'));
44✔
259

260
  if (enabledOldFormat) {
44✔
261
    hasBannerType = hasBannerType || bidRequest.mediaType === BANNER ||
44✔
262
      (isEmpty(bidRequest.mediaTypes) && isEmpty(bidRequest.mediaType));
263
    hasVideoType = hasVideoType || bidRequest.mediaType === VIDEO;
44✔
264
  }
265

266
  if (hasBannerType && hasVideoType) {
44✔
267
    const playerParams = deepAccess(bidRequest, 'params.playerParams');
5✔
268
    if (playerParams) {
5✔
269
      return VIDEO;
3✔
270
    } else {
271
      return BANNER;
2✔
272
    }
273
  } else if (hasBannerType) {
39✔
274
    return BANNER;
33✔
275
  } else if (hasVideoType) {
6✔
276
    return VIDEO;
6✔
277
  }
278

279
  return null;
×
280
}
281

282
/**
283
 * NOTE:
284
 *   If `mediaTypes.banner` exists, then `mediaTypes.banner.sizes` must also exist.
285
 *   The reason for this is that Prebid.js will perform the verification and
286
 *   if `mediaTypes.banner.sizes` is inappropriate, it will delete the entire `mediaTypes.banner`.
287
 * @param  {Object} bidRequest -
288
 * @param  {Object} bidRequest.banner -
289
 * @param  {Array<string>} bidRequest.banner.sizes -
290
 * @param  {boolean} [enabledOldFormat = true] - default: `true`.
291
 * @returns {string} - strings like `"300x250"` or `"300x250,728x90"`.
292
 */
293
function getBannerSizes(bidRequest, enabledOldFormat = true) {
35!
294
  let sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes');
35✔
295

296
  if (enabledOldFormat) {
35✔
297
    sizes = sizes || bidRequest.sizes;
35✔
298
  }
299

300
  return parseSizesInput(sizes).join(',');
35✔
301
}
302

303
/**
304
 * @param  {Object} bidRequest -
305
 * @param  {boolean} [enabledOldFormat = true] - default: `true`.
306
 * @param  {boolean} [enabled1x1 = true] - default: `true`.
307
 * @returns {{w: number, h: number}} -
308
 */
309
function getVideoSize(bidRequest, enabledOldFormat = true, enabled1x1 = true) {
9!
310
  /**
311
   * @param  {Array<number, number> | Array<Array<number, number>>} sizes -
312
   * @return {{w: number, h: number} | null} -
313
   */
314
  const _getPlayerSize = (sizes) => {
9✔
315
    let result = null;
15✔
316

317
    const size = parseSizesInput(sizes)[0];
15✔
318
    if (isEmpty(size)) {
15✔
319
      return result;
7✔
320
    }
321

322
    const splited = size.split('x');
8✔
323
    const sizeObj = {w: parseInt(splited[0], 10), h: parseInt(splited[1], 10)};
8✔
324
    const _isValidPlayerSize = !(isEmpty(sizeObj)) && (isFinite(sizeObj.w) && isFinite(sizeObj.h));
8✔
325
    if (!_isValidPlayerSize) {
8!
326
      return result;
×
327
    }
328

329
    result = sizeObj;
8✔
330
    return result;
8✔
331
  }
332

333
  let playerSize = _getPlayerSize(deepAccess(bidRequest, 'mediaTypes.video.playerSize'));
9✔
334

335
  if (enabledOldFormat) {
9✔
336
    playerSize = playerSize || _getPlayerSize(bidRequest.sizes);
9✔
337
  }
338

339
  if (enabled1x1) {
9✔
340
    // NOTE: `video.playerSize` in 1x1 is always [1,1].
341
    if (playerSize && (playerSize.w === 1 && playerSize.h === 1)) {
9✔
342
      // NOTE: `params.playerSize` is a specific object to support `1x1`.
343
      playerSize = _getPlayerSize(deepAccess(bidRequest, 'params.playerSize'));
2✔
344
    }
345
  }
346

347
  return playerSize || DEFAULT_VIDEO_SIZE;
9✔
348
}
349

350
/**
351
 * Create render for outstream video.
352
 * @param {Object} response -
353
 * @returns {Renderer} - Prebid Renderer object
354
 */
355
function newRenderer(response) {
356
  const renderer = Renderer.install({
1✔
357
    id: response.uid,
358
    url: VIDEO_PLAYER_URL,
359
    loaded: false,
360
  });
361

362
  try {
1✔
363
    renderer.setRender(outstreamRender);
1✔
364
  } catch (err) {
365
    logWarn('Prebid Error calling setRender on newRenderer', err);
×
366
  }
367

368
  return renderer;
1✔
369
}
370

371
/**
372
 * Handles an outstream response after the library is loaded
373
 * @param {Object} bid
374
 */
375
function outstreamRender(bid) {
376
  bid.renderer.push(() => {
×
377
    window.DACIVTPREBID.renderPrebid(bid);
×
378
  });
379
}
380

381
/**
382
 * Create render for cmer outstream video.
383
 * @param {Object} response -
384
 * @returns {Renderer} - Prebid Renderer object
385
 */
386
function newCmerRenderer(response) {
387
  const renderer = Renderer.install({
×
388
    id: response.uid,
389
    url: CMER_PLAYER_URL,
390
    loaded: false,
391
  });
392

393
  try {
×
394
    renderer.setRender(cmerRender);
×
395
  } catch (err) {
396
    logWarn('Prebid Error calling setRender on newRenderer', err);
×
397
  }
398

399
  return renderer;
×
400
}
401

402
/**
403
 * Handles an outstream response after the library is loaded
404
 * @param {Object} bid
405
 */
406
function cmerRender(bid) {
407
  bid.renderer.push(() => {
×
408
    window.CMERYONEPREBID.renderPrebid(bid);
×
409
  });
410
}
411

412
/**
413
 * Stop sending push_sync requests in case it's either Safari browser OR iOS device OR GDPR applies.
414
 * Data extracted from navigator's userAgent
415
 * @param {Object} gdprConsent Is the GDPR Consent object wrapping gdprApplies {boolean} and consentString {string} attributes.
416
 */
417
function skipSync(gdprConsent) {
418
  return (getBrowser() === browserTypes.SAFARI || getOS() === osTypes.IOS) || gdprApplies(gdprConsent);
2!
419
}
420

421
/**
422
 * Check if GDPR applies.
423
 */
424
function gdprApplies(gdprConsent) {
UNCOV
425
  return gdprConsent && typeof gdprConsent.gdprApplies === 'boolean' && gdprConsent.gdprApplies;
×
426
}
427

428
registerBidder(spec);
1✔
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