1 2function leftAsNumber(target) { 3 var left = getComputedStyle(target).left; 4 return Number(left.substring(0, left.length - 2)); 5} 6 7suite('effect', function() { 8 // Test normalize. 9 test('Normalize keyframes with all offsets specified but not sorted by offset. Some offsets are out of [0, 1] range.', function() { 10 var normalizedKeyframes; 11 assert.throws(function() { 12 normalizedKeyframes = normalizeKeyframes([ 13 {offset: 0}, 14 {offset: -1}, 15 {offset: 1}, 16 {offset: 0.5}, 17 {offset: 2} 18 ]); 19 }); 20 }); 21 22 test('Normalize keyframes with some offsets not specified, and not sorted by offset.', function() { 23 assert.throws(function() { 24 normalizeKeyframes([ 25 {offset: 0.5}, 26 {offset: 0}, 27 {offset: 0.8}, 28 {}, 29 {offset: 1} 30 ]); 31 }); 32 }); 33 34 test('Normalize keyframes with some offsets not specified, and not sorted by offset. Out of order keyframes are out of [0, 1] range.', function() { 35 assert.throws(function() { 36 normalizeKeyframes([ 37 {offset: 0}, 38 {offset: -1}, 39 {offset: 0.5}, 40 {}, 41 {offset: 1} 42 ]); 43 }); 44 }); 45 46 test('Normalize keyframes with some offsets not specified, but sorted by offset where specified. Some offsets are out of [0, 1] range.', function() { 47 var normalizedKeyframes; 48 assert.doesNotThrow(function() { 49 normalizedKeyframes = normalizeKeyframes([ 50 {offset: -1}, 51 {offset: 0}, 52 {offset: 0.5}, 53 {}, 54 {}, 55 {offset: 2} 56 ]); 57 }); 58 assert.equal(normalizedKeyframes.length, 4); 59 assert.closeTo(normalizedKeyframes[0].offset, 0, 0.001); 60 assert.closeTo(normalizedKeyframes[1].offset, 0.5, 0.001); 61 assert.closeTo(normalizedKeyframes[2].offset, 0.75, 0.001); 62 assert.closeTo(normalizedKeyframes[3].offset, 1, 0.001); 63 }); 64 65 test('Normalize keyframes with some offsets not specified, but sorted by offset where specified. All specified offsets in [0, 1] range.', function() { 66 var normalizedKeyframes; 67 assert.doesNotThrow(function() { 68 normalizedKeyframes = normalizeKeyframes([ 69 {left: '0px', offset: 0}, 70 {left: '10px'}, 71 {left: '20px'}, 72 {left: '30px', offset: 0.6}, 73 {left: '40px'}, 74 {left: '50px'} 75 ]); 76 }); 77 assert.equal(normalizedKeyframes.length, 6); 78 assert.closeTo(normalizedKeyframes[0].offset, 0, 0.001); 79 assert.equal(normalizedKeyframes[0].left, '0px'); 80 assert.closeTo(normalizedKeyframes[1].offset, 0.2, 0.001); 81 assert.equal(normalizedKeyframes[1].left, '10px'); 82 assert.closeTo(normalizedKeyframes[2].offset, 0.4, 0.001); 83 assert.equal(normalizedKeyframes[2].left, '20px'); 84 assert.closeTo(normalizedKeyframes[3].offset, 0.6, 0.001); 85 assert.equal(normalizedKeyframes[3].left, '30px'); 86 assert.closeTo(normalizedKeyframes[4].offset, 0.8, 0.001); 87 assert.equal(normalizedKeyframes[4].left, '40px'); 88 assert.closeTo(normalizedKeyframes[5].offset, 1, 0.001); 89 assert.equal(normalizedKeyframes[5].left, '50px'); 90 }); 91 92 test('Normalize keyframes with no offsets specified.', function() { 93 var normalizedKeyframes; 94 assert.doesNotThrow(function() { 95 normalizedKeyframes = normalizeKeyframes([ 96 {left: '0px'}, 97 {left: '10px'}, 98 {left: '20px'}, 99 {left: '30px'}, 100 {left: '40px'} 101 ]); 102 }); 103 assert.equal(normalizedKeyframes.length, 5); 104 assert.closeTo(normalizedKeyframes[0].offset, 0, 0.001); 105 assert.equal(normalizedKeyframes[0].left, '0px'); 106 assert.closeTo(normalizedKeyframes[1].offset, 0.25, 0.001); 107 assert.equal(normalizedKeyframes[1].left, '10px'); 108 assert.closeTo(normalizedKeyframes[2].offset, 0.5, 0.001); 109 assert.equal(normalizedKeyframes[2].left, '20px'); 110 assert.closeTo(normalizedKeyframes[3].offset, 0.75, 0.001); 111 assert.equal(normalizedKeyframes[3].left, '30px'); 112 assert.closeTo(normalizedKeyframes[4].offset, 1, 0.001); 113 assert.equal(normalizedKeyframes[4].left, '40px'); 114 }); 115 116 test('Normalize keyframes where a keyframe has an offset that is not a number.', function() { 117 assert.throws(function() { 118 normalizeKeyframes([ 119 {offset: 0}, 120 {offset: 'one'}, 121 {offset: 1} 122 ]); 123 }); 124 }); 125 126 test('Normalize keyframes where a keyframe has an offset that is a numeric string.', function() { 127 var normalizedKeyframes; 128 assert.doesNotThrow(function() { 129 normalizedKeyframes = normalizeKeyframes([ 130 {offset: 0}, 131 {offset: '0.5'}, 132 {offset: 1} 133 ]); 134 }); 135 assert.equal(normalizedKeyframes.length, 3); 136 assert.closeTo(normalizedKeyframes[0].offset, 0, 0.001); 137 assert.closeTo(normalizedKeyframes[1].offset, 0.5, 0.001); 138 assert.closeTo(normalizedKeyframes[2].offset, 1, 0.001); 139 }); 140 141 test('Normalize keyframes where some keyframes have easings.', function() { 142 var normalizedKeyframes; 143 assert.doesNotThrow(function() { 144 normalizedKeyframes = normalizeKeyframes([ 145 {left: '0px', easing: 'ease-in'}, 146 {left: '10px'}, 147 {left: '0px'} 148 ]); 149 }); 150 }); 151 152 test('Normalize keyframes with invalid specified easing.', function() { 153 var normalizedKeyframes; 154 assert.doesNotThrow(function() { 155 normalizedKeyframes = normalizeKeyframes([ 156 {left: '0px', easing: 'easy-peasy'}, 157 {left: '10px'}, 158 {left: '0px'} 159 ]); 160 }); 161 assert.equal('' + normalizedKeyframes[0].easing, 'function (x) { return x; }'); 162 }); 163 164 test('Normalize keyframes where some properties are given non-string, non-number values.', function() { 165 var normalizedKeyframes; 166 assert.doesNotThrow(function() { 167 normalizedKeyframes = normalizeKeyframes([ 168 {left: {}}, 169 {left: '100px'}, 170 {left: []} 171 ]); 172 }); 173 assert(normalizedKeyframes.length, 3); 174 assert.equal(normalizedKeyframes[0].left, '[object Object]'); 175 assert.equal(normalizedKeyframes[1].left, '100px'); 176 assert.equal(normalizedKeyframes[2].left, ''); 177 }); 178 179 test('Normalize input that is not an array.', function() { 180 assert.throws(function() { 181 normalizeKeyframes(10); 182 }); 183 }); 184 185 test('Normalize an empty array.', function() { 186 var normalizedKeyframes; 187 assert.doesNotThrow(function() { 188 normalizedKeyframes = normalizeKeyframes([]); 189 }); 190 assert.deepEqual(normalizedKeyframes, []); 191 }); 192 193 test('Normalize null.', function() { 194 var normalizedKeyframes; 195 assert.doesNotThrow(function() { 196 normalizedKeyframes = normalizeKeyframes(null); 197 }); 198 assert.deepEqual(normalizedKeyframes, []); 199 }); 200 201 test('Normalize shorthands.', function() { 202 var normalizedKeyframes; 203 assert.doesNotThrow(function() { 204 normalizedKeyframes = normalizeKeyframes([{borderColor: 'purple green orange blue'}, {borderColor: 'red'}]); 205 }); 206 assert.equal(normalizedKeyframes[0].borderTopColor, 'purple'); 207 assert.equal(normalizedKeyframes[0].borderRightColor, 'green'); 208 assert.equal(normalizedKeyframes[0].borderBottomColor, 'orange'); 209 assert.equal(normalizedKeyframes[0].borderLeftColor, 'blue'); 210 assert.equal(normalizedKeyframes[1].borderTopColor, 'red'); 211 assert.equal(normalizedKeyframes[1].borderRightColor, 'red'); 212 assert.equal(normalizedKeyframes[1].borderBottomColor, 'red'); 213 assert.equal(normalizedKeyframes[1].borderLeftColor, 'red'); 214 215 assert.doesNotThrow(function() { 216 normalizedKeyframes = normalizeKeyframes([{font: 'italic bold 20pt / 200% serif'}, {font: 'italic normal bold 50pt serif'}]); 217 }); 218 assert.equal(normalizedKeyframes[0].fontStyle, 'italic'); 219 assert.equal(normalizedKeyframes[0].fontVariant, 'normal'); 220 assert.equal(normalizedKeyframes[0].fontWeight, '700'); 221 assert.equal(normalizedKeyframes[0].fontSize, '20pt'); 222 assert.equal(normalizedKeyframes[0].lineHeight, '200%'); 223 assert.equal(normalizedKeyframes[0].fontFamily, 'serif'); 224 assert.equal(normalizedKeyframes[1].fontStyle, 'italic'); 225 assert.equal(normalizedKeyframes[1].fontVariant, 'normal'); 226 assert.equal(normalizedKeyframes[1].fontWeight, '700'); 227 assert.equal(normalizedKeyframes[1].fontSize, '50pt'); 228 assert.equal(normalizedKeyframes[1].lineHeight, 'normal'); 229 assert.equal(normalizedKeyframes[1].fontFamily, 'serif'); 230 }); 231 232 // Test makePropertySpecificKeyframeGroups. 233 test('Make property specific keyframe groups for a simple effect with one property.', function() { 234 var groups; 235 assert.doesNotThrow(function() { 236 groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ 237 {left: '0px'}, 238 {left: '200px', offset: 0.3}, 239 {left: '0px'} 240 ])); 241 }); 242 assert.equal(Object.getOwnPropertyNames(groups).length, 1); 243 assert.equal(groups.left.length, 3); 244 assert.closeTo(groups.left[0].offset, 0, 0.001); 245 assert.equal(groups.left[0].value, '0px'); 246 assert.closeTo(groups.left[1].offset, 0.3, 0.001); 247 assert.equal(groups.left[1].value, '200px'); 248 assert.closeTo(groups.left[2].offset, 1, 0.001); 249 assert.equal(groups.left[2].value, '0px'); 250 }); 251 252 test('Make property specific keyframe groups for an effect with three properties.', function() { 253 var groups; 254 assert.doesNotThrow(function() { 255 groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ 256 {left: '0px', top: '200px', opacity: 1}, 257 {left: '200px', top: '0px'}, 258 {left: '0px', top: '200px', opacity: 0}, 259 {top: '0px', opacity: 1}, 260 {left: '200px', top: '200px', opacity: 0} 261 ])); 262 }); 263 assert.equal(Object.getOwnPropertyNames(groups).length, 3); 264 265 assert.equal(groups.left.length, 4); 266 assert.closeTo(groups.left[0].offset, 0, 0.001); 267 assert.equal(groups.left[0].value, '0px'); 268 assert.closeTo(groups.left[1].offset, 0.25, 0.001); 269 assert.equal(groups.left[1].value, '200px'); 270 assert.closeTo(groups.left[2].offset, 0.5, 0.001); 271 assert.equal(groups.left[2].value, '0px'); 272 assert.closeTo(groups.left[3].offset, 1, 0.001); 273 assert.equal(groups.left[3].value, '200px'); 274 275 assert.equal(groups.top.length, 5); 276 assert.closeTo(groups.top[0].offset, 0, 0.001); 277 assert.equal(groups.top[0].value, '200px'); 278 assert.closeTo(groups.top[1].offset, 0.25, 0.001); 279 assert.equal(groups.top[1].value, '0px'); 280 assert.closeTo(groups.top[2].offset, 0.5, 0.001); 281 assert.equal(groups.top[2].value, '200px'); 282 assert.closeTo(groups.top[3].offset, 0.75, 0.001); 283 assert.equal(groups.top[3].value, '0px'); 284 assert.closeTo(groups.top[4].offset, 1, 0.001); 285 assert.equal(groups.top[4].value, '200px'); 286 287 assert.equal(groups.opacity.length, 4); 288 assert.closeTo(groups.opacity[0].offset, 0, 0.001); 289 assert.equal(groups.opacity[0].value, 1); 290 assert.closeTo(groups.opacity[1].offset, 0.5, 0.001); 291 assert.equal(groups.opacity[1].value, 0); 292 assert.closeTo(groups.opacity[2].offset, 0.75, 0.001); 293 assert.equal(groups.opacity[2].value, 1); 294 assert.closeTo(groups.opacity[3].offset, 1, 0.001); 295 assert.equal(groups.opacity[3].value, 0); 296 }); 297 298 test('Make property specific keyframes when the offset of the last keyframe is specified but not equal to 1.', function() { 299 assert.throws(function() { 300 makePropertySpecificKeyframeGroups(normalizeKeyframes([ 301 {left: '0px', offset: 0}, 302 {left: '20px'}, 303 {left: '30px', offset: 0.9} 304 ])); 305 }); 306 }); 307 308 test('Make property specific keyframes when no properties are animated, and the offset of the last keyframe is specified but not equal to 1.', function() { 309 var groups; 310 assert.doesNotThrow(function() { 311 groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ 312 {offset: 0}, 313 {}, 314 {offset: 0.9} 315 ])); 316 }); 317 assert.equal(Object.getOwnPropertyNames(groups).length, 0); 318 }); 319 320 test('Make property specific keyframes when a property appears in some keyframes, but not in the last keyframe.', function() { 321 assert.throws(function() { 322 makePropertySpecificKeyframeGroups(normalizeKeyframes([ 323 {left: '0px', top: '0px'}, 324 {left: '10px', top: '10px'}, 325 {top: '20px'} 326 ])); 327 }); 328 }); 329 330 test('Make property specific keyframes when a property appears in some keyframes, but not in the first keyframe.', function() { 331 assert.throws(function() { 332 makePropertySpecificKeyframeGroups(normalizeKeyframes([ 333 {left: '0px'}, 334 {left: '10px', top: '10px'}, 335 {left: '20px', top: '20px'} 336 ])); 337 }); 338 }); 339 340 test('Make property specific keyframes where two properties are animated. One property in a keyframe with offset 1. One property in the last keyframe, with no offset.', function() { 341 var groups; 342 assert.doesNotThrow(function() { 343 groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ 344 {left: '0px', top: '0px', offset: 0}, 345 {left: '20px', offset: 1}, 346 {top: '20px'} 347 ])); 348 }); 349 assert.equal(Object.getOwnPropertyNames(groups).length, 2); 350 }); 351 352 test('Make property specific keyframes where two properties are animated. One property in a keyframe with offset 0. One property in the first keyframe, with no offset.', function() { 353 var groups; 354 assert.doesNotThrow(function() { 355 groups = makePropertySpecificKeyframeGroups(normalizeKeyframes([ 356 {top: '0px'}, 357 {left: '0px', offset: 0}, 358 {left: '20px', top: '20px', offset: 1} 359 ])); 360 }); 361 assert.equal(Object.getOwnPropertyNames(groups).length, 2); 362 }); 363 364 // Test per-keyframe easings. 365 test('Apply keyframe easings.', function() { 366 var target1 = document.createElement('div'); 367 var target2 = document.createElement('div'); 368 target1.style.position = 'absolute'; 369 target2.style.position = 'absolute'; 370 document.body.appendChild(target1); 371 document.body.appendChild(target2); 372 373 var player1 = target1.animate( 374 [ 375 {left: '0px'}, 376 {left: '50px', offset: 0.25}, 377 {left: '0px'} 378 ], 379 {duration: 4000, fill: 'forwards'}); 380 var player2 = target2.animate( 381 [ 382 {left: '0px', easing: 'ease-in'}, 383 {left: '50px', offset: 0.25}, 384 {left: '0px'} 385 ], 386 {duration: 4000, fill: 'forwards'}); 387 388 tick(0); 389 assert.equal(leftAsNumber(target1), 0); 390 assert.equal(leftAsNumber(target2), 0); 391 tick(250); 392 assert.closeTo(leftAsNumber(target1), 12.5, 1); 393 assert.closeTo(leftAsNumber(target2), 4.65, 1); 394 tick(500); 395 assert.closeTo(leftAsNumber(target1), 25, 1); 396 assert.closeTo(leftAsNumber(target2), 15.25, 1); 397 tick(1000); 398 assert.equal(leftAsNumber(target1), 50); 399 assert.equal(leftAsNumber(target2), 50); 400 401 tick(2500); 402 assert.equal(leftAsNumber(target1), 25); 403 assert.equal(leftAsNumber(target2), 25); 404 tick(4000); 405 assert.equal(leftAsNumber(target1), 0); 406 assert.equal(leftAsNumber(target2), 0); 407 }); 408 409 // Test makeInterpolations. 410 test('Make interpolations for a simple effect with one property.', function() { 411 var interpolations; 412 assert.doesNotThrow(function() { 413 interpolations = makeInterpolations(makePropertySpecificKeyframeGroups(normalizeKeyframes([ 414 {left: '0px'}, 415 {left: '200px', offset: 0.3}, 416 {left: '0px'} 417 ]))); 418 }); 419 assert.equal(interpolations.length, 2); 420 421 assert.closeTo(interpolations[0].startTime, 0, 0.001); 422 assert.closeTo(interpolations[0].endTime, 0.3, 0.001); 423 assert.equal(interpolations[0].property, 'left'); 424 assert.equal(typeof interpolations[0].interpolation, 'function'); 425 426 assert.closeTo(interpolations[1].startTime, 0.3, 0.001); 427 assert.closeTo(interpolations[1].endTime, 1, 0.001); 428 assert.equal(interpolations[1].property, 'left'); 429 assert.equal(typeof interpolations[1].interpolation, 'function'); 430 }); 431}); 432 433suite('effect-convertEffectInput', function() { 434 setup(function() { 435 this.target = document.createElement('div'); 436 this.target.style.position = 'absolute'; 437 document.documentElement.appendChild(this.target); 438 }); 439 teardown(function() { 440 if (this.target.parent) 441 this.target.removeChild(this.target); 442 }); 443 444 test('Convert effect input for a simple effect with one property.', function() { 445 var effectFunction; 446 assert.doesNotThrow(function() { 447 effectFunction = webAnimations1.convertEffectInput([ 448 {left: '0px'}, 449 {left: '200px', offset: 0.3}, 450 {left: '100px'} 451 ]); 452 }); 453 454 effectFunction(this.target, 0); 455 assert.closeTo(leftAsNumber(this.target), 0, 0.001); 456 effectFunction(this.target, 0.075); 457 assert.closeTo(leftAsNumber(this.target), 50, 0.001); 458 effectFunction(this.target, 0.15); 459 assert.closeTo(leftAsNumber(this.target), 100, 0.001); 460 effectFunction(this.target, 0.65); 461 assert.closeTo(leftAsNumber(this.target), 150, 0.001); 462 effectFunction(this.target, 1); 463 assert.closeTo(leftAsNumber(this.target), 100, 0.001); 464 effectFunction(this.target, 2); 465 assert.closeTo(leftAsNumber(this.target), -42.856, 0.01); 466 }); 467 468 test('Convert effect input where one property is animated and the property has two keyframes at offset 1.', function() { 469 var effectFunction; 470 assert.doesNotThrow(function() { 471 effectFunction = webAnimations1.convertEffectInput([ 472 {left: '0px', offset: 0}, 473 {left: '20px', offset: 1}, 474 {left: '30px'} 475 ]); 476 }); 477 effectFunction(this.target, 1); 478 assert.equal(getComputedStyle(this.target).left, '30px'); 479 effectFunction(this.target, 2); 480 assert.equal(getComputedStyle(this.target).left, '30px'); 481 }); 482 483 test('Convert effect input and apply effect at fraction null.', function() { 484 var effectFunction; 485 var underlying = getComputedStyle(this.target).left; 486 assert.doesNotThrow(function() { 487 effectFunction = webAnimations1.convertEffectInput([ 488 {left: '0px'}, 489 {left: '100px'} 490 ]); 491 }); 492 493 effectFunction(this.target, 1); 494 assert.equal(getComputedStyle(this.target).left, '100px'); 495 effectFunction(this.target, null); 496 assert.equal(getComputedStyle(this.target).left, underlying); 497 }); 498}); 499