| OLD | NEW |
| (Empty) |
| 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"; | |
| 19 | |
| 20 var target = document.getElementById("target"); | |
| 21 | |
| 22 function assert_frames_equal(a, b, name) { | |
| 23 assert_equals(Object.keys(a).sort().toString(), | |
| 24 Object.keys(b).sort().toString(), | |
| 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 | |
| 31 function assert_frame_lists_equal(a, b) { | |
| 32 assert_equals(a.length, b.length, "number of frames"); | |
| 33 for (var i = 0; i < Math.min(a.length, b.length); i++) { | |
| 34 assert_frames_equal(a[i], b[i], "ComputedKeyframe #" + i); | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 var gEmptyKeyframeListTests = [ | |
| 39 [], | |
| 40 null, | |
| 41 undefined, | |
| 42 ]; | |
| 43 | |
| 44 test(function(t) { | |
| 45 gEmptyKeyframeListTests.forEach(function(frames) { | |
| 46 assert_equals(new KeyframeEffectReadOnly(target, frames).getFrames().length, | |
| 47 0, "number of frames for " + JSON.stringify(frames)); | |
| 48 }); | |
| 49 }, "a KeyframeEffectReadOnly can be constructed with no frames"); | |
| 50 | |
| 51 // [specified easing value, expected easing value] | |
| 52 var gEasingValueTests = [ | |
| 53 ["linear", "linear"], | |
| 54 ["ease-in-out", "ease-in-out"], | |
| 55 ["Ease\\2d in-out", "ease-in-out"], | |
| 56 ["ease /**/", "ease"], | |
| 57 ]; | |
| 58 | |
| 59 test(function(t) { | |
| 60 gEasingValueTests.forEach(function(subtest) { | |
| 61 var easing = subtest[0]; | |
| 62 var expected = subtest[1]; | |
| 63 var effect = new KeyframeEffectReadOnly(target, { | |
| 64 left: ["10px", "20px"], | |
| 65 easing: easing | |
| 66 }); | |
| 67 assert_equals(effect.getFrames()[0].easing, expected, | |
| 68 "resulting easing for '" + easing + "'"); | |
| 69 }); | |
| 70 }, "easing values are parsed correctly when passed to the " + | |
| 71 "KeyframeEffectReadOnly constructor in a property-indexed keyframe"); | |
| 72 | |
| 73 test(function(t) { | |
| 74 gEasingValueTests.forEach(function(subtest) { | |
| 75 var easing = subtest[0]; | |
| 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 | |
| 100 var gGoodKeyframeCompositeValueTests = [ | |
| 101 "replace", "add", "accumulate", undefined | |
| 102 ]; | |
| 103 | |
| 104 var gGoodOptionsCompositeValueTests = [ | |
| 105 "replace", "add", "accumulate" | |
| 106 ]; | |
| 107 | |
| 108 var gBadCompositeValueTests = [ | |
| 109 "unrecognised", "replace ", "Replace", null | |
| 110 ]; | |
| 111 | |
| 112 test(function(t) { | |
| 113 var getFrame = function(composite) { | |
| 114 return { left: [ "10px", "20px" ], composite: composite }; | |
| 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 | |
| 129 test(function(t) { | |
| 130 var getFrames = function(composite) { | |
| 131 return [ | |
| 132 { offset: 0, left: "10px", composite: composite }, | |
| 133 { offset: 1, left: "20px" } | |
| 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 | |
| 167 var gPropertyIndexedKeyframesTests = [ | |
| 168 { desc: "a one property two value property-indexed keyframes specification", | |
| 169 input: { left: ["10px", "20px"] }, | |
| 170 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 171 left: "10px" }, | |
| 172 { offset: null, computedOffset: 1, easing: "linear", | |
| 173 left: "20px" }] }, | |
| 174 { desc: "a one shorthand property two value property-indexed keyframes" | |
| 175 + " specification", | |
| 176 input: { margin: ["10px", "10px 20px 30px 40px"] }, | |
| 177 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 178 margin: "10px" }, | |
| 179 { offset: null, computedOffset: 1, easing: "linear", | |
| 180 margin: "10px 20px 30px 40px" }] }, | |
| 181 { desc: "a two property (one shorthand and one of its longhand components)" | |
| 182 + " two value property-indexed keyframes specification", | |
| 183 input: { marginTop: ["50px", "60px"], | |
| 184 margin: ["10px", "10px 20px 30px 40px"] }, | |
| 185 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 186 marginTop: "50px", margin: "10px" }, | |
| 187 { offset: null, computedOffset: 1, easing: "linear", | |
| 188 marginTop: "60px", margin: "10px 20px 30px 40px" }] }, | |
| 189 { desc: "a two property two value property-indexed keyframes specification", | |
| 190 input: { left: ["10px", "20px"], | |
| 191 top: ["30px", "40px"] }, | |
| 192 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 193 left: "10px", top: "30px" }, | |
| 194 { offset: null, computedOffset: 1, easing: "linear", | |
| 195 left: "20px", top: "40px" }] }, | |
| 196 { desc: "a two property property-indexed keyframes specification with" | |
| 197 + " different numbers of values", | |
| 198 input: { left: ["10px", "20px", "30px"], | |
| 199 top: ["40px", "50px"] }, | |
| 200 output: [{ offset: null, computedOffset: 0.0, easing: "linear", | |
| 201 left: "10px", top: "40px" }, | |
| 202 { offset: null, computedOffset: 0.5, easing: "linear", | |
| 203 left: "20px" }, | |
| 204 { offset: null, computedOffset: 1.0, easing: "linear", | |
| 205 left: "30px", top: "50px" }] }, | |
| 206 { desc: "a property-indexed keyframes specification with an invalid value", | |
| 207 input: { left: ["10px", "20px", "30px", "40px", "50px"], | |
| 208 top: ["15px", "25px", "invalid", "45px", "55px"] }, | |
| 209 output: [{ offset: null, computedOffset: 0.00, easing: "linear", | |
| 210 left: "10px", top: "15px" }, | |
| 211 { offset: null, computedOffset: 0.25, easing: "linear", | |
| 212 left: "20px", top: "25px" }, | |
| 213 { offset: null, computedOffset: 0.50, easing: "linear", | |
| 214 left: "30px", top: "invalid" }, | |
| 215 { offset: null, computedOffset: 0.75, easing: "linear", | |
| 216 left: "40px", top: "45px" }, | |
| 217 { offset: null, computedOffset: 1.00, easing: "linear", | |
| 218 left: "50px", top: "55px" }] }, | |
| 219 { desc: "a one property two value property-indexed keyframes specification" | |
| 220 + " that needs to stringify its values", | |
| 221 input: { opacity: [0, 1] }, | |
| 222 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 223 opacity: "0" }, | |
| 224 { offset: null, computedOffset: 1, easing: "linear", | |
| 225 opacity: "1" }] }, | |
| 226 { desc: "a one property one value property-indexed keyframes specification", | |
| 227 input: { left: ["10px"] }, | |
| 228 output: [{ offset: null, computedOffset: 1, easing: "linear", | |
| 229 left: "10px" }] }, | |
| 230 { desc: "a one property one non-array value property-indexed keyframes" | |
| 231 + " specification", | |
| 232 input: { left: "10px" }, | |
| 233 output: [{ offset: null, computedOffset: 1, easing: "linear", | |
| 234 left: "10px" }] }, | |
| 235 { desc: "a one property two value property-indexed keyframes specification" | |
| 236 + " where the first value is invalid", | |
| 237 input: { left: ["invalid", "10px"] }, | |
| 238 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 239 left: "invalid" }, | |
| 240 { offset: null, computedOffset: 1, easing: "linear", | |
| 241 left: "10px" }] }, | |
| 242 { desc: "a one property two value property-indexed keyframes specification" | |
| 243 + " where the second value is invalid", | |
| 244 input: { left: ["10px", "invalid"] }, | |
| 245 output: [{ offset: null, computedOffset: 0, easing: "linear", | |
| 246 left: "10px" }, | |
| 247 { offset: null, computedOffset: 1, easing: "linear", | |
| 248 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 ]; | |
| 282 | |
| 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 = [ | |
| 318 { desc: "a one property two keyframe sequence", | |
| 319 input: [{ offset: 0, left: "10px" }, | |
| 320 { offset: 1, left: "20px" }], | |
| 321 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | |
| 322 { offset: 1, computedOffset: 1, easing: "linear", left: "20px" }] | |
| 323 }, | |
| 324 { desc: "a two property two keyframe sequence", | |
| 325 input: [{ offset: 0, left: "10px", top: "30px" }, | |
| 326 { offset: 1, left: "20px", top: "40px" }], | |
| 327 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 328 left: "10px", top: "30px" }, | |
| 329 { offset: 1, computedOffset: 1, easing: "linear", | |
| 330 left: "20px", top: "40px" }] }, | |
| 331 { desc: "a one shorthand property two keyframe sequence", | |
| 332 input: [{ offset: 0, margin: "10px" }, | |
| 333 { offset: 1, margin: "20px 30px 40px 50px" }], | |
| 334 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 335 margin: "10px" }, | |
| 336 { offset: 1, computedOffset: 1, easing: "linear", | |
| 337 margin: "20px 30px 40px 50px" }] }, | |
| 338 { desc: "a two property (a shorthand and one of its component longhands)" | |
| 339 + " two keyframe sequence", | |
| 340 input: [{ offset: 0, margin: "10px", marginTop: "20px" }, | |
| 341 { offset: 1, marginTop: "70px", margin: "30px 40px 50px 60px" }], | |
| 342 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 343 margin: "10px", marginTop: "20px" }, | |
| 344 { offset: 1, computedOffset: 1, easing: "linear", | |
| 345 marginTop: "70px", margin: "30px 40px 50px 60px" }] }, | |
| 346 { desc: "a keyframe sequence with duplicate values for a given interior" | |
| 347 + " offset", | |
| 348 input: [{ offset: 0.0, left: "10px" }, | |
| 349 { offset: 0.5, left: "20px" }, | |
| 350 { offset: 0.5, left: "30px" }, | |
| 351 { offset: 0.5, left: "40px" }, | |
| 352 { offset: 1.0, left: "50px" }], | |
| 353 output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear", | |
| 354 left: "10px" }, | |
| 355 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 356 left: "20px" }, | |
| 357 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 358 left: "30px" }, | |
| 359 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 360 left: "40px" }, | |
| 361 { offset: 1.0, computedOffset: 1.0, easing: "linear", | |
| 362 left: "50px" }] }, | |
| 363 { desc: "a keyframe sequence with duplicate values for offsets 0 and 1", | |
| 364 input: [{ offset: 0, left: "10px" }, | |
| 365 { offset: 0, left: "20px" }, | |
| 366 { offset: 0, left: "30px" }, | |
| 367 { offset: 1, left: "40px" }, | |
| 368 { offset: 1, left: "50px" }, | |
| 369 { offset: 1, left: "60px" }], | |
| 370 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | |
| 371 { offset: 0, computedOffset: 0, easing: "linear", left: "20px" }, | |
| 372 { offset: 0, computedOffset: 0, easing: "linear", left: "30px" }, | |
| 373 { offset: 1, computedOffset: 1, easing: "linear", left: "40px" }, | |
| 374 { offset: 1, computedOffset: 1, easing: "linear", left: "50px" }, | |
| 375 { offset: 1, computedOffset: 1, easing: "linear", left: "60px" }] | |
| 376 }, | |
| 377 { desc: "a two property four keyframe sequence", | |
| 378 input: [{ offset: 0, left: "10px" }, | |
| 379 { offset: 0, top: "20px" }, | |
| 380 { offset: 1, top: "30px" }, | |
| 381 { offset: 1, left: "40px" }], | |
| 382 output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" }, | |
| 383 { offset: 0, computedOffset: 0, easing: "linear", top: "20px" }, | |
| 384 { offset: 1, computedOffset: 1, easing: "linear", top: "30px" }, | |
| 385 { offset: 1, computedOffset: 1, easing: "linear", left: "40px" }] | |
| 386 }, | |
| 387 { desc: "a one property keyframe sequence with some omitted offsets", | |
| 388 input: [{ offset: 0.00, left: "10px" }, | |
| 389 { offset: 0.25, left: "20px" }, | |
| 390 { left: "30px" }, | |
| 391 { left: "40px" }, | |
| 392 { offset: 1.00, left: "50px" }], | |
| 393 output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", | |
| 394 left: "10px" }, | |
| 395 { offset: 0.25, computedOffset: 0.25, easing: "linear", | |
| 396 left: "20px" }, | |
| 397 { offset: null, computedOffset: 0.50, easing: "linear", | |
| 398 left: "30px" }, | |
| 399 { offset: null, computedOffset: 0.75, easing: "linear", | |
| 400 left: "40px" }, | |
| 401 { offset: 1.00, computedOffset: 1.00, easing: "linear", | |
| 402 left: "50px" }] }, | |
| 403 { desc: "a two property keyframe sequence with some omitted offsets", | |
| 404 input: [{ offset: 0.00, left: "10px", top: "20px" }, | |
| 405 { offset: 0.25, left: "30px" }, | |
| 406 { left: "40px" }, | |
| 407 { left: "50px", top: "60px" }, | |
| 408 { offset: 1.00, left: "70px", top: "80px" }], | |
| 409 output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", | |
| 410 left: "10px", top: "20px" }, | |
| 411 { offset: 0.25, computedOffset: 0.25, easing: "linear", | |
| 412 left: "30px" }, | |
| 413 { offset: null, computedOffset: 0.50, easing: "linear", | |
| 414 left: "40px" }, | |
| 415 { offset: null, computedOffset: 0.75, easing: "linear", | |
| 416 left: "50px", top: "60px" }, | |
| 417 { offset: 1.00, computedOffset: 1.00, easing: "linear", | |
| 418 left: "70px", top: "80px" }] }, | |
| 419 { desc: "a one property keyframe sequence with all omitted offsets", | |
| 420 input: [{ left: "10px" }, | |
| 421 { left: "20px" }, | |
| 422 { left: "30px" }, | |
| 423 { left: "40px" }, | |
| 424 { left: "50px" }], | |
| 425 output: [{ offset: null, computedOffset: 0.00, easing: "linear", | |
| 426 left: "10px" }, | |
| 427 { offset: null, computedOffset: 0.25, easing: "linear", | |
| 428 left: "20px" }, | |
| 429 { offset: null, computedOffset: 0.50, easing: "linear", | |
| 430 left: "30px" }, | |
| 431 { offset: null, computedOffset: 0.75, easing: "linear", | |
| 432 left: "40px" }, | |
| 433 { offset: null, computedOffset: 1.00, easing: "linear", | |
| 434 left: "50px" }] }, | |
| 435 { desc: "a keyframe sequence with different easing values, but the same" | |
| 436 + " easing value for a given offset", | |
| 437 input: [{ offset: 0.0, easing: "ease", left: "10px"}, | |
| 438 { offset: 0.0, easing: "ease", top: "20px"}, | |
| 439 { offset: 0.5, easing: "linear", left: "30px" }, | |
| 440 { offset: 0.5, easing: "linear", top: "40px" }, | |
| 441 { offset: 1.0, easing: "step-end", left: "50px" }, | |
| 442 { offset: 1.0, easing: "step-end", top: "60px" }], | |
| 443 output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease", | |
| 444 left: "10px" }, | |
| 445 { offset: 0.0, computedOffset: 0.0, easing: "ease", | |
| 446 top: "20px" }, | |
| 447 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 448 left: "30px" }, | |
| 449 { offset: 0.5, computedOffset: 0.5, easing: "linear", | |
| 450 top: "40px" }, | |
| 451 { offset: 1.0, computedOffset: 1.0, easing: "step-end", | |
| 452 left: "50px" }, | |
| 453 { offset: 1.0, computedOffset: 1.0, easing: "step-end", | |
| 454 top: "60px" }] }, | |
| 455 { desc: "a keyframe sequence with different composite values, but the" | |
| 456 + " same composite value for a given offset", | |
| 457 input: [{ offset: 0.0, composite: "replace", left: "10px" }, | |
| 458 { offset: 0.0, composite: "replace", top: "20px" }, | |
| 459 { offset: 0.5, composite: "add", left: "30px" }, | |
| 460 { offset: 0.5, composite: "add", top: "40px" }, | |
| 461 { offset: 1.0, composite: "replace", left: "50px" }, | |
| 462 { offset: 1.0, composite: "replace", top: "60px" }], | |
| 463 output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear", | |
| 464 composite: "replace", left: "10px" }, | |
| 465 { offset: 0.0, computedOffset: 0.0, easing: "linear", | |
| 466 composite: "replace", top: "20px" }, | |
| 467 { offset: 0.5, computedOffset: 0.0, easing: "linear", | |
| 468 composite: "add", left: "30px" }, | |
| 469 { offset: 0.5, computedOffset: 0.0, easing: "linear", | |
| 470 composite: "add", top: "40px" }, | |
| 471 { offset: 1.0, computedOffset: 1.0, easing: "linear", | |
| 472 composite: "replace", left: "50px" }, | |
| 473 { offset: 1.0, computedOffset: 1.0, easing: "linear", | |
| 474 composite: "replace", top: "60px" }] }, | |
| 475 { desc: "a one property two keyframe sequence that needs to stringify" | |
| 476 + " its values", | |
| 477 input: [{ offset: 0, opacity: 0 }, | |
| 478 { offset: 1, opacity: 1 }], | |
| 479 output: [{ offset: 0, computedOffset: 0, easing: "linear", opacity: "0" }, | |
| 480 { offset: 1, computedOffset: 1, easing: "linear", opacity: "1" }] | |
| 481 }, | |
| 482 { desc: "a keyframe sequence where shorthand precedes longhand", | |
| 483 input: [{ offset: 0, margin: "10px", marginRight: "20px" }, | |
| 484 { offset: 1, margin: "30px" }], | |
| 485 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 486 margin: "10px", marginRight: "20px" }, | |
| 487 { offset: 1, computedOffset: 1, easing: "linear", | |
| 488 margin: "30px" }] }, | |
| 489 { desc: "a keyframe sequence where longhand precedes shorthand", | |
| 490 input: [{ offset: 0, marginRight: "20px", margin: "10px" }, | |
| 491 { offset: 1, margin: "30px" }], | |
| 492 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 493 marginRight: "20px", margin: "10px" }, | |
| 494 { offset: 1, computedOffset: 1, easing: "linear", | |
| 495 margin: "30px" }] }, | |
| 496 { desc: "a keyframe sequence where lesser shorthand precedes greater" | |
| 497 + " shorthand", | |
| 498 input: [{ offset: 0, | |
| 499 borderLeft: "1px solid rgb(1, 2, 3)", | |
| 500 border: "2px dotted rgb(4, 5, 6)" }, | |
| 501 { offset: 1, border: "3px dashed rgb(7, 8, 9)" }], | |
| 502 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 503 borderLeft: "1px solid rgb(1, 2, 3)", | |
| 504 border: "2px dotted rgb(4, 5, 6)" }, | |
| 505 { offset: 1, computedOffset: 1, easing: "linear", | |
| 506 border: "3px dashed rgb(7, 8, 9)" }] }, | |
| 507 { desc: "a keyframe sequence where greater shorthand precedes lesser" | |
| 508 + " shorthand", | |
| 509 input: [{ offset: 0, border: "2px dotted rgb(4, 5, 6)", | |
| 510 borderLeft: "1px solid rgb(1, 2, 3)" }, | |
| 511 { offset: 1, border: "3px dashed rgb(7, 8, 9)" }], | |
| 512 output: [{ offset: 0, computedOffset: 0, easing: "linear", | |
| 513 border: "2px dotted rgb(4, 5, 6)", | |
| 514 borderLeft: "1px solid rgb(1, 2, 3)" }, | |
| 515 { offset: 1, computedOffset: 1, easing: "linear", | |
| 516 border: "3px dashed rgb(7, 8, 9)" }] }, | |
| 517 ]; | |
| 518 | |
| 519 gKeyframeSequenceTests.forEach(function(subtest) { | |
| 520 test(function(t) { | |
| 521 var effect = new KeyframeEffectReadOnly(target, subtest.input); | |
| 522 assert_frame_lists_equal(effect.getFrames(), subtest.output); | |
| 523 }, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc); | |
| 524 | |
| 525 test(function(t) { | |
| 526 var effect = new KeyframeEffectReadOnly(target, subtest.input); | |
| 527 var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames()); | |
| 528 assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames()); | |
| 529 }, "a KeyframeEffectReadOnly constructed with " + subtest.desc + | |
| 530 " roundtrips"); | |
| 531 }); | |
| 532 | |
| 533 var gInvalidEasingInKeyframeSequenceTests = [ | |
| 534 { desc: "a blank easing", | |
| 535 input: [{ easing: "" }] }, | |
| 536 { desc: "an unrecognized easing", | |
| 537 input: [{ easing: "unrecognized" }] }, | |
| 538 { desc: "an 'initial' easing", | |
| 539 input: [{ easing: "initial" }] }, | |
| 540 { desc: "an 'inherit' easing", | |
| 541 input: [{ easing: "inherit" }] }, | |
| 542 { desc: "a variable easing", | |
| 543 input: [{ easing: "var(--x)" }] }, | |
| 544 { desc: "a multi-value easing", | |
| 545 input: [{ easing: "ease-in-out, ease-out" }] } | |
| 546 ]; | |
| 547 | |
| 548 gInvalidEasingInKeyframeSequenceTests.forEach(function(subtest) { | |
| 549 test(function(t) { | |
| 550 assert_throws(new TypeError, function() { | |
| 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 | |
| 579 var gKeyframeEffectOptionTests = [ | |
| 580 { desc: "an empty KeyframeEffectOptions object", | |
| 581 input: { }, | |
| 582 expected: { } }, | |
| 583 { desc: "a normal KeyframeEffectOptions object", | |
| 584 input: { delay: 1000, | |
| 585 fill: "auto", | |
| 586 iterations: 5.5, | |
| 587 duration: "auto", | |
| 588 direction: "alternate" }, | |
| 589 expected: { delay: 1000, | |
| 590 fill: "auto", | |
| 591 iterations: 5.5, | |
| 592 duration: "auto", | |
| 593 direction: "alternate" } }, | |
| 594 { desc: "a double value", | |
| 595 input: 3000, | |
| 596 expected: { duration: 3000 } }, | |
| 597 { desc: "+Infinity", | |
| 598 input: Infinity, | |
| 599 expected: { duration: Infinity } }, | |
| 600 { desc: "an Infinity duration", | |
| 601 input: { duration: Infinity }, | |
| 602 expected: { duration: Infinity } }, | |
| 603 { desc: "an auto duration", | |
| 604 input: { duration: "auto" }, | |
| 605 expected: { duration: "auto" } }, | |
| 606 { desc: "an Infinity iterations", | |
| 607 input: { iterations: Infinity }, | |
| 608 expected: { iterations: Infinity } }, | |
| 609 { desc: "an auto fill", | |
| 610 input: { fill: "auto" }, | |
| 611 expected: { fill: "auto" } }, | |
| 612 { desc: "a forwards fill", | |
| 613 input: { fill: "forwards" }, | |
| 614 expected: { fill: "forwards" } } | |
| 615 ]; | |
| 616 | |
| 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 = [ | |
| 645 { desc: "-Infinity", | |
| 646 input: -Infinity, | |
| 647 expected: { name: "TypeError" } }, | |
| 648 { desc: "NaN", | |
| 649 input: NaN, | |
| 650 expected: { name: "TypeError" } }, | |
| 651 { desc: "a negative value", | |
| 652 input: -1, | |
| 653 expected: { name: "TypeError" } }, | |
| 654 { desc: "a negative Infinity duration", | |
| 655 input: { duration: -Infinity }, | |
| 656 expected: { name: "TypeError" } }, | |
| 657 { desc: "a NaN duration", | |
| 658 input: { duration: NaN }, | |
| 659 expected: { name: "TypeError" } }, | |
| 660 { desc: "a negative duration", | |
| 661 input: { duration: -1 }, | |
| 662 expected: { name: "TypeError" } }, | |
| 663 { desc: "a string duration", | |
| 664 input: { duration: "merrychristmas" }, | |
| 665 expected: { name: "TypeError" } }, | |
| 666 { desc: "a negative Infinity iterations", | |
| 667 input: { iterations: -Infinity}, | |
| 668 expected: { name: "TypeError" } }, | |
| 669 { desc: "a NaN iterations", | |
| 670 input: { iterations: NaN }, | |
| 671 expected: { name: "TypeError" } }, | |
| 672 { desc: "a negative iterations", | |
| 673 input: { iterations: -1 }, | |
| 674 expected: { name: "TypeError" } }, | |
| 675 { desc: "a blank easing", | |
| 676 input: { easing: "" }, | |
| 677 expected: { name: "TypeError" } }, | |
| 678 { desc: "an unrecognized easing", | |
| 679 input: { easing: "unrecognised" }, | |
| 680 expected: { name: "TypeError" } }, | |
| 681 { desc: "an 'initial' easing", | |
| 682 input: { easing: "initial" }, | |
| 683 expected: { name: "TypeError" } }, | |
| 684 { desc: "an 'inherit' easing", | |
| 685 input: { easing: "inherit" }, | |
| 686 expected: { name: "TypeError" } }, | |
| 687 { desc: "a variable easing", | |
| 688 input: { easing: "var(--x)" }, | |
| 689 expected: { name: "TypeError" } }, | |
| 690 { desc: "a multi-value easing", | |
| 691 input: { easing: "ease-in-out, ease-out" }, | |
| 692 expected: { name: "TypeError" } } | |
| 693 ]; | |
| 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 |