blob: 351cea3e65aac50c66b0dd7a70c397187862fede [file] [log] [blame]
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<style>
.anim {
position: absolute;
left: 10px;
height: 90px;
width: 100px;
background-color: black;
}
</style>
<body>
</body>
<script>
var addAnimDiv = function() {
var element = document.createElement('div');
element.className = 'anim';
document.body.appendChild(element);
return element;
};
var assertEquivalentFramesSyntax = function(testParams) {
var e1 = addAnimDiv();
var e2 = addAnimDiv();
var e1Style = getComputedStyle(e1);
var e2Style = getComputedStyle(e2);
var options = {duration: testParams.duration, fill: "forwards"};
var player1 = e1.animate(testParams.listOfKeyframes, options);
var player2 = e2.animate(testParams.keyframeWithListOfValues, options);
player1.pause();
player2.pause();
for (var i = 0; i < testParams.expectationList.length; i++) {
var expected = testParams.expectationList[i];
player1.currentTime = expected.at;
player2.currentTime = expected.at;
for (var property in expected.is) {
assert_equals(e1Style.getPropertyValue(property), expected.is[property]);
assert_equals(e2Style.getPropertyValue(property), expected.is[property]);
}
}
};
test(function() {
var element = addAnimDiv();
var elementStyle = getComputedStyle(element);
var player = element.animate([
{left: '10px', opacity: '1', offset: 0},
{left: '100px', opacity: '0', offset: 1}
], 1);
player.pause();
player.currentTime = 0.5;
assert_equals(elementStyle.left, '55px');
assert_equals(elementStyle.opacity, '0.5');
}, 'Calling animate() should start an animation.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '10px', opacity: '1'},
{left: '100px', opacity: '0'},
{left: '150px', opacity: '1'}
],
keyframeWithListOfValues: {
left: ['10px', '100px', '150px'],
opacity: ['1', '0', '1']
},
duration: 1,
expectationList: [
{at: 0, is: {left: '10px', opacity: '1'}},
{at: 0.25, is: {left: '55px', opacity: '0.5'}},
{at: 0.5, is: {left: '100px', opacity: '0'}},
{at: 0.75, is: {left: '125px', opacity: '0.5'}},
{at: 1, is: {left: '150px', opacity: '1'}}
]
});
}, 'Calling animate() with alternative list syntax should give same result.');
test(function() {
var element = addAnimDiv();
var elementStyle = getComputedStyle(element);
var player = element.animate([
{backgroundColor: 'green', offset: 0},
{backgroundColor: 'purple', offset: 1}
], 1);
player.pause();
player.currentTime = 0.5;
assert_equals(elementStyle.backgroundColor, 'rgb(64, 64, 64)');
}, 'Calling animate() should start an animation. CamelCase property names should be parsed.');
test(function() {
var element = addAnimDiv();
var elementStyle = getComputedStyle(element);
var player = element.animate([
{left: '10px', offset: '0'},
{left: '100px', offset: '1'}
], 1);
player.pause();
player.currentTime = 0.5;
assert_equals(elementStyle.left, '55px');
}, 'Offsets may be specified as strings.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '0px', easing: 'steps(2, start)'},
{left: '100px', easing: 'steps(2, start)'},
{left: '300px'}
],
keyframeWithListOfValues: {
left: ['0px', '100px', '300px'],
easing: 'steps(2, start)'
},
duration: 1,
expectationList: [
{at: 0, is: {left: '50px'}},
{at: 0.25, is: {left: '100px'}},
{at: 0.5, is: {left: '200px'}},
{at: 0.75, is: {left: '300px'}}
]
});
}, 'When using the alternative list syntax, all keyframes have the same timing function.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '0px', offset: 0.5},
{left: '100px', offset: 0.5}
],
keyframeWithListOfValues: {
left: ['0px', '100px'],
offset: 0.5
},
duration: 1,
expectationList: [
{at: 0, is: {left: '10px'}},
{at: 0.25, is: {left: '5px'}},
{at: 0.49, is: {left: '0.2px'}},
{at: 0.5, is: {left: '100px'}},
{at: 0.75, is: {left: '55px'}},
{at: 1, is: {left: '10px'}}
]
});
}, 'When using the alternative list syntax, offset is applied to all specified keyframes.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '0px', composite: 'add'},
{left: '100px', composite: 'add'}
],
keyframeWithListOfValues: {
left: ['0px', '100px'],
composite: 'add'
},
duration: 1,
expectationList: [
{at: 0, is: {left: '10px'}},
{at: 0.5, is: {left: '60px'}},
{at: 1, is: {left: '110px'}}
]
});
}, 'When using the alternative list syntax, composite is applied to all keyframes.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '0px', offset: 0},
{opacity: '0', offset: 0},
{left: '10px', offset: 0.33},
{opacity: '0.4', offset: 0.5},
{left: '40px', offset: 0.67},
{left: '100px', offset: 1},
{opacity: '1', offset: 1}
],
keyframeWithListOfValues: {
left: ['0px', '10px', '40px', '100px'],
opacity: ['0', '0.4', '1']
},
duration: 1,
expectationList: [
{at: 0, is: {left: '0px', opacity: '0'}},
{at: 0.5, is: {left: '25px', opacity: '0.4'}},
{at: 1, is: {left: '100px', opacity: '1'}}
]
});
}, 'When using the alternative list syntax, properties can have different length lists.');
test(function() {
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '100px'}
],
keyframeWithListOfValues: {
left: ['100px']
},
duration: 1,
expectationList: [
{at: 0, is: {left: '10px'}},
{at: 0.5, is: {left: '55px'}},
{at: 1, is: {left: '100px'}}
]
});
assertEquivalentFramesSyntax({
listOfKeyframes: [
{left: '100px'}
],
keyframeWithListOfValues: {
left: '100px'
},
duration: 1,
expectationList: [
{at: 0, is: {left: '10px'}},
{at: 0.5, is: {left: '55px'}},
{at: 1, is: {left: '100px'}}
]
});
}, 'The list of keyframes can have one element.');
test(function() {
var element = addAnimDiv();
var keyframes = [
{left: ['10px', '100px']},
{left: ['5px', '50px']}
];
assert_throws({name: 'TypeError'}, function() { element.animate(keyframes, 1); });
}, 'Should throw when mixing two different list syntaxes.');
test(function() {
var element = addAnimDiv();
var keyframes = [
{opacity: '0.5', offset: 0.5},
{opacity: '0.9', offset: 1},
{opacity: '0', offset: 0}
];
assert_throws({name: 'TypeError'}, function() { element.animate(keyframes, 1); });
}, 'Should throw when keyframes have unsorted offsets.');
test(function() {
var element = addAnimDiv();
var keyframes = [
{opacity: '1', offset: -1},
{opacity: '1', offset: NaN},
{opacity: '1', offset: 2},
{opacity: '0.5', offset: 1},
{opacity: '0', offset: 0}
];
assert_throws({name: 'TypeError'}, function() { element.animate(keyframes, 1); });
}, 'Should throw when keyframes has offsets outside the range [0.0, 1.0].');
test(function() {
var element = addAnimDiv();
var keyframes = [
{opacity: '0.5'},
{opacity: '1', offset: 1},
{opacity: '0', offset: 0}
];
assert_throws({name: 'TypeError'}, function() { element.animate(keyframes, 1); });
}, 'Should throw when keyframes are not loosely sorted and any have no offset.');
test(function() {
var element = addAnimDiv();
var keyframes = [
{opacity: '0.5', offset: null},
{opacity: '1', offset: 1},
{opacity: '0', offset: 0}
];
assert_throws({name: 'TypeError'}, function() { element.animate(keyframes, 1); });
}, 'Should throw when keyframes are not loosely sorted and any have null offset.');
var keyframesWithInvalid = [
{width: '0px', backgroundColor: 'octarine', offset: 0},
{width: '1000px', foo: 'bar', offset: 1}];
test(function() {
var element = addAnimDiv();
var elementStyle = getComputedStyle(element);
var player = element.animate(keyframesWithInvalid, {duration: 1, fill: 'forwards'});
player.pause();
player.currentTime = 1;
assert_equals(elementStyle.width, '1000px');
assert_equals(elementStyle.backgroundColor, 'rgb(0, 0, 0)');
assert_equals(elementStyle.foo, undefined);
}, 'Calling animate() with a pre-constructed keyframes list should start an animation. Invalid style declarations should be ignored.');
</script>