summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/view-timelines/testcommon.js
blob: a798fe918ddc46781ad59d53e44f17cc5812bdf9 (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
'use strict';

function assert_px_equals(observed, expected, description) {
  assert_equals(observed.unit, 'px',
                `Unexpected unit type for '${description}'`);
  assert_approx_equals(observed.value, expected, 0.0001,
                       `Unexpected value for ${description}`);
}

function CreateViewTimelineOpacityAnimation(test, target, options) {
  const timeline_options = {
    subject: target,
    axis: 'block'
  };
  if (options && 'timeline' in options) {
    for (let key in options.timeline) {
      timeline_options[key] = options.timeline[key];
    }
  }
  const animation_options = {
    timeline: new ViewTimeline(timeline_options)
  };
  if (options && 'animation' in options) {
    for (let key in options.animation) {
      animation_options[key] = options.animation[key];
    }
  }

  const anim =
      target.animate({ opacity: [0.3, 0.7] }, animation_options);
  test.add_cleanup(() => {
    anim.cancel();
  });
  return anim;
}

// Verify that range specified in the options aligns with the active range of
// the animation.
//
// Sample call:
// await runTimelineBoundsTest(t, {
//   timeline: { inset: [ CSS.percent(0), CSS.percent(20)] },
//   timing: { fill: 'both' }
//   startOffset: 600,
//   endOffset: 900
// });
async function runTimelineBoundsTest(t, options, message) {
  const scrollOffsetProp = options.axis == 'block' ? 'scrollTop' : 'scrollLeft';
  container[scrollOffsetProp] = 0;
  await waitForNextFrame();

  const anim =
      options.anim ||
      CreateViewTimelineOpacityAnimation(t, target, options);
  if (options.timing)
    anim.effect.updateTiming(options.timing);

  const timeline = anim.timeline;
  await anim.ready;

  // Advance to the start offset, which triggers entry to the active phase.
  container[scrollOffsetProp] = options.startOffset;
  await waitForNextFrame();
  assert_equals(getComputedStyle(target).opacity, '0.3',
                `Effect at the start of the active phase: ${message}`);

  // Advance to the midpoint of the animation.
  container[scrollOffsetProp] = (options.startOffset + options.endOffset) / 2;
  await waitForNextFrame();
  assert_equals(getComputedStyle(target).opacity,'0.5',
                `Effect at the midpoint of the active range: ${message}`);

  // Advance to the end of the animation.
  container[scrollOffsetProp] = options.endOffset;
  await waitForNextFrame();
  assert_equals(getComputedStyle(target).opacity, '0.7',
                `Effect is in the active phase at effect end time: ${message}`);

  // Return the animation so that we can continue testing with the same object.
  return anim;
}

// Sets the start and end range for a view timeline and ensures that the
// range aligns with expected values.
//
// Sample call:
// await runTimelineRangeTest(t, {
//   rangeStart: { rangeName: 'cover', offset: CSS.percent(0) } ,
//   rangeEnd: { rangeName: 'cover', offset: CSS.percent(100) },
//   startOffset: 600,
//   endOffset: 900
// });
async function runTimelineRangeTest(t, options) {
  const rangeToString = range => {
    const parts = [];
    if (range.rangeName)
      parts.push(range.rangeName);
    if (range.offset)
      parts.push(`${range.offset.value}%`);
    return parts.join(' ');
  };
  const range =
     `${rangeToString(options.rangeStart)} to ` +
     `${rangeToString(options.rangeEnd)}`;

  options.timeline = {
    axis: options.axis || 'inline'
  };
  options.animation = {
    rangeStart: options.rangeStart,
    rangeEnd: options.rangeEnd,
  };
  options.timing = {
    // Set fill to accommodate floating point precision errors at the
    // endpoints.
    fill: 'both'
  };

  return runTimelineBoundsTest(t, options, range);
}

// Sets the Inset for a view timeline and ensures that the range aligns with
// expected values.
//
// Sample call:
// await runTimelineInsetTest(t, {
//   inset: [ CSS.px(20), CSS.px(40) ]
//   startOffset: 600,
//   endOffset: 900
// });
async function runTimelineInsetTest(t, options) {
  options.timeline = {
    axis: 'inline',
    inset: options.inset
  };
  options.timing = {
    // Set fill to accommodate floating point precision errors at the
    // endpoints.
    fill: 'both'
  }
  const length = options.inset.length;
  const range =
      (options.inset instanceof Array) ? options.inset.join(' ')
                                       : options.inset;
  return runTimelineBoundsTest(t, options, range);
}