summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/scroll-timelines/testcommon.js
blob: 97e81f494cc6f0d40b293ade0db8e65cc53424e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
'use strict';

// Builds a generic structure that looks like:
//
// <div class="scroller">  // 100x100 viewport
//   <div class="contents"></div>  // 500x500
// </div>
//
// The |scrollerOverrides| and |contentOverrides| parameters are maps which
// are applied to the scroller and contents style after basic setup.
//
// Appends the outer 'scroller' element to the document body, and returns it.
function setupScrollTimelineTest(
    scrollerOverrides = new Map(), contentOverrides = new Map()) {
  let scroller = document.createElement('div');
  scroller.style.width = '100px';
  scroller.style.height = '100px';
  // Hide the scrollbars, but maintain the ability to scroll. This setting
  // ensures that variability in scrollbar sizing does not contribute to test
  // failures or flakes.
  scroller.style.overflow = 'hidden';
  for (const [key, value] of scrollerOverrides) {
    scroller.style[key] = value;
  }

  let contents = document.createElement('div');
  contents.style.width = '500px';
  contents.style.height = '500px';
  for (const [key, value] of contentOverrides) {
    contents.style[key] = value;
  }

  scroller.appendChild(contents);
  document.body.appendChild(scroller);
  return scroller;
}

// Helper method to calculate the current time, implementing only step 5 of
// https://wicg.github.io/scroll-animations/#current-time-algorithm
function calculateCurrentTime(
    currentScrollOffset, startScrollOffset, endScrollOffset) {
  return ((currentScrollOffset - startScrollOffset) /
          (endScrollOffset - startScrollOffset)) *
         100;
}

function createScroller(test) {
  var scroller = createDiv(test);
  scroller.innerHTML = "<div class='contents'></div>";
  scroller.classList.add('scroller');
  // Trigger layout run.
  scroller.scrollTop;
  return scroller;
}

function createScrollerWithStartAndEnd(test, orientationClass = 'vertical') {
  var scroller = createDiv(test);
  scroller.innerHTML =
    `<div class='contents'>
        <div id='start'></div>
        <div id='end'></div>
      </div>`;
  scroller.classList.add('scroller');
  scroller.classList.add(orientationClass);

  return scroller;
}

function createScrollTimeline(test, options) {
  options = options || {
    source: createScroller(test)
  }
  return new ScrollTimeline(options);
}

function createScrollLinkedAnimation(test, timeline) {
  return createScrollLinkedAnimationWithTiming(test, /* duration in ms*/ 1000, timeline);
}

function createScrollLinkedAnimationWithTiming(test, timing, timeline) {
  if (timeline === undefined)
    timeline = createScrollTimeline(test);
  const KEYFRAMES = { opacity: [0, 1] };
  return new Animation(
    new KeyframeEffect(createDiv(test), KEYFRAMES, timing), timeline);
}

function assert_approx_equals_or_null(actual, expected, tolerance, name) {
  if (actual === null || expected === null){
    assert_equals(actual, expected, name);
  }
  else {
    assert_approx_equals(actual, expected, tolerance, name);
  }
}

function assert_percents_approx_equal(actual, expected, maxScroll,
                                      description) {
  // Base the tolerance on being out by up to half a pixel.
  const tolerance = 0.5 / maxScroll * 100;
  assert_equals(actual.unit, "percent", `'actual' unit type must be ` +
      `'percent' for "${description}"`);
  assert_true(actual instanceof CSSUnitValue, `'actual' must be of type ` +
      `CSSNumberish for "${description}"`);
  if (expected instanceof CSSUnitValue){
    // Verify that when the expected in a CSSUnitValue, it is the correct unit
    // type
    assert_equals(expected.unit, "percent", `'expected' unit type must be ` +
        `'percent' for "${description}"`);
    assert_approx_equals(actual.value, expected.value, tolerance,
        `values do not match for "${description}"`);
  } else if (typeof expected, "number"){
    assert_approx_equals(actual.value, expected, tolerance,
        `values do not match for "${description}"`);
  }
}

function assert_percents_equal(actual, expected, description) {
  // Rough estimate of the default size of the scrollable area based on
  // sizes in setupScrollTimelineTest.
  const defaultScrollRange = 400;
  return assert_percents_approx_equal(actual, expected, defaultScrollRange,
                                      description);
}