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

prebid / Prebid.js / 19437775255

17 Nov 2025 05:00PM UTC coverage: 96.213% (-0.02%) from 96.231%
19437775255

push

github

web-flow
sevioBidAdapter_bugfix: Send all sizes instead of just maxSize (#14133)

* Send all sizes instead of just maxSize

* Added tests to cover modifs in the sizes that we are sending

53222 of 65234 branches covered (81.59%)

10 of 10 new or added lines in 2 files covered. (100.0%)

304 existing lines in 58 files now uncovered.

202715 of 210693 relevant lines covered (96.21%)

71.77 hits per line

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

87.67
/modules/videoModule/index.ts
1
import {config} from '../../src/config.js';
1✔
2
import * as events from '../../src/events.js';
3
import {logError, logWarn, mergeDeep} from '../../src/utils.js';
4
import {getGlobal} from '../../src/prebidGlobal.js';
5
import {EVENTS} from '../../src/constants.js';
6
import {
7
  AD_ERROR,
8
  AD_IMPRESSION,
9
  additionalEvents,
10
  AUCTION_AD_LOAD_ABORT,
11
  BID_ERROR,
12
  BID_IMPRESSION,
13
  videoEvents
14
} from '../../libraries/video/constants/events.js'
15
import {PLACEMENT} from '../../libraries/video/constants/ortb.js';
16
import {videoKey} from '../../libraries/video/constants/constants.js'
17
import {videoCoreFactory} from './coreVideo.js';
18
import {gamSubmoduleFactory} from './gamAdServerSubmodule.js';
19
import {videoImpressionVerifierFactory} from './videoImpressionVerifier.js';
20
import {AdQueueCoordinator} from './adQueue.js';
21
import {getExternalVideoEventName, getExternalVideoEventPayload} from '../../libraries/video/shared/helpers.js'
22
import {VIDEO} from '../../src/mediaTypes.js';
23
import {auctionManager} from '../../src/auctionManager.js';
24
import {doRender} from '../../src/adRendering.js';
25
import {getHook} from '../../src/hook.js';
26
import {type VideoBid} from '../../src/bidfactory.js';
27
import type {BidderCode} from "../../src/types/common.d.ts";
28
import type {ORTBImp, ORTBRequest} from "../../src/types/ortb/request.d.ts";
29
import type {DeepPartial} from "../../src/types/objects.d.ts";
30
import type {AdServerVendor} from "../../libraries/video/constants/vendorCodes.ts";
31
import type {VideoEvent} from "../../libraries/video/constants/events.ts";
32

33
const allVideoEvents = Object.keys(videoEvents).map(eventKey => videoEvents[eventKey]);
37✔
34

35
events.addEvents(allVideoEvents.concat(additionalEvents).map(getExternalVideoEventName) as any);
1✔
36

37
declare module '../../src/events' {
38
  interface EventNames {
39
    video: VideoEvent
40
  }
41
}
42

43
interface AdServerConfig {
44
  /**
45
   * The identifier of the AdServer vendor (i.e. gam, etc).
46
   */
47
  vendorCode: AdServerVendor
48
  /**
49
   * Your AdServer Ad Tag. The targeting params of the winning bid will be appended.
50
   */
51
  baseAdTagUrl?: string;
52
  /**
53
   * Querystring parameters that will be used to construct the video ad tag URL.
54
   */
55
  params?: Record<string, string>;
56
}
57

58
interface AdUnitVideoOptions {
59
  /**
60
   * Unique identifier of the player provider, used to specify which player should be used to render the ad.
61
   * Equivalent to the HTML Div Id of the player.
62
   */
63
  divId: string;
64
  /**
65
   * Configuration for ad server integration. Supersedes video.adServer configurations defined in the Prebid Config.
66
   */
67
  adServer?: AdServerConfig
68
}
69

70
declare module '../../src/adUnits' {
71
  interface AdUnitDefinition {
72
    video?: AdUnitVideoOptions
73
  }
74
}
75

76
/**
77
 * This module adds User Video support to prebid.js
78
 * @module modules/videoModule
79
 */
80
export function PbVideo(videoCore_, getConfig_, pbGlobal_, requestBids_, pbEvents_, videoEvents_, gamAdServerFactory_, videoImpressionVerifierFactory_, adQueueCoordinator_) {
81
  const videoCore = videoCore_;
18✔
82
  const getConfig = getConfig_;
18✔
83
  const pbGlobal = pbGlobal_;
18✔
84
  const requestBids = requestBids_;
18✔
85
  const pbEvents = pbEvents_;
18✔
86
  const videoEvents = videoEvents_;
18✔
87
  const gamAdServerFactory = gamAdServerFactory_;
18✔
88
  const adQueueCoordinator = adQueueCoordinator_;
18✔
89
  let gamSubmodule;
90
  let mainContentDivId;
91
  let contentEnrichmentEnabled = true;
18✔
92
  const videoImpressionVerifierFactory = videoImpressionVerifierFactory_;
18✔
93
  let videoImpressionVerifier;
94

95
  function init() {
96
    const cache = getConfig('cache');
18✔
97
    videoImpressionVerifier = videoImpressionVerifierFactory(!!cache);
18✔
98
    getConfig(videoKey, ({ video }) => {
18✔
99
      video.providers.forEach(provider => {
8✔
100
        const divId = provider.divId;
16✔
101
        videoCore.registerProvider(provider);
16✔
102
        adQueueCoordinator.registerProvider(divId);
16✔
103
        videoCore.initProvider(divId);
16✔
104
        videoCore.onEvents(videoEvents, (type, payload) => {
16✔
105
          pbEvents.emit(getExternalVideoEventName(type), getExternalVideoEventPayload(type, payload));
1✔
106
        }, divId);
107

108
        const adServerConfig = provider.adServer;
16✔
109
        if (!gamSubmodule && adServerConfig) {
16✔
110
          gamSubmodule = gamAdServerFactory();
8✔
111
        }
112
      });
113
      contentEnrichmentEnabled = video.contentEnrichmentEnabled !== false;
8✔
114
      mainContentDivId = contentEnrichmentEnabled ? video.mainContentDivId : null;
8!
115
    });
116

117
    requestBids.before(beforeBidsRequested, 40);
18✔
118

119
    pbEvents.on(EVENTS.BID_ADJUSTMENT, function (bid) {
18✔
120
      videoImpressionVerifier.trackBid(bid);
1✔
121
    });
122

123
    pbEvents.on(getExternalVideoEventName(AD_IMPRESSION), function (payload) {
18✔
124
      triggerVideoBidEvent(BID_IMPRESSION, payload);
2✔
125
    });
126

127
    pbEvents.on(getExternalVideoEventName(AD_ERROR), function (payload) {
18✔
128
      triggerVideoBidEvent(BID_ERROR, payload);
2✔
129
    });
130
  }
131

132
  type RenderBidOptions = {
133
    adXml?: string;
134
    winner?: BidderCode;
135
    [option: string]: unknown;
136
  };
137

138
  function renderBid(divId: string, bid: VideoBid, options: RenderBidOptions = {}) {
1!
139
    const adUrl = bid.vastUrl;
1✔
140
    options.adXml = bid.vastXml;
1✔
141
    options.winner = bid.bidder;
1✔
142

143
    loadAd(adUrl, divId, options);
1✔
144
  }
145

146
  function getOrtbVideo(divId: string): DeepPartial<ORTBImp['video']> {
147
    return videoCore.getOrtbVideo(divId);
2✔
148
  }
149

150
  function getOrtbContent(divId: string): DeepPartial<ORTBRequest['site']['content']> {
151
    return videoCore.getOrtbContent(divId);
2✔
152
  }
153

154
  return { init, renderBid, getOrtbVideo, getOrtbContent };
18✔
155

156
  function beforeBidsRequested(nextFn, bidderRequest) {
157
    logErrorForInvalidDivIds(bidderRequest);
6✔
158
    enrichAuction(bidderRequest);
6✔
159

160
    const bidsBackHandler = bidderRequest.bidsBackHandler;
6✔
161
    if (!bidsBackHandler || typeof bidsBackHandler !== 'function') {
6!
162
      pbEvents.on(EVENTS.AUCTION_END, auctionEnd);
6✔
163
    }
164

165
    return nextFn.call(this, bidderRequest);
6✔
166
  }
167

168
  function logErrorForInvalidDivIds(bidderRequest) {
169
    const adUnits = bidderRequest.adUnits || pbGlobal.adUnits || [];
6✔
170
    adUnits.forEach(adUnit => {
6✔
171
      const video = adUnit.video;
2✔
172
      if (!video) {
2!
173
        return;
×
174
      }
175
      if (!video.divId) {
2!
176
        logError(`Missing Video player div ID for ad unit '${adUnit.code}'`);
×
177
      }
178
      if (!videoCore.hasProviderFor(video.divId)) {
2✔
179
        logError(`Video player div ID '${video.divId}' for ad unit '${adUnit.code}' does not match any registered player`);
2✔
180
      }
181
    });
182
  }
183

184
  function enrichAuction(bidderRequest) {
185
    if (mainContentDivId) {
6!
186
      enrichOrtb2(mainContentDivId, bidderRequest);
×
187
    }
188

189
    const adUnits = bidderRequest.adUnits || pbGlobal.adUnits || [];
6✔
190
    adUnits.forEach(adUnit => {
6✔
191
      const divId = getDivId(adUnit);
2✔
192
      enrichAdUnit(adUnit, divId);
2✔
193
      if (contentEnrichmentEnabled && !mainContentDivId) {
2✔
194
        enrichOrtb2(divId, bidderRequest);
2✔
195
      }
196
    });
197
  }
198

199
  function getDivId(adUnit) {
200
    const videoConfig = adUnit.video;
2✔
201
    if (!adUnit.mediaTypes.video || !videoConfig) {
2!
202
      return;
×
203
    }
204

205
    return videoConfig.divId;
2✔
206
  }
207

208
  function enrichAdUnit(adUnit, videoDivId) {
209
    const ortbVideo = getOrtbVideo(videoDivId);
2✔
210
    if (!ortbVideo) {
2!
211
      return;
×
212
    }
213

214
    const video = Object.assign({}, ortbVideo, adUnit.mediaTypes.video);
2✔
215

216
    if (!video.context) {
2✔
217
      video.context = ortbVideo.placement === PLACEMENT.INSTREAM ? 'instream' : 'outstream';
2!
218
    }
219

220
    if (!video.plcmt) {
2✔
221
      logWarn('Video.plcmt has not been set. Failure to set a value may result in loss of bids');
2✔
222
    }
223

224
    const width = ortbVideo.w;
2✔
225
    const height = ortbVideo.h;
2✔
226
    if (!video.playerSize && width && height) {
2!
227
      video.playerSize = [width, height];
×
228
    }
229

230
    adUnit.mediaTypes.video = video;
2✔
231
  }
232

233
  function enrichOrtb2(divId, bidderRequest) {
234
    const ortbContent = getOrtbContent(divId);
2✔
235
    if (!ortbContent) {
2!
236
      return;
×
237
    }
238
    bidderRequest.ortb2 = mergeDeep({}, bidderRequest.ortb2, { site: { content: ortbContent } });
2✔
239
  }
240

241
  function auctionEnd(auctionResult) {
242
    pbEvents.off(EVENTS.AUCTION_END, auctionEnd);
4✔
243
    return Promise.all(
4✔
244
      auctionResult.adUnits
245
        .filter(au => au.video)
8✔
246
        .map(renderWinningBid)
247
    )
248
  }
249

250
  function getAdServerConfig(adUnitVideoConfig) {
251
    const globalVideoConfig = getConfig(videoKey);
5✔
252
    const globalProviderConfig = globalVideoConfig.providers.find(provider => provider.divId === adUnitVideoConfig.divId) || {};
8✔
253
    if (!globalVideoConfig.adServer && !globalProviderConfig.adServer && !adUnitVideoConfig.adServer) {
5✔
254
      return;
2✔
255
    }
256
    return mergeDeep({}, globalVideoConfig.adServer, globalProviderConfig.adServer, adUnitVideoConfig.adServer);
3✔
257
  }
258

259
  async function renderWinningBid(adUnit) {
260
    const adUnitCode = adUnit.code;
5✔
261

262
    const videoConfig = adUnit.video;
5✔
263
    const divId = videoConfig.divId;
5✔
264

265
    const adServerConfig = getAdServerConfig(videoConfig);
5✔
266
    const winningBid = getWinningBid(adUnitCode);
5✔
267
    if (!winningBid) return;
5✔
268

269
    const options: any = { adUnitCode };
3✔
270

271
    async function prefetchVast() {
272
      const gamVastWrapper = await gamSubmodule.getVastXml(
×
273
        adUnit, adServerConfig.baseAdTagUrl, adServerConfig.params, winningBid
274
      );
275
      options.prefetchedVastXml = gamVastWrapper;
×
276
    }
277

278
    if (adServerConfig) {
3✔
279
      if (config.getConfig('cache.useLocal')) {
2!
280
        await prefetchVast();
×
281
      } else {
282
        const adTagUrl = gamSubmodule.getAdTagUrl(
2✔
283
          adUnit, adServerConfig.baseAdTagUrl, adServerConfig.params
284
        );
285
        loadAd(adTagUrl, divId, options);
2✔
286
        return;
2✔
287
      }
288
    }
289

290
    renderBid(divId, winningBid, options);
1✔
291
  }
292

293
  function getWinningBid(adUnitCode) {
294
    const highestCpmBids = pbGlobal.getHighestCpmBids(adUnitCode);
5✔
295
    if (!highestCpmBids.length) {
5✔
296
      pbEvents.emit(getExternalVideoEventName(AUCTION_AD_LOAD_ABORT), getExternalVideoEventPayload(AUCTION_AD_LOAD_ABORT, {adUnitCode}));
2✔
297
      return;
2✔
298
    }
299
    return highestCpmBids.shift();
3✔
300
  }
301

302
  function loadAd(adTagUrl: string, divId: string, options: RenderBidOptions) {
303
    adQueueCoordinator.queueAd(adTagUrl, divId, options);
3✔
304
  }
305

306
  function triggerVideoBidEvent(eventName, adEventPayload) {
307
    const bid = getBid(adEventPayload);
4✔
308
    if (!bid) {
4✔
309
      return;
2✔
310
    }
311

312
    pbGlobal.markWinningBidAsUsed(bid);
2✔
313
    pbEvents.emit(getExternalVideoEventName(eventName), getExternalVideoEventPayload(eventName, { bid, adEvent: adEventPayload }));
2✔
314
  }
315

316
  function getBid(adPayload) {
317
    const { adId, adTagUrl, wrapperAdIds } = adPayload;
4✔
318
    const bidIdentifiers = videoImpressionVerifier.getBidIdentifiers(adId, adTagUrl, wrapperAdIds);
4✔
319
    if (!bidIdentifiers) {
4!
320
      return;
×
321
    }
322

323
    const { adUnitCode, requestId, auctionId } = bidIdentifiers;
4✔
324
    const bidAdId = bidIdentifiers.adId;
4✔
325
    const { bids } = pbGlobal.getBidResponsesForAdUnitCode(adUnitCode);
4✔
326
    return ((bids) || []).find(bid => bid.adId === bidAdId && bid.requestId === requestId && bid.auctionId === auctionId);
4!
327
  }
328
}
329

330
declare module '../../src/prebidGlobal' {
331
  interface PrebidJS {
332
    videoModule: ReturnType<typeof PbVideo>
333
  }
334
}
335

336
function videoRenderHook(next, args) {
UNCOV
337
  if (args.bidResponse.mediaType === VIDEO) {
×
UNCOV
338
    const adUnit = auctionManager.index.getAdUnit(args.bidResponse);
×
UNCOV
339
    if (adUnit?.video) {
×
340
      getGlobal().videoModule.renderBid(adUnit.video.divId, args.bidResponse);
×
341
      next.bail();
×
342
      return;
×
343
    }
344
  }
UNCOV
345
  next(args);
×
346
}
347

348
export function pbVideoFactory() {
349
  const videoCore = videoCoreFactory();
1✔
350
  const adQueueCoordinator = AdQueueCoordinator(videoCore, events);
1✔
351
  const pbGlobal = getGlobal();
1✔
352
  const pbVideo = PbVideo(videoCore, config.getConfig, pbGlobal, getHook('requestBids'), events, allVideoEvents, gamSubmoduleFactory, videoImpressionVerifierFactory, adQueueCoordinator);
1✔
353
  pbVideo.init();
1✔
354
  pbGlobal.videoModule = pbVideo;
1✔
355
  doRender.before(videoRenderHook);
1✔
356
  return pbVideo;
1✔
357
}
358

359
pbVideoFactory();
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