summaryrefslogtreecommitdiffstats
path: root/dom/animation/test/css-animations/file_animation-currenttime.html
blob: ec6fb3f1a898b3237ae9acdf7d370579011bbbc3 (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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<!doctype html>
<html>
  <head>
    <meta charset=utf-8>
    <title>Tests for the effect of setting a CSS animation's
           Animation.currentTime</title>
    <style>

.animated-div {
  margin-left: 10px;
  /* Make it easier to calculate expected values: */
  animation-timing-function: linear ! important;
}

@keyframes anim {
  from { margin-left: 100px; }
  to { margin-left: 200px; }
}

    </style>
    <script src="../testcommon.js"></script>
  </head>
  <body>
    <script type="text/javascript">

'use strict';

// TODO: We should separate this test(Testing for CSS Animation events /
// Testing for currentTime of Web Animation).
// e.g:
//  CSS Animation events test :
//    - check the firing an event using Animation.currentTime
//  The current Time of Web Animation test :
//    - check an current time value on several situation(init / processing..)
//    - Based on W3C Spec, check the behavior of setting current time.

// TODO: Once the computedTiming property is implemented, add checks to the
// checker helpers to ensure that computedTiming's properties are updated as
// expected.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1108055

const CSS_ANIM_EVENTS =
  ['animationstart', 'animationiteration', 'animationend'];

test(function(t)
{
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = "anim 100s";
  var animation = div.getAnimations()[0];

  // Animations shouldn't start until the next paint tick, so:
  assert_equals(animation.currentTime, 0,
    'Animation.currentTime should be zero when an animation ' +
    'is initially created');

  // Make sure the animation is running before we set the current time.
  animation.startTime = animation.timeline.currentTime;

  animation.currentTime = 50 * MS_PER_SEC;
  assert_times_equal(animation.currentTime, 50 * MS_PER_SEC,
    'Check setting of currentTime actually works');
}, 'Sanity test to check round-tripping assigning to new animation\'s ' +
   'currentTime');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  return animation.ready.then(function() {
    // the 0.0001 here is for rounding error
    assert_less_than_equal(animation.currentTime,
      animation.timeline.currentTime - animation.startTime + 0.0001,
      'Animation.currentTime should be less than the local time ' +
      'equivalent of the timeline\'s currentTime on the first paint tick ' +
      'after animation creation');

    animation.currentTime = 100 * MS_PER_SEC;
    return eventWatcher.wait_for('animationstart');
  }).then(function() {
    animation.currentTime = 200 * MS_PER_SEC;
    return eventWatcher.wait_for('animationend');
  });
}, 'Skipping forward through animation');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];
  animation.currentTime = 200 * MS_PER_SEC;
  var previousTimelineTime = animation.timeline.currentTime;

  return eventWatcher.wait_for(['animationstart',
                                'animationend']).then(function() {
    assert_true(document.timeline.currentTime - previousTimelineTime <
                100 * MS_PER_SEC,
                'Sanity check that seeking worked rather than the events ' +
                'firing after normal playback through the very long ' +
                'animation duration');

    animation.currentTime = 150 * MS_PER_SEC;
    return eventWatcher.wait_for('animationstart');
  }).then(function() {
    animation.currentTime = 0;
    return eventWatcher.wait_for('animationend');
  });
}, 'Skipping backwards through animation');

// Next we have multiple tests to check that redundant currentTime changes do
// NOT dispatch events. It's impossible to distinguish between events not being
// dispatched and events just taking an incredibly long time to dispatch
// without waiting an infinitely long time. Obviously we don't want to do that
// (block this test from finishing forever), so instead we just listen for
// events until two animation frames (i.e. requestAnimationFrame callbacks)
// have happened, then assume that no events will ever be dispatched for the
// redundant changes if no events were detected in that time.

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  animation.currentTime = 150 * MS_PER_SEC;
  animation.currentTime = 50 * MS_PER_SEC;

  return waitForAnimationFrames(2);
}, 'Redundant change, before -> active, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  animation.currentTime = 250 * MS_PER_SEC;
  animation.currentTime = 50 * MS_PER_SEC;

  return waitForAnimationFrames(2);
}, 'Redundant change, before -> after, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  var retPromise = eventWatcher.wait_for('animationstart').then(function() {
    animation.currentTime = 50 * MS_PER_SEC;
    animation.currentTime = 150 * MS_PER_SEC;

    return waitForAnimationFrames(2);
  });
  // get us into the initial state:
  animation.currentTime = 150 * MS_PER_SEC;

  return retPromise;
}, 'Redundant change, active -> before, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  var retPromise = eventWatcher.wait_for('animationstart').then(function() {
    animation.currentTime = 250 * MS_PER_SEC;
    animation.currentTime = 150 * MS_PER_SEC;

    return waitForAnimationFrames(2);
  });
  // get us into the initial state:
  animation.currentTime = 150 * MS_PER_SEC;

  return retPromise;
}, 'Redundant change, active -> after, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  var retPromise =  eventWatcher.wait_for(['animationstart',
                                           'animationend']).then(function() {
    animation.currentTime = 50 * MS_PER_SEC;
    animation.currentTime = 250 * MS_PER_SEC;

    return waitForAnimationFrames(2);
  });
  // get us into the initial state:
  animation.currentTime = 250 * MS_PER_SEC;

  return retPromise;
}, 'Redundant change, after -> before, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s 100s";
  var animation = div.getAnimations()[0];

  var retPromise =  eventWatcher.wait_for(['animationstart',
                                           'animationend']).then(function() {
    animation.currentTime = 150 * MS_PER_SEC;
    animation.currentTime = 250 * MS_PER_SEC;

    return waitForAnimationFrames(2);
  });
  // get us into the initial state:
  animation.currentTime = 250 * MS_PER_SEC;

  return retPromise;
}, 'Redundant change, after -> active, then back');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
  div.style.animation = "anim 100s"
  var animation = div.getAnimations()[0];

  animation.pause();
  animation.currentTime = 150 * MS_PER_SEC;

  return eventWatcher.wait_for(['animationstart',
                                'animationend']).then(function() {
    animation.currentTime = 50 * MS_PER_SEC;
    return eventWatcher.wait_for('animationstart');
  });
}, 'Seeking finished -> paused dispatches animationstart');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = "anim 100s";

  var animation = div.getAnimations()[0];

  return animation.ready.then(function() {
    var exception;
    try {
      animation.currentTime = null;
    } catch (e) {
      exception = e;
    }
    assert_equals(exception.name, 'TypeError',
      'Expect TypeError exception on trying to set ' +
      'Animation.currentTime to null');
  });
}, 'Setting currentTime to null');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = 'anim 100s';

  var animation = div.getAnimations()[0];
  var pauseTime;

  return animation.ready.then(function() {
    assert_not_equals(animation.currentTime, null,
      'Animation.currentTime not null on ready Promise resolve');
    animation.pause();
    return animation.ready;
  }).then(function() {
    pauseTime = animation.currentTime;
    return waitForFrame();
  }).then(function() {
    assert_equals(animation.currentTime, pauseTime,
      'Animation.currentTime is unchanged after pausing');
  });
}, 'Animation.currentTime after pausing');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = "anim 100s";
  var animation = div.getAnimations()[0];

  return animation.ready.then(function() {
    // just before animation ends:
    animation.currentTime = 100 * MS_PER_SEC - 1;
    return waitForAnimationFrames(2);
  }).then(function() {
    assert_equals(animation.currentTime, 100 * MS_PER_SEC,
      'Animation.currentTime should not continue to increase after the ' +
      'animation has finished');
  });
}, 'Animation.currentTime clamping');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = "anim 100s";
  var animation = div.getAnimations()[0];

  return animation.ready.then(function() {
    // play backwards:
    animation.playbackRate = -1;

    // just before animation ends (at the "start"):
    animation.currentTime = 1;

    return waitForAnimationFrames(2);
  }).then(function() {
    assert_equals(animation.currentTime, 0,
      'Animation.currentTime should not continue to decrease after an ' +
      'animation running in reverse has finished and currentTime is zero');
  });
}, 'Animation.currentTime clamping for reversed animation');

test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = 'anim 100s';
  var animation = div.getAnimations()[0];
  animation.cancel();

  assert_equals(animation.currentTime, null,
                'The currentTime of a cancelled animation should be null');
}, 'Animation.currentTime after cancelling');

promise_test(function(t) {
  var div = addDiv(t, {'class': 'animated-div'});
  div.style.animation = 'anim 100s';
  var animation = div.getAnimations()[0];

  return animation.ready.then(function() {
    animation.finish();

    // Initiate a pause then abort it
    animation.pause();
    animation.play();

    // Wait to return to running state
    return animation.ready;
  }).then(function() {
    assert_true(animation.currentTime < 100 * 1000,
                'After aborting a pause when finished, the currentTime should'
                + ' jump back towards the start of the animation');
  });
}, 'After aborting a pause when finished, the call to play() should rewind'
   + ' the current time');

done();
    </script>
  </body>
</html>