summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/scroll-timelines/setting-current-time.html
blob: f6c826db6993663462727f8ec4629e62adf28f61 (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
<!DOCTYPE html>
<meta charset=utf-8>
<title>Setting the current time of an animation</title>
<link rel="help" href="https://drafts.csswg.org/web-animations-1/#setting-the-current-time-of-an-animation">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="testcommon.js"></script>
<style>
.scroller {
  overflow: auto;
  height: 200px;
  width: 100px;
  will-change: transform;
}
.contents {
  height: 1000px;
  width: 100%;
}
</style>
<body>
<div id="log"></div>
<script>
'use strict';

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;

  assert_throws_js(TypeError, () => {
    animation.currentTime = null;
  });
}, 'Setting animation current time to null throws TypeError.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  assert_throws_dom('NotSupportedError', () => {
    animation.currentTime = CSSNumericValue.parse("300");
  });
  assert_throws_dom('NotSupportedError', () => {
    animation.currentTime = CSSNumericValue.parse("300ms");
  });
  assert_throws_dom('NotSupportedError', () => {
    animation.currentTime = CSSNumericValue.parse("0.3s");
  });
}, 'Setting the current time to an absolute time value throws exception');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();

  animation.currentTime = CSSNumericValue.parse("33.3%");

  assert_percents_equal(animation.currentTime, 33.3,
    "Animation current time should be equal to the set value."
  );
}, 'Set animation current time to a valid value without playing.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;
  animation.currentTime = CSSNumericValue.parse("33.3%");

  assert_percents_equal(animation.currentTime, 33.3,
    "Animation current time should be equal to the set value."
  );
}, 'Set animation current time to a valid value while playing.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;
  animation.currentTime = CSSNumericValue.parse("200%");

  assert_equals(animation.playState, "finished");
  assert_percents_equal(animation.currentTime, 200,
    "Animation current time should be equal to the set value."
  );
}, 'Set animation current time to a value beyond effect end.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;
  animation.currentTime = CSSNumericValue.parse("-10%");

  assert_equals(animation.playState, "running");
  assert_percents_equal(animation.currentTime, -10,
    "Animation current time should be equal to the set value."
  );
}, 'Set animation current time to a negative value.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  animation.currentTime = CSSNumericValue.parse("30%");

  assert_equals(animation.playState, "running");
  assert_true(animation.pending);
  assert_percents_equal(animation.currentTime, 30);
}, "Setting current time while play pending overrides the current time");

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;
  animation.currentTime = CSSNumericValue.parse("33.3%");

  assert_percents_equal(animation.currentTime, 33.3,
    "Animation current time should be equal to the set value."
  );

  // Cancel the animation and play it again, check that current time has reset
  // to scroll offset based current time.
  animation.cancel();
  animation.play();
  await animation.ready;

  assert_percents_equal(animation.currentTime, animation.timeline.currentTime,
    "Animation current time should return to a value matching its" +
    " timeline current time after animation is cancelled and played again."
  );
}, 'Setting animation.currentTime then restarting the animation should' +
  ' reset the current time.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;
  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop = 0.25 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();

  await animation.ready;
  const originalCurrentTime = animation.currentTime.value;

  // Set the current time to something other than where the scroll offset.
  animation.currentTime = CSSNumericValue.parse("50%");

  // Setting current time is internally setting the start time to
  // scrollTimeline.currentTime - newAnimationCurrentTime.
  // Which results in current time of (timeline.currentTime - start_time).
  // This behavior puts the animation in a strange "out of sync" state between
  // the scroller and the animation effect, this is currently expected
  // behavior.

  const expectedStartTime = originalCurrentTime - animation.currentTime.value;
  assert_percents_equal(animation.startTime, expectedStartTime,
    "Animation current time should be updated when setting the current time" +
    " to a time within the range of the animation.");

  scroller.scrollTop = 0.7 * maxScroll;
  // Wait for new animation frame  which allows the timeline to compute new
  // current time.
  await waitForNextFrame();

  assert_percents_equal(animation.startTime, expectedStartTime,
    "Animation start time should remain unchanged when the scroller changes" +
    " position."
  );
  assert_percents_equal(animation.currentTime,
    animation.timeline.currentTime.value - animation.startTime.value,
    "Animation current time should return to a value equal to" +
    " (timeline.currentTime - animation.startTime) after timeline scroll" +
    " source has been scrolled."
  );
}, 'Set Animation current time then scroll.');

promise_test(async t => {
  const animation = createScrollLinkedAnimation(t);
  const scroller = animation.timeline.source;

  // Wait for new animation frame which allows the timeline to compute new
  // current time.
  await waitForNextFrame();
  animation.play();
  await animation.ready;

  // Make the timeline inactive.
  scroller.style.overflow = 'visible';
  scroller.scrollTop;
  await waitForNextFrame();

  assert_equals(animation.currentTime, null,
    'Current time is unresolved when the timeline is inactive.');

  animation.currentTime = CSSNumericValue.parse("30%");
  assert_percents_equal(animation.currentTime, 30,
    'Animation current time should be equal to the set value.');
  assert_equals(animation.playState, 'paused',
    'Animation play state is \'paused\' when current time is set and ' +
    'timeline is inactive.');
}, 'Animation current time and play state are correct when current time is ' +
   'set while the timeline is inactive.');

promise_test(async t => {
    const animation = createScrollLinkedAnimation(t);
    const scroller = animation.timeline.source;

    // Wait for new animation frame which allows the timeline to compute new
    // current time.
    await waitForNextFrame();
    animation.play();
    await animation.ready;

    // Make the timeline inactive.
    scroller.style.overflow = 'visible';
    scroller.scrollTop;
    await waitForNextFrame();

    assert_equals(animation.timeline.currentTime, null,
      'Current time is unresolved when the timeline is inactive.');

    animation.currentTime = CSSNumericValue.parse("30%");
    assert_percents_equal(animation.currentTime, 30,
      'Animation current time should be equal to the set value.');
    assert_equals(animation.playState, 'paused',
      'Animation play state is \'paused\' when current time is set and ' +
      'timeline is inactive.');

    // Make the timeline active.
    scroller.style.overflow = 'auto';
    scroller.scrollTop;
    await waitForNextFrame();

    assert_percents_equal(animation.timeline.currentTime, 0,
      'Current time is resolved when the timeline is active.');
    assert_percents_equal(animation.currentTime, 30,
      'Animation current time holds the set value.');
    assert_equals(animation.playState, 'paused',
      'Animation holds \'paused\' state.');
}, 'Animation current time set while the timeline is inactive holds when the ' +
   'timeline becomes active again.');
</script>
</body>