| OLD | NEW |
| 1 <!DOCTYPE html> | |
| 2 <meta charset=utf-8> | |
| 3 <title>KeyframeEffectReadOnly constructor tests</title> | |
| 4 <link rel="help" href="http://w3c.github.io/web-animations/#the-keyframeeffect-i
nterfaces"> | |
| 5 <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> | |
| 6 <script src="../../../../resources/testharness.js"></script> | |
| 7 <script src="../../../../resources/testharnessreport.js"></script> | |
| 8 <script src="../testcommon.js"></script> | |
| 9 <body> | |
| 10 <div id="log"></div> | |
| 11 <div id="target"></div> | |
| 12 <style> | |
| 13 #target { | |
| 14 border-style: solid; /* so border-*-width values don't compute to 0 */ | |
| 15 } | |
| 16 </style> | |
| 17 <script> | |
| 18 "use strict"; | 1 "use strict"; |
| 19 | 2 |
| 20 var target = document.getElementById("target"); | 3 // Utility functions and common keyframe test data. |
| 21 | 4 |
| 22 function assert_frames_equal(a, b, name) { | 5 // ------------------------------ |
| 23 assert_equals(Object.keys(a).sort().toString(), | 6 // Helper functions |
| 24 Object.keys(b).sort().toString(), | 7 // ------------------------------ |
| 25 "properties on " + name); | |
| 26 for (var p in a) { | |
| 27 assert_equals(a[p], b[p], "value for '" + p + "' on " + name); | |
| 28 } | |
| 29 } | |
| 30 | 8 |
| 9 /** |
| 10 * Test equality between two lists of computed keyframes |
| 11 * @param {Array.<ComputedKeyframe>} a - actual computed keyframes |
| 12 * @param {Array.<ComputedKeyframe>} b - expected computed keyframes |
| 13 */ |
| 31 function assert_frame_lists_equal(a, b) { | 14 function assert_frame_lists_equal(a, b) { |
| 32 assert_equals(a.length, b.length, "number of frames"); | 15 assert_equals(a.length, b.length, "number of frames"); |
| 33 for (var i = 0; i < Math.min(a.length, b.length); i++) { | 16 for (var i = 0; i < Math.min(a.length, b.length); i++) { |
| 34 assert_frames_equal(a[i], b[i], "ComputedKeyframe #" + i); | 17 assert_frames_equal(a[i], b[i], "ComputedKeyframe #" + i); |
| 35 } | 18 } |
| 36 } | 19 } |
| 37 | 20 |
| 38 var gEmptyKeyframeListTests = [ | 21 /** Helper */ |
| 39 [], | 22 function assert_frames_equal(a, b, name) { |
| 40 null, | 23 assert_equals(Object.keys(a).sort().toString(), |
| 41 undefined, | 24 Object.keys(b).sort().toString(), |
| 42 ]; | 25 "properties on " + name); |
| 26 for (var p in a) { |
| 27 assert_equals(a[p], b[p], "value for '" + p + "' on " + name); |
| 28 } |
| 29 } |
| 43 | 30 |
| 44 test(function(t) { | 31 // ------------------------------ |
| 45 gEmptyKeyframeListTests.forEach(function(frames) { | 32 // Easing values |
| 46 assert_equals(new KeyframeEffectReadOnly(target, frames).getFrames().length, | 33 // ------------------------------ |
| 47 0, "number of frames for " + JSON.stringify(frames)); | |
| 48 }); | |
| 49 }, "a KeyframeEffectReadOnly can be constructed with no frames"); | |
| 50 | 34 |
| 51 // [specified easing value, expected easing value] | 35 // [specified easing value, expected easing value] |
| 52 var gEasingValueTests = [ | 36 var gEasingValueTests = [ |
| 53 ["linear", "linear"], | 37 ["linear", "linear"], |
| 54 ["ease-in-out", "ease-in-out"], | 38 ["ease-in-out", "ease-in-out"], |
| 55 ["Ease\\2d in-out", "ease-in-out"], | 39 ["Ease\\2d in-out", "ease-in-out"], |
| 56 ["ease /**/", "ease"], | 40 ["ease /**/", "ease"], |
| 57 ]; | 41 ]; |
| 58 | 42 |
| 59 test(function(t) { | 43 var gInvalidEasingInKeyframeSequenceTests = [ |
| 60 gEasingValueTests.forEach(function(subtest) { | 44 { desc: "a blank easing", |
| 61 var easing = subtest[0]; | 45 input: [{ easing: "" }] }, |
| 62 var expected = subtest[1]; | 46 { desc: "an unrecognized easing", |
| 63 var effect = new KeyframeEffectReadOnly(target, { | 47 input: [{ easing: "unrecognized" }] }, |
| 64 left: ["10px", "20px"], | 48 { desc: "an 'initial' easing", |
| 65 easing: easing | 49 input: [{ easing: "initial" }] }, |
| 66 }); | 50 { desc: "an 'inherit' easing", |
| 67 assert_equals(effect.getFrames()[0].easing, expected, | 51 input: [{ easing: "inherit" }] }, |
| 68 "resulting easing for '" + easing + "'"); | 52 { desc: "a variable easing", |
| 69 }); | 53 input: [{ easing: "var(--x)" }] }, |
| 70 }, "easing values are parsed correctly when passed to the " + | 54 { desc: "a multi-value easing", |
| 71 "KeyframeEffectReadOnly constructor in a property-indexed keyframe"); | 55 input: [{ easing: "ease-in-out, ease-out" }] } |
| 56 ]; |
| 72 | 57 |
| 73 test(function(t) { | 58 // ------------------------------ |
| 74 gEasingValueTests.forEach(function(subtest) { | 59 // Composite values |
| 75 var easing = subtest[0]; | 60 // ------------------------------ |
| 76 var expected = subtest[1]; | |
| 77 var effect = new KeyframeEffectReadOnly(target, [ | |
| 78 { offset: 0, left: "10px", easing: easing }, | |
| 79 { offset: 1, left: "20px" } | |
| 80 ]); | |
| 81 assert_equals(effect.getFrames()[0].easing, expected, | |
| 82 "resulting easing for '" + easing + "'"); | |
| 83 }); | |
| 84 }, "easing values are parsed correctly when passed to the " + | |
| 85 "KeyframeEffectReadOnly constructor in regular keyframes"); | |
| 86 | |
| 87 test(function(t) { | |
| 88 gEasingValueTests.forEach(function(subtest) { | |
| 89 var easing = subtest[0]; | |
| 90 var expected = subtest[1]; | |
| 91 var effect = new KeyframeEffectReadOnly(target, { | |
| 92 left: ["10px", "20px"] | |
| 93 }, { easing: easing }); | |
| 94 assert_equals(effect.timing.easing, expected, | |
| 95 "resulting easing for '" + easing + "'"); | |
| 96 }); | |
| 97 }, "easing values are parsed correctly when passed to the " + | |
| 98 "KeyframeEffectReadOnly constructor in KeyframeTimingOptions"); | |
| 99 | 61 |
| 100 var gGoodKeyframeCompositeValueTests = [ | 62 var gGoodKeyframeCompositeValueTests = [ |
| 101 "replace", "add", "accumulate", undefined | 63 "replace", "add", "accumulate", undefined |
| 102 ]; | 64 ]; |
| 103 | 65 |
| 104 var gGoodOptionsCompositeValueTests = [ | 66 var gGoodOptionsCompositeValueTests = [ |
| 105 "replace", "add", "accumulate" | 67 "replace", "add", "accumulate" |
| 106 ]; | 68 ]; |
| 107 | 69 |
| 108 var gBadCompositeValueTests = [ | 70 var gBadCompositeValueTests = [ |
| 109 "unrecognised", "replace ", "Replace", null | 71 "unrecognised", "replace ", "Replace", null |
| 110 ]; | 72 ]; |
| 111 | 73 |
| 112 test(function(t) { | 74 // ------------------------------ |
| 113 var getFrame = function(composite) { | 75 // Keyframes |
| 114 return { left: [ "10px", "20px" ], composite: composite }; | 76 // ------------------------------ |
| 115 }; | |
| 116 gGoodKeyframeCompositeValueTests.forEach(function(composite) { | |
| 117 var effect = new KeyframeEffectReadOnly(target, getFrame(composite)); | |
| 118 assert_equals(effect.getFrames()[0].composite, composite, | |
| 119 "resulting composite for '" + composite + "'"); | |
| 120 }); | |
| 121 gBadCompositeValueTests.forEach(function(composite) { | |
| 122 assert_throws(new TypeError, function() { | |
| 123 new KeyframeEffectReadOnly(target, getFrame(composite)); | |
| 124 }); | |
| 125 }); | |
| 126 }, "composite values are parsed correctly when passed to the " + | |
| 127 "KeyframeEffectReadOnly constructor in property-indexed keyframes"); | |
| 128 | 77 |
| 129 test(function(t) { | 78 var gEmptyKeyframeListTests = [ |
| 130 var getFrames = function(composite) { | 79 [], |
| 131 return [ | 80 null, |
| 132 { offset: 0, left: "10px", composite: composite }, | 81 undefined, |
| 133 { offset: 1, left: "20px" } | 82 ]; |
| 134 ]; | |
| 135 }; | |
| 136 gGoodKeyframeCompositeValueTests.forEach(function(composite) { | |
| 137 var effect = new KeyframeEffectReadOnly(target, getFrames(composite)); | |
| 138 assert_equals(effect.getFrames()[0].composite, composite, | |
| 139 "resulting composite for '" + composite + "'"); | |
| 140 }); | |
| 141 gBadCompositeValueTests.forEach(function(composite) { | |
| 142 assert_throws(new TypeError, function() { | |
| 143 new KeyframeEffectReadOnly(target, getFrames(composite)); | |
| 144 }); | |
| 145 }); | |
| 146 }, "composite values are parsed correctly when passed to the " + | |
| 147 "KeyframeEffectReadOnly constructor in regular keyframes"); | |
| 148 | |
| 149 test(function(t) { | |
| 150 gGoodOptionsCompositeValueTests.forEach(function(composite) { | |
| 151 var effect = new KeyframeEffectReadOnly(target, { | |
| 152 left: ["10px", "20px"] | |
| 153 }, { composite: composite }); | |
| 154 assert_equals(effect.getFrames()[0].composite, composite, | |
| 155 "resulting composite for '" + composite + "'"); | |
| 156 }); | |
| 157 gBadCompositeValueTests.forEach(function(composite) { | |
| 158 assert_throws(new TypeError, function() { | |
| 159 new KeyframeEffectReadOnly(target, { | |
| 160 left: ["10px", "20px"] | |
| 161 }, { composite: composite }); | |
| 162 }); | |
| 163 }); | |
| 164 }, "composite values are parsed correctly when passed to the " + | |
| 165 "KeyframeEffectReadOnly constructor in KeyframeTimingOptions"); | |
| 166 | 83 |
| 167 var gPropertyIndexedKeyframesTests = [ | 84 var gPropertyIndexedKeyframesTests = [ |
| 168 { desc: "a one property two value property-indexed keyframes specification", | 85 { desc: "a one property two value property-indexed keyframes specification", |
| 169 input: { left: ["10px", "20px"] }, | 86 input: { left: ["10px", "20px"] }, |
| 170 output: [{ offset: null, computedOffset: 0, easing: "linear", | 87 output: [{ offset: null, computedOffset: 0, easing: "linear", |
| 171 left: "10px" }, | 88 left: "10px" }, |
| 172 { offset: null, computedOffset: 1, easing: "linear", | 89 { offset: null, computedOffset: 1, easing: "linear", |
| 173 left: "20px" }] }, | 90 left: "20px" }] }, |
| 174 { desc: "a one shorthand property two value property-indexed keyframes" | 91 { desc: "a one shorthand property two value property-indexed keyframes" |
| 175 + " specification", | 92 + " specification", |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 left: "40px", top: "45px" }, | 133 left: "40px", top: "45px" }, |
| 217 { offset: null, computedOffset: 1.00, easing: "linear", | 134 { offset: null, computedOffset: 1.00, easing: "linear", |
| 218 left: "50px", top: "55px" }] }, | 135 left: "50px", top: "55px" }] }, |
| 219 { desc: "a one property two value property-indexed keyframes specification" | 136 { desc: "a one property two value property-indexed keyframes specification" |
| 220 + " that needs to stringify its values", | 137 + " that needs to stringify its values", |
| 221 input: { opacity: [0, 1] }, | 138 input: { opacity: [0, 1] }, |
| 222 output: [{ offset: null, computedOffset: 0, easing: "linear", | 139 output: [{ offset: null, computedOffset: 0, easing: "linear", |
| 223 opacity: "0" }, | 140 opacity: "0" }, |
| 224 { offset: null, computedOffset: 1, easing: "linear", | 141 { offset: null, computedOffset: 1, easing: "linear", |
| 225 opacity: "1" }] }, | 142 opacity: "1" }] }, |
| 143 { desc: "a property-indexed keyframes specification with a CSS variable" |
| 144 + " reference", |
| 145 input: { left: [ "var(--dist)", "calc(var(--dist) + 100px)" ] }, |
| 146 output: [{ offset: null, computedOffset: 0.0, easing: "linear", |
| 147 left: "var(--dist)" }, |
| 148 { offset: null, computedOffset: 1.0, easing: "linear", |
| 149 left: "calc(var(--dist) + 100px)" }] }, |
| 150 { desc: "a property-indexed keyframes specification with a CSS variable" |
| 151 + " reference in a shorthand property", |
| 152 input: { margin: [ "var(--dist)", "calc(var(--dist) + 100px)" ] }, |
| 153 output: [{ offset: null, computedOffset: 0.0, easing: "linear", |
| 154 margin: "var(--dist)" }, |
| 155 { offset: null, computedOffset: 1.0, easing: "linear", |
| 156 margin: "calc(var(--dist) + 100px)" }] }, |
| 226 { desc: "a one property one value property-indexed keyframes specification", | 157 { desc: "a one property one value property-indexed keyframes specification", |
| 227 input: { left: ["10px"] }, | 158 input: { left: ["10px"] }, |
| 228 output: [{ offset: null, computedOffset: 1, easing: "linear", | 159 output: [{ offset: null, computedOffset: 1, easing: "linear", |
| 229 left: "10px" }] }, | 160 left: "10px" }] }, |
| 230 { desc: "a one property one non-array value property-indexed keyframes" | 161 { desc: "a one property one non-array value property-indexed keyframes" |
| 231 + " specification", | 162 + " specification", |
| 232 input: { left: "10px" }, | 163 input: { left: "10px" }, |
| 233 output: [{ offset: null, computedOffset: 1, easing: "linear", | 164 output: [{ offset: null, computedOffset: 1, easing: "linear", |
| 234 left: "10px" }] }, | 165 left: "10px" }] }, |
| 235 { desc: "a one property two value property-indexed keyframes specification" | 166 { desc: "a one property two value property-indexed keyframes specification" |
| 236 + " where the first value is invalid", | 167 + " where the first value is invalid", |
| 237 input: { left: ["invalid", "10px"] }, | 168 input: { left: ["invalid", "10px"] }, |
| 238 output: [{ offset: null, computedOffset: 0, easing: "linear", | 169 output: [{ offset: null, computedOffset: 0, easing: "linear", |
| 239 left: "invalid" }, | 170 left: "invalid" }, |
| 240 { offset: null, computedOffset: 1, easing: "linear", | 171 { offset: null, computedOffset: 1, easing: "linear", |
| 241 left: "10px" }] }, | 172 left: "10px" }] }, |
| 242 { desc: "a one property two value property-indexed keyframes specification" | 173 { desc: "a one property two value property-indexed keyframes specification" |
| 243 + " where the second value is invalid", | 174 + " where the second value is invalid", |
| 244 input: { left: ["10px", "invalid"] }, | 175 input: { left: ["10px", "invalid"] }, |
| 245 output: [{ offset: null, computedOffset: 0, easing: "linear", | 176 output: [{ offset: null, computedOffset: 0, easing: "linear", |
| 246 left: "10px" }, | 177 left: "10px" }, |
| 247 { offset: null, computedOffset: 1, easing: "linear", | 178 { offset: null, computedOffset: 1, easing: "linear", |
| 248 left: "invalid" }] }, | 179 left: "invalid" }] }, |
| 249 { desc: "a two property property-indexed keyframes specification where one" | |
| 250 + " property is missing from the first keyframe", | |
| 251 input: [{ offset: 0, left: "10px" }, | |
| 252 { offset: 1, left: "20px", top: "30px" }], | |
| 253 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | |
| 254 { offset: 1, computedOffset: 1, easing: "linear", | |
| 255 left: "20px", top: "30px" }] }, | |
| 256 { desc: "a two property property-indexed keyframes specification where one" | |
| 257 + " property is missing from the last keyframe", | |
| 258 input: [{ offset: 0, left: "10px", top: "20px" }, | |
| 259 { offset: 1, left: "30px" }], | |
| 260 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 261 left: "10px" , top: "20px" }, | |
| 262 { offset: 1, computedOffset: 1, easing: "linear", | |
| 263 left: "30px" }] }, | |
| 264 { desc: "a property-indexed keyframes specification with repeated values" | |
| 265 + " at offset 0 with different easings", | |
| 266 input: [{ offset: 0.0, left: "100px", easing: "ease" }, | |
| 267 { offset: 0.0, left: "200px", easing: "ease" }, | |
| 268 { offset: 0.5, left: "300px", easing: "linear" }, | |
| 269 { offset: 1.0, left: "400px", easing: "ease-out" }, | |
| 270 { offset: 1.0, left: "500px", easing: "step-end" }], | |
| 271 output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease", | |
| 272 left: "100px" }, | |
| 273 { offset: 0.0, computedOffset: 0.0, easing: "ease", | |
| 274 left: "200px" }, | |
| 275 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 276 left: "300px" }, | |
| 277 { offset: 1.0, computedOffset: 1.0, easing: "ease-out", | |
| 278 left: "400px" }, | |
| 279 { offset: 1.0, computedOffset: 1.0, easing: "step-end", | |
| 280 left: "500px" }] }, | |
| 281 ]; | 180 ]; |
| 282 | 181 |
| 283 gPropertyIndexedKeyframesTests.forEach(function(subtest) { | |
| 284 test(function(t) { | |
| 285 var effect = new KeyframeEffectReadOnly(target, subtest.input); | |
| 286 assert_frame_lists_equal(effect.getFrames(), subtest.output); | |
| 287 }, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc); | |
| 288 | |
| 289 test(function(t) { | |
| 290 var effect = new KeyframeEffectReadOnly(target, subtest.input); | |
| 291 var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames()); | |
| 292 assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames()); | |
| 293 }, "a KeyframeEffectReadOnly constructed with " + subtest.desc + | |
| 294 " roundtrips"); | |
| 295 }); | |
| 296 | |
| 297 test(function(t) { | |
| 298 var expectedOrder = ["composite", "easing", "offset", "left", "marginLeft"]; | |
| 299 var actualOrder = []; | |
| 300 var kf1 = {}; | |
| 301 var kf2 = { marginLeft: "10px", left: "20px", offset: 1 }; | |
| 302 [{ p: "marginLeft", v: "10px" }, | |
| 303 { p: "left", v: "20px" }, | |
| 304 { p: "offset", v: "0" }, | |
| 305 { p: "easing", v: "linear" }, | |
| 306 { p: "composite", v: "replace" }].forEach(function(e) { | |
| 307 Object.defineProperty(kf1, e.p, { | |
| 308 enumerable: true, | |
| 309 get: function() { actualOrder.push(e.p); return e.v; } | |
| 310 }); | |
| 311 }); | |
| 312 new KeyframeEffectReadOnly(target, [kf1, kf2]); | |
| 313 assert_array_equals(actualOrder, expectedOrder, "property access order"); | |
| 314 }, "the KeyframeEffectReadOnly constructor reads keyframe properties in the " + | |
| 315 "expected order"); | |
| 316 | |
| 317 var gKeyframeSequenceTests = [ | 182 var gKeyframeSequenceTests = [ |
| 183 { desc: "a one property one keyframe sequence", |
| 184 input: [{ offset: 1, left: "10px" }], |
| 185 output: [{ offset: null, computedOffset: 1, easing: "linear", |
| 186 left: "10px" }] }, |
| 318 { desc: "a one property two keyframe sequence", | 187 { desc: "a one property two keyframe sequence", |
| 319 input: [{ offset: 0, left: "10px" }, | 188 input: [{ offset: 0, left: "10px" }, |
| 320 { offset: 1, left: "20px" }], | 189 { offset: 1, left: "20px" }], |
| 321 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | 190 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, |
| 322 { offset: 1, computedOffset: 1, easing: "linear", left: "20px" }] | 191 { offset: 1, computedOffset: 1, easing: "linear", left: "20px" }] |
| 323 }, | 192 }, |
| 324 { desc: "a two property two keyframe sequence", | 193 { desc: "a two property two keyframe sequence", |
| 325 input: [{ offset: 0, left: "10px", top: "30px" }, | 194 input: [{ offset: 0, left: "10px", top: "30px" }, |
| 326 { offset: 1, left: "20px", top: "40px" }], | 195 { offset: 1, left: "20px", top: "40px" }], |
| 327 output: [{ offset: 0, computedOffset: 0, easing: "linear", | 196 output: [{ offset: 0, computedOffset: 0, easing: "linear", |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 { desc: "a two property four keyframe sequence", | 246 { desc: "a two property four keyframe sequence", |
| 378 input: [{ offset: 0, left: "10px" }, | 247 input: [{ offset: 0, left: "10px" }, |
| 379 { offset: 0, top: "20px" }, | 248 { offset: 0, top: "20px" }, |
| 380 { offset: 1, top: "30px" }, | 249 { offset: 1, top: "30px" }, |
| 381 { offset: 1, left: "40px" }], | 250 { offset: 1, left: "40px" }], |
| 382 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | 251 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, |
| 383 { offset: 0, computedOffset: 0, easing: "linear", top: "20px" }, | 252 { offset: 0, computedOffset: 0, easing: "linear", top: "20px" }, |
| 384 { offset: 1, computedOffset: 1, easing: "linear", top: "30px" }, | 253 { offset: 1, computedOffset: 1, easing: "linear", top: "30px" }, |
| 385 { offset: 1, computedOffset: 1, easing: "linear", left: "40px" }] | 254 { offset: 1, computedOffset: 1, easing: "linear", left: "40px" }] |
| 386 }, | 255 }, |
| 256 { desc: "a single keyframe sequence with omitted offsets", |
| 257 input: [{ left: "10px" }], |
| 258 output: [{ offset: null, computedOffset: 1, easing: "linear", |
| 259 left: "10px" }] }, |
| 387 { desc: "a one property keyframe sequence with some omitted offsets", | 260 { desc: "a one property keyframe sequence with some omitted offsets", |
| 388 input: [{ offset: 0.00, left: "10px" }, | 261 input: [{ offset: 0.00, left: "10px" }, |
| 389 { offset: 0.25, left: "20px" }, | 262 { offset: 0.25, left: "20px" }, |
| 390 { left: "30px" }, | 263 { left: "30px" }, |
| 391 { left: "40px" }, | 264 { left: "40px" }, |
| 392 { offset: 1.00, left: "50px" }], | 265 { offset: 1.00, left: "50px" }], |
| 393 output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", | 266 output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", |
| 394 left: "10px" }, | 267 left: "10px" }, |
| 395 { offset: 0.25, computedOffset: 0.25, easing: "linear", | 268 { offset: 0.25, computedOffset: 0.25, easing: "linear", |
| 396 left: "20px" }, | 269 left: "20px" }, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 composite: "replace", left: "50px" }, | 345 composite: "replace", left: "50px" }, |
| 473 { offset: 1.0, computedOffset: 1.0, easing: "linear", | 346 { offset: 1.0, computedOffset: 1.0, easing: "linear", |
| 474 composite: "replace", top: "60px" }] }, | 347 composite: "replace", top: "60px" }] }, |
| 475 { desc: "a one property two keyframe sequence that needs to stringify" | 348 { desc: "a one property two keyframe sequence that needs to stringify" |
| 476 + " its values", | 349 + " its values", |
| 477 input: [{ offset: 0, opacity: 0 }, | 350 input: [{ offset: 0, opacity: 0 }, |
| 478 { offset: 1, opacity: 1 }], | 351 { offset: 1, opacity: 1 }], |
| 479 output: [{ offset: 0, computedOffset: 0, easing: "linear", opacity: "0" }, | 352 output: [{ offset: 0, computedOffset: 0, easing: "linear", opacity: "0" }, |
| 480 { offset: 1, computedOffset: 1, easing: "linear", opacity: "1" }] | 353 { offset: 1, computedOffset: 1, easing: "linear", opacity: "1" }] |
| 481 }, | 354 }, |
| 355 { desc: "a keyframe sequence with a CSS variable reference", |
| 356 input: [{ left: "var(--dist)" }, |
| 357 { left: "calc(var(--dist) + 100px)" }], |
| 358 output: [{ offset: null, computedOffset: 0.0, easing: "linear", |
| 359 left: "var(--dist)" }, |
| 360 { offset: null, computedOffset: 1.0, easing: "linear", |
| 361 left: "calc(var(--dist) + 100px)" }] }, |
| 362 { desc: "a keyframe sequence with a CSS variable reference in a shorthand" |
| 363 + " property", |
| 364 input: [{ margin: "var(--dist)" }, |
| 365 { margin: "calc(var(--dist) + 100px)" }], |
| 366 output: [{ offset: null, computedOffset: 0.0, easing: "linear", |
| 367 margin: "var(--dist)" }, |
| 368 { offset: null, computedOffset: 1.0, easing: "linear", |
| 369 margin: "calc(var(--dist) + 100px)" }] }, |
| 482 { desc: "a keyframe sequence where shorthand precedes longhand", | 370 { desc: "a keyframe sequence where shorthand precedes longhand", |
| 483 input: [{ offset: 0, margin: "10px", marginRight: "20px" }, | 371 input: [{ offset: 0, margin: "10px", marginRight: "20px" }, |
| 484 { offset: 1, margin: "30px" }], | 372 { offset: 1, margin: "30px" }], |
| 485 output: [{ offset: 0, computedOffset: 0, easing: "linear", | 373 output: [{ offset: 0, computedOffset: 0, easing: "linear", |
| 486 margin: "10px", marginRight: "20px" }, | 374 margin: "10px", marginRight: "20px" }, |
| 487 { offset: 1, computedOffset: 1, easing: "linear", | 375 { offset: 1, computedOffset: 1, easing: "linear", |
| 488 margin: "30px" }] }, | 376 margin: "30px" }] }, |
| 489 { desc: "a keyframe sequence where longhand precedes shorthand", | 377 { desc: "a keyframe sequence where longhand precedes shorthand", |
| 490 input: [{ offset: 0, marginRight: "20px", margin: "10px" }, | 378 input: [{ offset: 0, marginRight: "20px", margin: "10px" }, |
| 491 { offset: 1, margin: "30px" }], | 379 { offset: 1, margin: "30px" }], |
| (...skipping 15 matching lines...) Expand all Loading... |
| 507 { desc: "a keyframe sequence where greater shorthand precedes lesser" | 395 { desc: "a keyframe sequence where greater shorthand precedes lesser" |
| 508 + " shorthand", | 396 + " shorthand", |
| 509 input: [{ offset: 0, border: "2px dotted rgb(4, 5, 6)", | 397 input: [{ offset: 0, border: "2px dotted rgb(4, 5, 6)", |
| 510 borderLeft: "1px solid rgb(1, 2, 3)" }, | 398 borderLeft: "1px solid rgb(1, 2, 3)" }, |
| 511 { offset: 1, border: "3px dashed rgb(7, 8, 9)" }], | 399 { offset: 1, border: "3px dashed rgb(7, 8, 9)" }], |
| 512 output: [{ offset: 0, computedOffset: 0, easing: "linear", | 400 output: [{ offset: 0, computedOffset: 0, easing: "linear", |
| 513 border: "2px dotted rgb(4, 5, 6)", | 401 border: "2px dotted rgb(4, 5, 6)", |
| 514 borderLeft: "1px solid rgb(1, 2, 3)" }, | 402 borderLeft: "1px solid rgb(1, 2, 3)" }, |
| 515 { offset: 1, computedOffset: 1, easing: "linear", | 403 { offset: 1, computedOffset: 1, easing: "linear", |
| 516 border: "3px dashed rgb(7, 8, 9)" }] }, | 404 border: "3px dashed rgb(7, 8, 9)" }] }, |
| 405 { desc: "a two property keyframe sequence where one property is missing" |
| 406 + " from the first keyframe", |
| 407 input: [{ offset: 0, left: "10px" }, |
| 408 { offset: 1, left: "20px", top: "30px" }], |
| 409 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, |
| 410 { offset: 1, computedOffset: 1, easing: "linear", |
| 411 left: "20px", top: "30px" }] }, |
| 412 { desc: "a two property keyframe sequence where one property is missing" |
| 413 + " from the last keyframe", |
| 414 input: [{ offset: 0, left: "10px", top: "20px" }, |
| 415 { offset: 1, left: "30px" }], |
| 416 output: [{ offset: 0, computedOffset: 0, easing: "linear", |
| 417 left: "10px" , top: "20px" }, |
| 418 { offset: 1, computedOffset: 1, easing: "linear", |
| 419 left: "30px" }] }, |
| 420 { desc: "a keyframe sequence with repeated values at offset 1 with" |
| 421 + " different easings", |
| 422 input: [{ offset: 0.0, left: "100px", easing: "ease" }, |
| 423 { offset: 0.0, left: "200px", easing: "ease" }, |
| 424 { offset: 0.5, left: "300px", easing: "linear" }, |
| 425 { offset: 1.0, left: "400px", easing: "ease-out" }, |
| 426 { offset: 1.0, left: "500px", easing: "step-end" }], |
| 427 output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease", |
| 428 left: "100px" }, |
| 429 { offset: 0.0, computedOffset: 0.0, easing: "ease", |
| 430 left: "200px" }, |
| 431 { offset: 0.5, computedOffset: 0.5, easing: "linear", |
| 432 left: "300px" }, |
| 433 { offset: 1.0, computedOffset: 1.0, easing: "ease-out", |
| 434 left: "400px" }, |
| 435 { offset: 1.0, computedOffset: 1.0, easing: "step-end", |
| 436 left: "500px" }] }, |
| 517 ]; | 437 ]; |
| 518 | 438 |
| 519 gKeyframeSequenceTests.forEach(function(subtest) { | 439 var gInvalidKeyframesTests = [ |
| 520 test(function(t) { | 440 { desc: "keyframes with an out-of-bounded positive offset", |
| 521 var effect = new KeyframeEffectReadOnly(target, subtest.input); | 441 input: [ { opacity: 0 }, |
| 522 assert_frame_lists_equal(effect.getFrames(), subtest.output); | 442 { opacity: 0.5, offset: 2 }, |
| 523 }, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc); | 443 { opacity: 1 } ], |
| 524 | 444 expected: { name: "TypeError" } }, |
| 525 test(function(t) { | 445 { desc: "keyframes with an out-of-bounded negative offset", |
| 526 var effect = new KeyframeEffectReadOnly(target, subtest.input); | 446 input: [ { opacity: 0 }, |
| 527 var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames()); | 447 { opacity: 0.5, offset: -1 }, |
| 528 assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames()); | 448 { opacity: 1 } ], |
| 529 }, "a KeyframeEffectReadOnly constructed with " + subtest.desc + | 449 expected: { name: "TypeError" } }, |
| 530 " roundtrips"); | 450 { desc: "keyframes not loosely sorted by offset", |
| 531 }); | 451 input: [ { opacity: 0, offset: 1 }, |
| 532 | 452 { opacity: 1, offset: 0 } ], |
| 533 var gInvalidEasingInKeyframeSequenceTests = [ | 453 expected: { name: "TypeError" } }, |
| 534 { desc: "a blank easing", | 454 { desc: "property-indexed keyframes with an invalid easing value", |
| 535 input: [{ easing: "" }] }, | 455 input: { opacity: [ 0, 0.5, 1 ], |
| 536 { desc: "an unrecognized easing", | 456 easing: "inherit" }, |
| 537 input: [{ easing: "unrecognized" }] }, | 457 expected: { name: "TypeError" } }, |
| 538 { desc: "an 'initial' easing", | 458 { desc: "a keyframe sequence with an invalid easing value", |
| 539 input: [{ easing: "initial" }] }, | 459 input: [ { opacity: 0, easing: "jumpy" }, |
| 540 { desc: "an 'inherit' easing", | 460 { opacity: 1 } ], |
| 541 input: [{ easing: "inherit" }] }, | 461 expected: { name: "TypeError" } }, |
| 542 { desc: "a variable easing", | 462 { desc: "keyframes with an invalid composite value", |
| 543 input: [{ easing: "var(--x)" }] }, | 463 input: [ { opacity: 0, composite: "alternate" }, |
| 544 { desc: "a multi-value easing", | 464 { opacity: 1 } ], |
| 545 input: [{ easing: "ease-in-out, ease-out" }] } | 465 expected: { name: "TypeError" } } |
| 546 ]; | 466 ]; |
| 547 | 467 |
| 548 gInvalidEasingInKeyframeSequenceTests.forEach(function(subtest) { | 468 // ------------------------------ |
| 549 test(function(t) { | 469 // KeyframeEffectOptions |
| 550 assert_throws(new TypeError, function() { | 470 // ------------------------------ |
| 551 new KeyframeEffectReadOnly(target, subtest.input); | |
| 552 }); | |
| 553 }, "Invalid easing [" + subtest.desc + "] in keyframe sequence " + | |
| 554 "should be thrown"); | |
| 555 }); | |
| 556 | |
| 557 test(function(t) { | |
| 558 var effect = new KeyframeEffectReadOnly(target, | |
| 559 {left: ["10px", "20px"]}); | |
| 560 | |
| 561 var timing = effect.timing; | |
| 562 assert_equals(timing.delay, 0, "default delay"); | |
| 563 assert_equals(timing.endDelay, 0, "default endDelay"); | |
| 564 assert_equals(timing.fill, "auto", "default fill"); | |
| 565 assert_equals(timing.iterations, 1.0, "default iterations"); | |
| 566 assert_equals(timing.iterationStart, 0.0, "default iterationStart"); | |
| 567 assert_equals(timing.duration, "auto", "default duration"); | |
| 568 assert_equals(timing.direction, "normal", "default direction"); | |
| 569 assert_equals(timing.easing, "linear", "default easing"); | |
| 570 | |
| 571 assert_equals(effect.composite, "replace", "default composite"); | |
| 572 assert_equals(effect.iterationComposite, "replace", | |
| 573 "default iterationComposite"); | |
| 574 assert_equals(effect.spacing, "distribute", | |
| 575 "default spacing"); | |
| 576 }, "a KeyframeEffectReadOnly constructed without any " + | |
| 577 "KeyframeEffectOptions object"); | |
| 578 | 471 |
| 579 var gKeyframeEffectOptionTests = [ | 472 var gKeyframeEffectOptionTests = [ |
| 580 { desc: "an empty KeyframeEffectOptions object", | 473 { desc: "an empty KeyframeEffectOptions object", |
| 581 input: { }, | 474 input: { }, |
| 582 expected: { } }, | 475 expected: { } }, |
| 583 { desc: "a normal KeyframeEffectOptions object", | 476 { desc: "a normal KeyframeEffectOptions object", |
| 584 input: { delay: 1000, | 477 input: { delay: 1000, |
| 585 fill: "auto", | 478 fill: "auto", |
| 586 iterations: 5.5, | 479 iterations: 5.5, |
| 587 duration: "auto", | 480 duration: "auto", |
| (...skipping 19 matching lines...) Expand all Loading... |
| 607 input: { iterations: Infinity }, | 500 input: { iterations: Infinity }, |
| 608 expected: { iterations: Infinity } }, | 501 expected: { iterations: Infinity } }, |
| 609 { desc: "an auto fill", | 502 { desc: "an auto fill", |
| 610 input: { fill: "auto" }, | 503 input: { fill: "auto" }, |
| 611 expected: { fill: "auto" } }, | 504 expected: { fill: "auto" } }, |
| 612 { desc: "a forwards fill", | 505 { desc: "a forwards fill", |
| 613 input: { fill: "forwards" }, | 506 input: { fill: "forwards" }, |
| 614 expected: { fill: "forwards" } } | 507 expected: { fill: "forwards" } } |
| 615 ]; | 508 ]; |
| 616 | 509 |
| 617 gKeyframeEffectOptionTests.forEach(function(stest) { | |
| 618 test(function(t) { | |
| 619 var effect = new KeyframeEffectReadOnly(target, | |
| 620 {left: ["10px", "20px"]}, | |
| 621 stest.input); | |
| 622 | |
| 623 // Helper function to provide default expected values when the test does | |
| 624 // not supply them. | |
| 625 var expected = function(field, defaultValue) { | |
| 626 return field in stest.expected ? stest.expected[field] : defaultValue; | |
| 627 }; | |
| 628 | |
| 629 var timing = effect.timing; | |
| 630 assert_equals(timing.delay, expected("delay", 0), | |
| 631 "timing delay"); | |
| 632 assert_equals(timing.fill, expected("fill", "auto"), | |
| 633 "timing fill"); | |
| 634 assert_equals(timing.iterations, expected("iterations", 1), | |
| 635 "timing iterations"); | |
| 636 assert_equals(timing.duration, expected("duration", "auto"), | |
| 637 "timing duration"); | |
| 638 assert_equals(timing.direction, expected("direction", "normal"), | |
| 639 "timing direction"); | |
| 640 | |
| 641 }, "a KeyframeEffectReadOnly constructed by " + stest.desc); | |
| 642 }); | |
| 643 | |
| 644 var gInvalidKeyframeEffectOptionTests = [ | 510 var gInvalidKeyframeEffectOptionTests = [ |
| 645 { desc: "-Infinity", | 511 { desc: "-Infinity", |
| 646 input: -Infinity, | 512 input: -Infinity, |
| 647 expected: { name: "TypeError" } }, | 513 expected: { name: "TypeError" } }, |
| 648 { desc: "NaN", | 514 { desc: "NaN", |
| 649 input: NaN, | 515 input: NaN, |
| 650 expected: { name: "TypeError" } }, | 516 expected: { name: "TypeError" } }, |
| 651 { desc: "a negative value", | 517 { desc: "a negative value", |
| 652 input: -1, | 518 input: -1, |
| 653 expected: { name: "TypeError" } }, | 519 expected: { name: "TypeError" } }, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 684 { desc: "an 'inherit' easing", | 550 { desc: "an 'inherit' easing", |
| 685 input: { easing: "inherit" }, | 551 input: { easing: "inherit" }, |
| 686 expected: { name: "TypeError" } }, | 552 expected: { name: "TypeError" } }, |
| 687 { desc: "a variable easing", | 553 { desc: "a variable easing", |
| 688 input: { easing: "var(--x)" }, | 554 input: { easing: "var(--x)" }, |
| 689 expected: { name: "TypeError" } }, | 555 expected: { name: "TypeError" } }, |
| 690 { desc: "a multi-value easing", | 556 { desc: "a multi-value easing", |
| 691 input: { easing: "ease-in-out, ease-out" }, | 557 input: { easing: "ease-in-out, ease-out" }, |
| 692 expected: { name: "TypeError" } } | 558 expected: { name: "TypeError" } } |
| 693 ]; | 559 ]; |
| 694 | |
| 695 gInvalidKeyframeEffectOptionTests.forEach(function(stest) { | |
| 696 test(function(t) { | |
| 697 assert_throws(stest.expected, function() { | |
| 698 new KeyframeEffectReadOnly(target, | |
| 699 { left: ["10px", "20px"] }, | |
| 700 stest.input); | |
| 701 }); | |
| 702 }, "Invalid KeyframeEffectReadOnly option by " + stest.desc); | |
| 703 }); | |
| 704 | |
| 705 test(function(t) { | |
| 706 var effect = new KeyframeEffect(target, | |
| 707 { left: ["10px", "20px"] }); | |
| 708 | |
| 709 assert_class_string(effect, "KeyframeEffect"); | |
| 710 assert_class_string(effect.timing, "AnimationEffectTiming"); | |
| 711 }, "KeyframeEffect constructor creates an AnimationEffectTiming timing object"); | |
| 712 | |
| 713 test(function(t) { | |
| 714 var test_error = { name: "test" }; | |
| 715 | |
| 716 assert_throws(test_error, function() { | |
| 717 new KeyframeEffect(target, { get left() { throw test_error }}) | |
| 718 }); | |
| 719 }, "KeyframeEffect constructor propagates exceptions generated by accessing" | |
| 720 + " the options object"); | |
| 721 | |
| 722 done(); | |
| 723 </script> | |
| 724 </body> | |
| OLD | NEW |