mirror of
https://github.com/servo/servo.git
synced 2025-06-24 00:54:32 +01:00
330 lines
11 KiB
HTML
330 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset=utf-8>
|
|
<title>KeyframeEffectReadOnly constructor tests</title>
|
|
<link rel="help" href="https://w3c.github.io/web-animations/#processing-a-keyframes-argument">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="../../testcommon.js"></script>
|
|
<script src="../../resources/keyframe-utils.js"></script>
|
|
<body>
|
|
<div id="log"></div>
|
|
<div id="target"></div>
|
|
<script>
|
|
'use strict';
|
|
|
|
// Test the "process a keyframe-like object" procedure.
|
|
//
|
|
// This file only tests the KeyframeEffectReadOnly constructor since it is
|
|
// assumed that the implementation of the KeyframeEffect constructor,
|
|
// Animatable.animate() method, and KeyframeEffect.setKeyframes() method will
|
|
// all share common machinery and it is not necessary to test each method.
|
|
|
|
// Test that only animatable properties are accessed
|
|
|
|
var gNonAnimatableProps = [
|
|
'animation', // Shorthands where all the longhand sub-properties are not
|
|
// animatable, are also not animatable.
|
|
'animationDelay',
|
|
'animationDirection',
|
|
'animationDuration',
|
|
'animationFillMode',
|
|
'animationIterationCount',
|
|
'animationName',
|
|
'animationPlayState',
|
|
'animationTimingFunction',
|
|
'transition',
|
|
'transitionDelay',
|
|
'transitionDuration',
|
|
'transitionProperty',
|
|
'transitionTimingFunction',
|
|
'display',
|
|
'unsupportedProperty',
|
|
'font-size', // Supported property that uses dashes
|
|
];
|
|
|
|
function TestKeyframe(testProp) {
|
|
var _propAccessCount = 0;
|
|
|
|
Object.defineProperty(this, testProp, {
|
|
get: function() { _propAccessCount++; },
|
|
enumerable: true
|
|
});
|
|
|
|
Object.defineProperty(this, 'propAccessCount', {
|
|
get: function() { return _propAccessCount; }
|
|
});
|
|
}
|
|
|
|
function GetTestKeyframeSequence(testProp) {
|
|
return [ new TestKeyframe(testProp) ]
|
|
}
|
|
|
|
gNonAnimatableProps.forEach(function(prop) {
|
|
test(function(t) {
|
|
var testKeyframe = new TestKeyframe(prop);
|
|
|
|
new KeyframeEffectReadOnly(null, testKeyframe);
|
|
|
|
assert_equals(testKeyframe.propAccessCount, 0, 'Accessor not called');
|
|
}, 'non-animatable property \'' + prop + '\' is not accessed when using'
|
|
+ ' a property-indexed keyframe object');
|
|
});
|
|
|
|
gNonAnimatableProps.forEach(function(prop) {
|
|
test(function(t) {
|
|
var testKeyframes = GetTestKeyframeSequence(prop);
|
|
|
|
new KeyframeEffectReadOnly(null, testKeyframes);
|
|
|
|
assert_equals(testKeyframes[0].propAccessCount, 0, 'Accessor not called');
|
|
}, 'non-animatable property \'' + prop + '\' is not accessed when using'
|
|
+ ' a keyframe sequence');
|
|
});
|
|
|
|
// Test equivalent forms of property indexed and sequenced keyframe syntax
|
|
|
|
function assertEquivalentKeyframeSyntax(keyframesA, keyframesB) {
|
|
var processedKeyframesA = new KeyframeEffectReadOnly(null, keyframesA).getKeyframes();
|
|
var processedKeyframesB = new KeyframeEffectReadOnly(null, keyframesB).getKeyframes();
|
|
assert_frame_lists_equal(processedKeyframesA, processedKeyframesB);
|
|
}
|
|
|
|
var gEquivalentSyntaxTests = [
|
|
{
|
|
description: 'two properties with one value',
|
|
indexedKeyframes: {
|
|
left: '100px',
|
|
opacity: ['1'],
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '100px', opacity: '1'},
|
|
],
|
|
},
|
|
{
|
|
description: 'two properties with three values',
|
|
indexedKeyframes: {
|
|
left: ['10px', '100px', '150px'],
|
|
opacity: ['1', '0', '1'],
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '10px', opacity: '1'},
|
|
{left: '100px', opacity: '0'},
|
|
{left: '150px', opacity: '1'},
|
|
],
|
|
},
|
|
{
|
|
description: 'two properties with different numbers of values',
|
|
indexedKeyframes: {
|
|
left: ['0px', '100px', '200px'],
|
|
opacity: ['0', '1']
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '0px', opacity: '0'},
|
|
{left: '100px'},
|
|
{left: '200px', opacity: '1'},
|
|
],
|
|
},
|
|
{
|
|
description: 'same offset applied to all keyframes',
|
|
indexedKeyframes: {
|
|
left: ['0px', '100px'],
|
|
offset: 0.5,
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '0px', offset: 0.5},
|
|
{left: '100px', offset: 0.5},
|
|
],
|
|
},
|
|
{
|
|
description: 'same easing applied to all keyframes',
|
|
indexedKeyframes: {
|
|
left: ['10px', '100px', '150px'],
|
|
opacity: ['1', '0', '1'],
|
|
easing: 'ease',
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '10px', opacity: '1', easing: 'ease'},
|
|
{left: '100px', opacity: '0', easing: 'ease'},
|
|
{left: '150px', opacity: '1', easing: 'ease'},
|
|
],
|
|
},
|
|
{
|
|
description: 'same composite applied to all keyframes',
|
|
indexedKeyframes: {
|
|
left: ['0px', '100px'],
|
|
composite: 'add',
|
|
},
|
|
sequencedKeyframes: [
|
|
{left: '0px', composite: 'add'},
|
|
{left: '100px', composite: 'add'},
|
|
],
|
|
},
|
|
];
|
|
|
|
gEquivalentSyntaxTests.forEach(function({description, indexedKeyframes, sequencedKeyframes}) {
|
|
test(function(t) {
|
|
assertEquivalentKeyframeSyntax(indexedKeyframes, sequencedKeyframes);
|
|
}, 'Equivalent property indexed and sequenced keyframes: ' + description);
|
|
});
|
|
|
|
// Test handling of custom iterable objects.
|
|
|
|
function createIterable(iterations) {
|
|
return {
|
|
[Symbol.iterator]() {
|
|
var i = 0;
|
|
return {
|
|
next() {
|
|
return iterations[i++];
|
|
},
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
test(() => {
|
|
var effect = new KeyframeEffect(null, createIterable([
|
|
{done: false, value: {left: '100px'}},
|
|
{done: false, value: {left: '300px'}},
|
|
{done: false, value: {left: '200px'}},
|
|
{done: true},
|
|
]));
|
|
assert_frame_lists_equal(effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
|
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
|
]);
|
|
}, 'Custom iterator with basic keyframes.');
|
|
|
|
test(() => {
|
|
var keyframes = createIterable([
|
|
{done: false, value: {left: '100px'}},
|
|
{done: false, value: {left: '300px'}},
|
|
{done: false, value: {left: '200px'}},
|
|
{done: true},
|
|
]);
|
|
keyframes.easing = 'ease-in-out';
|
|
keyframes.offset = '0.1';
|
|
var effect = new KeyframeEffect(null, keyframes);
|
|
assert_frame_lists_equal(effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
|
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
|
]);
|
|
}, 'easing and offset are ignored on iterable objects.');
|
|
|
|
test(() => {
|
|
var effect = new KeyframeEffect(null, createIterable([
|
|
{done: false, value: {left: '100px', top: '200px'}},
|
|
{done: false, value: {left: '300px'}},
|
|
{done: false, value: {left: '200px', top: '100px'}},
|
|
{done: true},
|
|
]));
|
|
assert_frame_lists_equal(effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', left: '100px', top: '200px'},
|
|
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', left: '200px', top: '100px'},
|
|
]);
|
|
}, 'Custom iterator with multiple properties specified.');
|
|
|
|
test(() => {
|
|
var effect = new KeyframeEffect(null, createIterable([
|
|
{done: false, value: {left: '100px'}},
|
|
{done: false, value: {left: '250px', offset: 0.75}},
|
|
{done: false, value: {left: '200px'}},
|
|
{done: true},
|
|
]));
|
|
assert_frame_lists_equal(effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
|
{offset: 0.75, computedOffset: 0.75, easing: 'linear', left: '250px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
|
]);
|
|
}, 'Custom iterator with offset specified.');
|
|
|
|
test(() => {
|
|
assert_throws({name: 'TypeError'}, function() {
|
|
new KeyframeEffect(null, createIterable([
|
|
{done: false, value: {left: '100px'}},
|
|
{done: false, value: 1234},
|
|
{done: false, value: {left: '200px'}},
|
|
{done: true},
|
|
]));
|
|
});
|
|
}, 'Custom iterator with non object keyframe should throw.');
|
|
|
|
test(() => {
|
|
var effect = new KeyframeEffect(null, createIterable([
|
|
{done: false, value: {left: ['100px', '200px']}},
|
|
{done: true},
|
|
]));
|
|
assert_frame_lists_equal(effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 1, easing: 'linear', left: '100px,200px'}
|
|
]);
|
|
}, 'Custom iterator with value list in keyframe should give bizarre string representation of list.');
|
|
|
|
test(function(t) {
|
|
var keyframe = {};
|
|
Object.defineProperty(keyframe, 'width', {value: '200px'});
|
|
Object.defineProperty(keyframe, 'height', {
|
|
value: '100px',
|
|
enumerable: true});
|
|
assert_equals(keyframe.width, '200px', 'width of keyframe is readable');
|
|
assert_equals(keyframe.height, '100px', 'height of keyframe is readable');
|
|
var anim = createDiv(t).animate([keyframe, {height: '200px'}], 1);
|
|
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', height: '100px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', height: '200px'},
|
|
]);
|
|
}, 'Only enumerable properties on keyframes are considered');
|
|
|
|
test(function(t) {
|
|
var KeyframeParent = function() { this.width = '100px'; };
|
|
KeyframeParent.prototype = { height: '100px' };
|
|
var Keyframe = function() { this.top = '100px'; };
|
|
Keyframe.prototype = Object.create(KeyframeParent.prototype);
|
|
Object.defineProperty(Keyframe.prototype, 'left', {
|
|
value: '100px',
|
|
enumerable: 'true'});
|
|
var keyframe = new Keyframe();
|
|
var anim = createDiv(t).animate([keyframe, {top: '200px'}], 1);
|
|
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', top: '100px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', top: '200px'},
|
|
]);
|
|
}, 'Only properties defined directly on keyframes are considered');
|
|
|
|
test(function(t) {
|
|
var keyframes = {};
|
|
Object.defineProperty(keyframes, 'width', ['100px', '200px']);
|
|
Object.defineProperty(keyframes, 'height', {
|
|
value: ['100px', '200px'],
|
|
enumerable: true});
|
|
var anim = createDiv(t).animate(keyframes, 1);
|
|
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', height: '100px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', height: '200px'},
|
|
]);
|
|
}, 'Only enumerable properties on property indexed keyframes are considered');
|
|
|
|
test(function(t) {
|
|
var KeyframesParent = function() { this.width = '100px'; };
|
|
KeyframesParent.prototype = { height: '100px' };
|
|
var Keyframes = function() { this.top = ['100px', '200px']; };
|
|
Keyframes.prototype = Object.create(KeyframesParent.prototype);
|
|
Object.defineProperty(Keyframes.prototype, 'left', {
|
|
value: ['100px', '200px'],
|
|
enumerable: 'true'});
|
|
var keyframes = new Keyframes();
|
|
var anim = createDiv(t).animate(keyframes, 1);
|
|
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
|
{offset: null, computedOffset: 0, easing: 'linear', top: '100px'},
|
|
{offset: null, computedOffset: 1, easing: 'linear', top: '200px'},
|
|
]);
|
|
}, 'Only properties defined directly on property indexed keyframes are considered');
|
|
|
|
// FIXME: Test that properties are accessed in ascending order by Unicode
|
|
// codepoint
|
|
// (There is an existing test for this in
|
|
// keyframe-effect/constructor.html that should be moved here.)
|
|
|
|
</script>
|