| <!doctype html> |
| <meta charset="utf-8"> |
| <body> |
| <script> |
| onload = function() { |
| |
| log('Sanity tests:'); |
| assertIterationTime('1s linear', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0.5, at: 0.5}, |
| {is: 0.2, at: 0.2}, |
| {is: 0.8, at: 0.8}, |
| {is: null, at: 2}, |
| ]); |
| |
| |
| log('\nFill-mode:'); |
| assertIterationTime('1s none', [ |
| {is: null, at: -1}, |
| {is: null, at: 2}, |
| ]); |
| |
| assertIterationTime('1s both', [ |
| {is: 0, at: -1}, |
| {is: 1, at: 2}, |
| ]); |
| |
| assertIterationTime('1s forwards', [ |
| {is: null, at: -1}, |
| {is: 1, at: 2}, |
| ]); |
| |
| assertIterationTime('1s backwards', [ |
| {is: 0, at: -1}, |
| {is: null, at: 2}, |
| ]); |
| |
| |
| log('\nFill-mode + reverse direction:'); |
| assertIterationTime('1s none reverse', [ |
| {is: null, at: -1}, |
| {is: null, at: 2}, |
| ]); |
| |
| assertIterationTime('1s both reverse', [ |
| {is: 1, at: -1}, |
| {is: 0, at: 2}, |
| ]); |
| |
| assertIterationTime('1s forwards reverse', [ |
| {is: null, at: -1}, |
| {is: 0, at: 2}, |
| ]); |
| |
| assertIterationTime('1s backwards reverse', [ |
| {is: 1, at: -1}, |
| {is: null, at: 2}, |
| ]); |
| |
| |
| log('\nEnd exclusive timing:') |
| assertIterationTime('1s', [ |
| {is: null, at: 1}, |
| ]); |
| |
| |
| log('\nZero duration:') |
| assertIterationTime('none', [ |
| {is: null, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 1}, |
| ]); |
| |
| assertIterationTime('both', [ |
| {is: 0, at: -1}, |
| {is: 1, at: 0}, |
| {is: 1, at: 1}, |
| ]); |
| |
| assertIterationTime('forwards', [ |
| {is: null, at: -1}, |
| {is: 1, at: 0}, |
| {is: 1, at: 1}, |
| ]); |
| |
| assertIterationTime('backwards', [ |
| {is: 0, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 1}, |
| ]); |
| |
| |
| log('\nZero duration + reverse direction:') |
| assertIterationTime('none reverse', [ |
| {is: null, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 1}, |
| ]); |
| |
| assertIterationTime('both reverse', [ |
| {is: 1, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 1}, |
| ]); |
| |
| assertIterationTime('forwards reverse', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 1}, |
| ]); |
| |
| assertIterationTime('backwards reverse', [ |
| {is: 1, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 1}, |
| ]); |
| |
| |
| log('\nZero iterations:') |
| assertIterationTime('1s 0s 0 none', [ |
| {is: null, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 0.5}, |
| {is: null, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 0s 0 both', [ |
| {is: 0, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 0s 0 forwards', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 0s 0 backwards', [ |
| {is: 0, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 2}, |
| ]); |
| |
| |
| log('\nZero iterations, zero duration:') |
| assertIterationTime('0s 0s 0 none', [ |
| {is: null, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 2}, |
| ]); |
| |
| assertIterationTime('0s 0s 0 both', [ |
| {is: 0, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 1}, |
| ]); |
| |
| assertIterationTime('0s 0s 0 forwards', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0, at: 1}, |
| ]); |
| |
| assertIterationTime('0s 0s 0 backwards', [ |
| {is: 0, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 1}, |
| ]); |
| |
| |
| log('\nMultiple iterations:') |
| assertIterationTime('1s 2 linear', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0.4, at: 0.4}, |
| {is: 0, at: 1}, |
| {is: 0.6, at: 1.6}, |
| {is: null, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 2 linear reverse', [ |
| {is: 1, at: 0}, |
| {is: 0.6, at: 0.4}, |
| {is: 1, at: 1}, |
| {is: 0.4, at: 1.6}, |
| ]); |
| |
| assertIterationTime('1s 2 linear alternate', [ |
| {is: 0, at: 0}, |
| {is: 0.4, at: 0.4}, |
| {is: 1, at: 1}, |
| {is: 0.4, at: 1.6}, |
| ]); |
| |
| assertIterationTime('1s 2 linear alternate-reverse', [ |
| {is: 1, at: 0}, |
| {is: 0.6, at: 0.4}, |
| {is: 0, at: 1}, |
| {is: 0.6, at: 1.6}, |
| ]); |
| |
| |
| log('\nFractional iterations:') |
| assertIterationTime('1s 0.5 linear', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0.2, at: 0.2}, |
| {is: null, at: 0.5}, |
| ]); |
| |
| assertIterationTime('1s 1.5 linear', [ |
| {is: null, at: -1}, |
| {is: 0, at: 0}, |
| {is: 0.5, at: 0.5}, |
| {is: 0, at: 1}, |
| {is: 0.4, at: 1.4}, |
| {is: null, at: 1.5}, |
| ]); |
| |
| assertIterationTime('1s 1.5 linear reverse', [ |
| {is: null, at: -1}, |
| {is: 1, at: 0}, |
| {is: 0.5, at: 0.5}, |
| {is: 1, at: 1}, |
| {is: 0.6, at: 1.4}, |
| {is: null, at: 1.5}, |
| ]); |
| |
| assertIterationTime('1s 1.6 linear forwards', [ |
| {is: 0.6, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 1.6 linear forwards reverse ', [ |
| {is: 0.4, at: 2}, |
| ]); |
| |
| assertIterationTime('1s 0.6 linear backwards reverse', [ |
| {is: 1, at: -1}, |
| ]); |
| |
| |
| log('\nInfinite iterations:') |
| assertIterationTime('1s infinite linear', [ |
| {is: 0, at: 1}, |
| {is: 0, at: 10}, |
| {is: 0, at: 1000}, |
| {is: 0.4, at: 1000.4}, |
| ]); |
| |
| |
| log('\nInfinite iterations, zero duration:') |
| assertIterationTime('0s infinite linear', [ |
| {is: null, at: -1}, |
| {is: null, at: 0}, |
| {is: null, at: 2}, |
| ]); |
| |
| }; |
| |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| } |
| |
| var testElement = document.createElement('div'); |
| document.body.appendChild(testElement); |
| testElement.style.left = 'auto'; |
| |
| function update() { |
| document.body.offsetTop; |
| } |
| function log(message, klass) { |
| message += '\n'; |
| var child; |
| if (klass) { |
| child = document.createElement('span'); |
| child.classList.add(klass); |
| child.textContent = message; |
| } else { |
| child = document.createTextNode(message); |
| } |
| document.body.appendChild(child); |
| } |
| |
| var prefix = 'animation' in document.body.style ? '' : '-webkit-'; |
| function assertIterationTime(animation, expectations) { |
| testElement.style.setProperty(prefix + 'animation', 'invalid ' + animation); |
| update(); |
| |
| expectations.forEach(function(expectation) { |
| if (expectation.is !== null && expectation.is != Math.round(expectation.is * 100) / 100) { |
| console.log('ERROR: Test requires too much precision. ' + JSON.stringify(expectation)); |
| return; |
| } |
| testElement.style.setProperty(prefix + 'animation-name', 'invalid'); |
| update(); |
| |
| var delay = expectation.at * -1; |
| testElement.style.setProperty(prefix + 'animation-delay', delay + 's'); |
| testElement.style.setProperty(prefix + 'animation-name', 'test'); |
| update(); |
| // FIXME: Set play-state: paused before starting the animation. |
| // For now, updating the style another two times makes this work in WebKit/Blink |
| testElement.style.setProperty(prefix + 'animation-name', 'test'); |
| update(); |
| testElement.style.setProperty(prefix + 'animation-name', 'test'); |
| update(); |
| |
| var result = getComputedStyle(testElement).left; |
| if (result === 'auto') { |
| result = null; |
| } else { |
| result = Math.round(Number(result.replace(/px$/, '')) * 100) / 100; |
| } |
| if (result === expectation.is) { |
| log('PASS: [' + animation + '] iteration time was [' + expectation.is + '] at ' + expectation.at + 's'); |
| } else { |
| log('FAIL: [' + animation + '] iteration time was [' + result + '] at ' + expectation.at + 's' + ' expected [' + expectation.is + ']', 'fail'); |
| } |
| }); |
| } |
| </script> |
| <style> |
| body { |
| white-space: pre; |
| font-family: monospace; |
| } |
| .fail { |
| font-weight: bold; |
| color: red; |
| } |
| @-webkit-keyframes test { |
| 0% { |
| left: 0px; |
| } |
| 100% { |
| left: 1px; |
| } |
| } |
| @keyframes test { |
| 0% { |
| left: 0px; |
| } |
| 100% { |
| left: 1px; |
| } |
| } |
| </style> |