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
|
<!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';
div.style.animationTimeline = 'none';
// 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 and animation-timeline map
// to the Animation, not the KeyframeEffect, so they should be overridden.
assert_equals(
animation.playState,
'paused',
'play state should be the value set by style'
);
assert_equals(
animation.timeline,
null,
'timeline should be the value set by style'
);
}, 'Replacing the effect of a CSSAnimation causes subsequent changes to'
+ ' corresponding animation-* properties to be ignored');
</script>
|