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

prebid / Prebid.js / 16197995703

10 Jul 2025 02:32PM UTC coverage: 96.232% (+0.003%) from 96.229%
16197995703

push

github

web-flow
Linting: remove exception (#13518)

* bump coveralls

* remove exceptions

* results

* eslint fix

* Update package-lock.json

* Update package-lock.json

* Core: remove codex comments and unused lint rule (#13520)

---------

Co-authored-by: Demetrio Girardi <dgirardi@prebid.org>

39174 of 48116 branches covered (81.42%)

9842 of 9975 new or added lines in 861 files covered. (98.67%)

15 existing lines in 8 files now uncovered.

192483 of 200020 relevant lines covered (96.23%)

88.4 hits per line

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

85.0
/modules/bidViewabilityIO.js
1
import { logMessage } from '../src/utils.js';
1✔
2
import { config } from '../src/config.js';
3
import * as events from '../src/events.js';
4
import {EVENTS} from '../src/constants.js';
5

6
const MODULE_NAME = 'bidViewabilityIO';
1✔
7
const CONFIG_ENABLED = 'enabled';
1✔
8

9
// IAB numbers from: https://support.google.com/admanager/answer/4524488?hl=en
10
const IAB_VIEWABLE_DISPLAY_TIME = 1000;
1✔
11
const IAB_VIEWABLE_DISPLAY_LARGE_PX = 242000;
1✔
12
export const IAB_VIEWABLE_DISPLAY_THRESHOLD = 0.5
1✔
13
export const IAB_VIEWABLE_DISPLAY_LARGE_THRESHOLD = 0.3;
1✔
14

15
const CLIENT_SUPPORTS_IO = window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype &&
1✔
16
    'intersectionRatio' in window.IntersectionObserverEntry.prototype;
17

18
const supportedMediaTypes = [
1✔
19
  'banner'
20
];
21

22
export const isSupportedMediaType = (bid) => {
1✔
23
  return supportedMediaTypes.indexOf(bid.mediaType) > -1;
3✔
24
}
25

26
const _logMessage = (message) => {
1✔
27
  return logMessage(`${MODULE_NAME}: ${message}`);
5✔
28
}
29

30
// returns options for the iO that detects if the ad is viewable
31
export const getViewableOptions = (bid) => {
1✔
32
  if (bid.mediaType === 'banner') {
4✔
33
    return {
2✔
34
      root: null,
35
      rootMargin: '0px',
36
      threshold: bid.width * bid.height > IAB_VIEWABLE_DISPLAY_LARGE_PX ? IAB_VIEWABLE_DISPLAY_LARGE_THRESHOLD : IAB_VIEWABLE_DISPLAY_THRESHOLD
2✔
37
    }
38
  }
39
}
40

41
// markViewed returns a function what will be executed when an ad satisifes the viewable iO
42
export const markViewed = (bid, entry, observer) => {
1✔
43
  return () => {
3✔
44
    observer.unobserve(entry.target);
1✔
45
    events.emit(EVENTS.BID_VIEWABLE, bid);
1✔
46
    _logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} was viewed`);
1✔
47
  }
48
}
49

50
// viewCallbackFactory creates the callback used by the viewable IntersectionObserver.
51
// When an ad comes into view, it sets a timeout for a function to be executed
52
// when that ad would be considered viewed per the IAB specs. The bid that was rendered
53
// is passed into the factory, so it can pass it into markViewed, so that it can be included
54
// in the BID_VIEWABLE event data. If the ad leaves view before the timer goes off, the setTimeout
55
// is cancelled, an the bid will not be marked as viewed. There's probably some kind of race-ish
56
// thing going on between IO and setTimeout but this isn't going to be perfect, it's just going to
57
// be pretty good.
58
export const viewCallbackFactory = (bid) => {
1✔
59
  return (entries, observer) => {
2✔
60
    entries.forEach(entry => {
1✔
61
      if (entry.isIntersecting) {
3✔
62
        _logMessage(`viewable timer starting for id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode}`);
1✔
63
        entry.target.view_tracker = setTimeout(markViewed(bid, entry, observer), IAB_VIEWABLE_DISPLAY_TIME);
1✔
64
      } else {
65
        _logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} is out of view`);
2✔
66
        if (entry.target.view_tracker) {
2✔
67
          clearTimeout(entry.target.view_tracker);
1✔
68
          _logMessage(`viewable timer stopped for id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode}`);
1✔
69
        }
70
      }
71
    });
72
  };
73
};
74

75
export const init = () => {
1✔
76
  config.getConfig(MODULE_NAME, conf => {
1✔
77
    if (conf[MODULE_NAME][CONFIG_ENABLED] && CLIENT_SUPPORTS_IO) {
×
78
      // if the module is enabled and the browser supports Intersection Observer,
79
      // then listen to AD_RENDER_SUCCEEDED to setup IO's for supported mediaTypes
80
      events.on(EVENTS.AD_RENDER_SUCCEEDED, ({doc, bid, id}) => {
×
81
        if (isSupportedMediaType(bid)) {
×
NEW
82
          const viewable = new IntersectionObserver(viewCallbackFactory(bid), getViewableOptions(bid));
×
NEW
83
          const element = document.getElementById(bid.adUnitCode);
×
UNCOV
84
          viewable.observe(element);
×
85
        }
86
      });
87
    }
88
  });
89
}
90

91
init()
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