summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-animations/CSSAnimation-effect.tentative.html
blob: 04812d24e589c22f2266522877a2eb41fa17dcd1 (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
<!doctype html>
<meta charset=utf-8>
<title>CSSAnimation.effect</title>
<meta name="timeout" content="long">
<!-- TODO: Add a more specific link for this once it is specified. -->
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#cssanimation">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/testcommon.js"></script>
<style>
@keyframes anim {
  from {
    margin-left: 0px;
  }
  to {
    margin-left: 100px;
  }
}
</style>
<div id="log"></div>
<script>
'use strict';

promise_test(async t => {
  const div = addDiv(t);
  div.style.animation = 'anim 100s';

  const watcher = new EventWatcher(t, div, [ 'animationend',
                                             'animationcancel' ],
                                   fastEventsTimeout);
  const animation = div.getAnimations()[0];
  await animation.ready;

  animation.currentTime = 50 * MS_PER_SEC;
  animation.effect = null;
  assert_equals(animation.playState, 'finished');
  assert_equals(getComputedStyle(div).marginLeft, '0px');
  await watcher.wait_for('animationend');
}, 'Setting a null effect on a running animation fires an animationend event');

promise_test(async t => {
  const div = addDiv(t);
  div.style.animation = 'anim 100s';

  const animation = div.getAnimations()[0];
  await animation.ready;

  animation.currentTime = 50 * MS_PER_SEC;
  animation.effect = new KeyframeEffect(div,
                                        { left: [ '0px' , '100px'] },
                                        100 * MS_PER_SEC);
  assert_equals(getComputedStyle(div).marginLeft, '0px');
  assert_equals(getComputedStyle(div).left, '50px');
}, 'Replacing an animation\'s effect with an effect that targets a different ' +
   'property should update both properties');

promise_test(async t => {
  const div = addDiv(t);
  div.style.animation = 'anim 100s';

  const animation = div.getAnimations()[0];
  await animation.ready;

  animation.currentTime = 50 * MS_PER_SEC;
  animation.effect = new KeyframeEffect(div,
                                        { left: [ '0px' , '100px'] },
                                        20 * MS_PER_SEC);
  assert_equals(animation.playState, 'finished');
}, 'Replacing an animation\'s effect with a shorter one that should have ' +
   'already finished, the animation finishes immediately');

promise_test(async t => {
  const div = addDiv(t);
  div.style.animation = 'anim 100s';

  const animation = div.getAnimations()[0];
  assert_true(animation.pending);

  animation.effect = new KeyframeEffect(div,
                                        { left: [ '0px' , '100px'] },
                                        100 * MS_PER_SEC);
  assert_true(animation.pending);

  await animation.ready;

  assert_false(animation.pending);
}, 'A play-pending animation\'s effect whose effect is replaced still exits ' +
   'the pending state');

promise_test(async t => {
  const div1 = addDiv(t);
  const div2 = addDiv(t);

  const watcher1 = new EventWatcher(t, div1, 'animationstart',
                                    fastEventsTimeout);
  // Watch |div2| as well to ensure it does *not* get events.
  const watcher2 = new EventWatcher(t, div2, 'animationstart');

  div1.style.animation = 'anim 100s';

  const animation = div1.getAnimations()[0];
  animation.effect = new KeyframeEffect(div2,
                                        { left: [ '0px', '100px' ] },
                                        100 * MS_PER_SEC);

  await watcher1.wait_for('animationstart');

  assert_equals(animation.effect.target, div2);

  // Then wait a couple of frames and check that no event was dispatched.
  await waitForAnimationFrames(2);
}, 'CSS animation events are dispatched at the original element even after'
   + ' setting an effect with a different target element');

promise_test(async t => {
  const div = addDiv(t);
  const watcher = new EventWatcher(t, div, [ 'animationstart',
                                             'animationend',
                                             'animationcancel' ],
                                   fastEventsTimeout);
  div.style.animation = 'anim 100s';
  const animation = div.getAnimations()[0];
  animation.finish();

  await watcher.wait_for([ 'animationstart', 'animationend' ]);
  // Set a longer effect
  animation.effect = new KeyframeEffect(div,
                                        { left: [ '0px', '100px' ] },
                                        200 * MS_PER_SEC);
  await watcher.wait_for('animationstart');
}, 'After replacing a finished animation\'s effect with a longer one ' +
   'it fires an animationstart event');

test(t => {
  const div = addDiv(t);
  div.style.animation = 'anim 100s';
  div.style.animationComposition = 'add';
  const animation = div.getAnimations()[0];
  assert_equals(animation.effect.composite, 'add');
}, 'Setting animation-composition sets the composite property on the effect');

test(t => {
  const div = addDiv(t);

  // Create custom keyframes so we can tweak them
  const stylesheet = document.styleSheets[0];
  const keyframes = '@keyframes anim-custom { to { left: 100px } }';
  const ruleIndex = stylesheet.insertRule(keyframes, 0);
  const keyframesRule = stylesheet.cssRules[ruleIndex];

  t.add_cleanup(function() {
    stylesheet.deleteRule(ruleIndex);
  });

  div.style.animation = 'anim-custom 100s';

  // Replace the effect
  const animation = div.getAnimations()[0];
  animation.effect = new KeyframeEffect(
    div,
    { left: '200px' },
    200 * MS_PER_SEC
  );

  // Update the timing properties
  div.style.animationDuration = '4s';
  div.style.animationIterationCount = '6';
  div.style.animationDirection = 'reverse';
  div.style.animationDelay = '8s';
  div.style.animationFillMode = 'both';
  div.style.animationPlayState = 'paused';
  div.style.animationComposition = 'add';

  // Update the keyframes
  keyframesRule.deleteRule(0);
  keyframesRule.appendRule('to { left: 300px }');

  // Check nothing (except the play state) changed
  assert_equals(
    animation.effect.getTiming().duration,
    200 * MS_PER_SEC,
    'duration should be the value set by the API'
  );
  assert_equals(
    animation.effect.getTiming().iterations,
    1,
    'iterations should be the value set by the API'
  );
  assert_equals(
    animation.effect.getTiming().direction,
    'normal',
    'direction should be the value set by the API'
  );
  assert_equals(
    animation.effect.getTiming().delay,
    0,
    'delay should be the value set by the API'
  );
  assert_equals(
    animation.effect.getTiming().fill,
    'auto',
    'fill should be the value set by the API'
  );
  assert_equals(
    animation.effect.getKeyframes()[0].left,
    '200px',
    'keyframes should be the value set by the API'
  );
  assert_equals(
    animation.effect.composite,
    'replace',
    'composite should be the value set by the API'
  );

  // Unlike the other properties animation-play-state maps to the Animation
  // not the KeyframeEffect so it should be overridden.
  assert_equals(
    animation.playState,
    'paused',
    'play state should be the value set by style'
  );
}, 'Replacing the effect of a CSSAnimation causes subsequent changes to'
   + ' corresponding animation-* properties to be ignored');

</script>