Update web-platform-tests to revision bda2059150dca8ab47f088b4cc619fcdc1f262fa

This commit is contained in:
Ms2ger 2016-05-30 09:58:25 +02:00
parent 3535f3f6c2
commit 7c4281f3da
182 changed files with 7692 additions and 1042 deletions

View file

@ -0,0 +1,278 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffectReadOnly constructor tests</title>
<link rel="help" href="https://w3c.github.io/web-animations/#the-keyframeeffect-interfaces">
<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>
<style>
#target {
border-style: solid; /* so border-*-width values don't compute to 0 */
}
</style>
<script>
"use strict";
var target = document.getElementById("target");
test(function(t) {
gEmptyKeyframeListTests.forEach(function(frames) {
assert_equals(new KeyframeEffectReadOnly(target, frames)
.getKeyframes().length,
0, "number of frames for " + JSON.stringify(frames));
});
}, "a KeyframeEffectReadOnly can be constructed with no frames");
test(function(t) {
gEasingValueTests.forEach(function(subtest) {
var easing = subtest[0];
var expected = subtest[1];
var effect = new KeyframeEffectReadOnly(target, {
left: ["10px", "20px"],
easing: easing
});
assert_equals(effect.getKeyframes()[0].easing, expected,
"resulting easing for '" + easing + "'");
});
}, "easing values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in a property-indexed keyframe");
test(function(t) {
gEasingValueTests.forEach(function(subtest) {
var easing = subtest[0];
var expected = subtest[1];
var effect = new KeyframeEffectReadOnly(target, [
{ offset: 0, left: "10px", easing: easing },
{ offset: 1, left: "20px" }
]);
assert_equals(effect.getKeyframes()[0].easing, expected,
"resulting easing for '" + easing + "'");
});
}, "easing values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in regular keyframes");
test(function(t) {
gEasingValueTests.forEach(function(subtest) {
var easing = subtest[0];
var expected = subtest[1];
var effect = new KeyframeEffectReadOnly(target, {
left: ["10px", "20px"]
}, { easing: easing });
assert_equals(effect.timing.easing, expected,
"resulting easing for '" + easing + "'");
});
}, "easing values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
test(function(t) {
var getKeyframe = function(composite) {
return { left: [ "10px", "20px" ], composite: composite };
};
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
var effect = new KeyframeEffectReadOnly(target, getKeyframe(composite));
assert_equals(effect.getKeyframes()[0].composite, composite,
"resulting composite for '" + composite + "'");
});
gBadCompositeValueTests.forEach(function(composite) {
assert_throws(new TypeError, function() {
new KeyframeEffectReadOnly(target, getKeyframe(composite));
});
});
}, "composite values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in property-indexed keyframes");
test(function(t) {
var getKeyframes = function(composite) {
return [
{ offset: 0, left: "10px", composite: composite },
{ offset: 1, left: "20px" }
];
};
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
var effect = new KeyframeEffectReadOnly(target, getKeyframes(composite));
assert_equals(effect.getKeyframes()[0].composite, composite,
"resulting composite for '" + composite + "'");
});
gBadCompositeValueTests.forEach(function(composite) {
assert_throws(new TypeError, function() {
new KeyframeEffectReadOnly(target, getKeyframes(composite));
});
});
}, "composite values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in regular keyframes");
test(function(t) {
gGoodOptionsCompositeValueTests.forEach(function(composite) {
var effect = new KeyframeEffectReadOnly(target, {
left: ["10px", "20px"]
}, { composite: composite });
assert_equals(effect.getKeyframes()[0].composite, composite,
"resulting composite for '" + composite + "'");
});
gBadCompositeValueTests.forEach(function(composite) {
assert_throws(new TypeError, function() {
new KeyframeEffectReadOnly(target, {
left: ["10px", "20px"]
}, { composite: composite });
});
});
}, "composite values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target, subtest.input);
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
}, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
test(function(t) {
var effect = new KeyframeEffectReadOnly(target, subtest.input);
var secondEffect =
new KeyframeEffectReadOnly(target, effect.getKeyframes());
assert_frame_lists_equal(secondEffect.getKeyframes(),
effect.getKeyframes());
}, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
" roundtrips");
});
test(function(t) {
var expectedOrder = ["composite", "easing", "offset", "left", "marginLeft"];
var actualOrder = [];
var kf1 = {};
var kf2 = { marginLeft: "10px", left: "20px", offset: 1 };
[{ p: "marginLeft", v: "10px" },
{ p: "left", v: "20px" },
{ p: "offset", v: "0" },
{ p: "easing", v: "linear" },
{ p: "composite", v: "replace" }].forEach(function(e) {
Object.defineProperty(kf1, e.p, {
enumerable: true,
get: function() { actualOrder.push(e.p); return e.v; }
});
});
new KeyframeEffectReadOnly(target, [kf1, kf2]);
assert_array_equals(actualOrder, expectedOrder, "property access order");
}, "the KeyframeEffectReadOnly constructor reads keyframe properties in the " +
"expected order");
gKeyframeSequenceTests.forEach(function(subtest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target, subtest.input);
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
}, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
test(function(t) {
var effect = new KeyframeEffectReadOnly(target, subtest.input);
var secondEffect =
new KeyframeEffectReadOnly(target, effect.getKeyframes());
assert_frame_lists_equal(secondEffect.getKeyframes(),
effect.getKeyframes());
}, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
" roundtrips");
});
gInvalidKeyframesTests.forEach(function(subtest) {
test(function(t) {
assert_throws(subtest.expected, function() {
new KeyframeEffectReadOnly(target, subtest.input);
});
}, "KeyframeEffectReadOnly constructor throws with " + subtest.desc);
});
gInvalidEasingInKeyframeSequenceTests.forEach(function(subtest) {
test(function(t) {
assert_throws(new TypeError, function() {
new KeyframeEffectReadOnly(target, subtest.input);
});
}, "Invalid easing [" + subtest.desc + "] in keyframe sequence " +
"should be thrown");
});
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] });
var timing = effect.timing;
assert_equals(timing.delay, 0, "default delay");
assert_equals(timing.endDelay, 0, "default endDelay");
assert_equals(timing.fill, "auto", "default fill");
assert_equals(timing.iterations, 1.0, "default iterations");
assert_equals(timing.iterationStart, 0.0, "default iterationStart");
assert_equals(timing.duration, "auto", "default duration");
assert_equals(timing.direction, "normal", "default direction");
assert_equals(timing.easing, "linear", "default easing");
assert_equals(effect.composite, "replace", "default composite");
assert_equals(effect.iterationComposite, "replace",
"default iterationComposite");
assert_equals(effect.spacing, "distribute",
"default spacing");
}, "a KeyframeEffectReadOnly constructed without any " +
"KeyframeEffectOptions object");
gKeyframeEffectOptionTests.forEach(function(stest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] },
stest.input);
// Helper function to provide default expected values when the test does
// not supply them.
var expected = function(field, defaultValue) {
return field in stest.expected ? stest.expected[field] : defaultValue;
};
var timing = effect.timing;
assert_equals(timing.delay, expected("delay", 0),
"timing delay");
assert_equals(timing.fill, expected("fill", "auto"),
"timing fill");
assert_equals(timing.iterations, expected("iterations", 1),
"timing iterations");
assert_equals(timing.duration, expected("duration", "auto"),
"timing duration");
assert_equals(timing.direction, expected("direction", "normal"),
"timing direction");
}, "a KeyframeEffectReadOnly constructed by " + stest.desc);
});
gInvalidKeyframeEffectOptionTests.forEach(function(stest) {
test(function(t) {
assert_throws(stest.expected, function() {
new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] },
stest.input);
});
}, "Invalid KeyframeEffectReadOnly option by " + stest.desc);
});
test(function(t) {
var effect = new KeyframeEffectReadOnly(null,
{ left: ["10px", "20px"] },
{ duration: 100 * MS_PER_SEC,
fill: "forwards" });
assert_equals(effect.target, null,
"Effect created with null target has correct target");
}, "a KeyframeEffectReadOnly constructed with null target");
test(function(t) {
var effect = new KeyframeEffect(target, null);
assert_class_string(effect, "KeyframeEffect");
assert_class_string(effect.timing, "AnimationEffectTiming");
}, "KeyframeEffect constructor creates an AnimationEffectTiming timing object");
test(function(t) {
var test_error = { name: "test" };
assert_throws(test_error, function() {
new KeyframeEffect(target, { get left() { throw test_error }})
});
}, "KeyframeEffect constructor propagates exceptions generated by accessing"
+ " the options object");
</script>
</body>

View file

@ -0,0 +1,673 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Effect-level easing tests</title>
<link rel="help" href="http://w3c.github.io/web-animations/#calculating-the-transformed-time">
<link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<script src="../../resources/effect-easing-tests.js"></script>
<body>
<div id="log"></div>
<div id="target"></div>
<script>
"use strict";
function assert_style_left_at(animation, time, easingFunction) {
animation.currentTime = time;
var portion = time / animation.effect.timing.duration;
assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
easingFunction(portion) * 100,
0.01,
'The left of the animation should be approximately ' +
easingFunction(portion) * 100 + ' at ' + time + 'ms');
}
gEffectEasingTests.forEach(function(options) {
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px' }, { left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: options.easing });
var easing = options.easingFunction;
anim.pause();
assert_style_left_at(anim, 0, easing);
assert_style_left_at(anim, 250, easing);
assert_style_left_at(anim, 500, easing);
assert_style_left_at(anim, 750, easing);
assert_style_left_at(anim, 1000, easing);
}, options.desc);
});
var gEffectEasingTestsWithKeyframeEasing = [
{
desc: 'effect easing produces values greater than 1 with keyframe ' +
'easing cubic-bezier(0, 0, 0, 0)',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
easingFunction: cubicBezier(0, 1.5, 1, 1.5)
},
{
desc: 'effect easing produces values greater than 1 with keyframe ' +
'easing cubic-bezier(1, 1, 1, 1)',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
easingFunction: cubicBezier(0, 1.5, 1, 1.5)
},
{
desc: 'effect easing produces negative values 1 with keyframe ' +
'easing cubic-bezier(0, 0, 0, 0)',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
easingFunction: cubicBezier(0, -0.5, 1, -0.5)
},
{
desc: 'effect easing produces negative values 1 with keyframe ' +
'easing cubic-bezier(1, 1, 1, 1)',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
easingFunction: cubicBezier(0, -0.5, 1, -0.5)
},
];
gEffectEasingTestsWithKeyframeEasing.forEach(function(options) {
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate(
[ { left: '0px', easing: options.keyframeEasing },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: options.easing });
var easing = options.easingFunction;
anim.pause();
assert_style_left_at(anim, 0, easing);
assert_style_left_at(anim, 250, easing);
assert_style_left_at(anim, 500, easing);
assert_style_left_at(anim, 750, easing);
assert_style_left_at(anim, 1000, easing);
}, options.desc);
});
// Other test cases that effect easing produces values outside of [0,1].
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
anim.pause();
// The bezier function produces values greater than 1 in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'effect easing produces values greater than 1 with step-start keyframe');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
anim.pause();
// The bezier function produces values greater than 1 in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'effect easing produces values greater than 1 with step-end keyframe');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
anim.pause();
// The bezier function produces negative values in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'effect easing produces negative values with step-start keyframe');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
anim.pause();
// The bezier function produces negative values in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'effect easing produces negative values with step-end keyframe');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate(
// http://cubic-bezier.com/#.5,1,.5,0
[ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
var keyframeEasing = function(x) {
assert_greater_than_equal(x, 0.0,
'This function should be called in [0, 1.0] range');
assert_less_than_equal(x, 1.0,
'This function should be called in [0, 1.0] range');
return cubicBezier(0.5, 1, 0.5, 0)(x);
}
var keyframeEasingExtrapolated = function(x) {
assert_greater_than(x, 1.0,
'This function should be called in (1.0, infinity) range');
// p3x + (p2y - p3y) / (p2x - p3x) * (x - p3x)
return 1.0 + (0 - 1) / (0.5 - 1) * (x - 1.0);
}
var effectEasing = function(x) {
return cubicBezier(0, 1.5, 1, 1.5)(x);
}
anim.pause();
// The effect-easing produces values greater than 1 in (0.23368794, 1)
assert_style_left_at(anim, 0, function(x) {
return keyframeEasing(effectEasing(x));
});
assert_style_left_at(anim, 230, function(x) {
return keyframeEasing(effectEasing(x));
});
assert_style_left_at(anim, 240, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
// Near the extreme point of the effect-easing function
assert_style_left_at(anim, 700, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
assert_style_left_at(anim, 990, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
assert_style_left_at(anim, 1000, function(x) {
return keyframeEasing(effectEasing(x));
});
}, 'effect easing produces values greater than 1 with keyframe easing ' +
'producing values greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate(
// http://cubic-bezier.com/#0,1.5,1,1.5
[ { left: '0px', easing: 'cubic-bezier(0, 1.5, 1, 1.5)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
var easing = function(x) {
assert_greater_than_equal(x, 0.0,
'This function should be called in [0, 1.0] range');
assert_less_than_equal(x, 1.0,
'This function should be called in [0, 1.0] range');
return cubicBezier(0, 1.5, 1, 1.5)(x);
}
var easingExtrapolated = function(x) {
assert_greater_than(x, 1.0,
'This function should be called in negative range');
// For cubic-bezier(0, 1.5, 1, 1.5), the tangent at the
// endpoint (x = 1.0) is infinity so we should just return 1.0.
return 1.0;
}
anim.pause();
// The effect-easing produces values greater than 1 in (0.23368794, 1)
assert_style_left_at(anim, 0, function(x) {
return easing(easing(x))
});
assert_style_left_at(anim, 230, function(x) {
return easing(easing(x))
});
assert_style_left_at(anim, 240, function(x) {
return easingExtrapolated(easing(x));
});
// Near the extreme point of the effect-easing function
assert_style_left_at(anim, 700, function(x) {
return easingExtrapolated(easing(x));
});
assert_style_left_at(anim, 990, function(x) {
return easingExtrapolated(easing(x));
});
assert_style_left_at(anim, 1000, function(x) {
return easing(easing(x))
});
}, 'effect easing which produces values greater than 1 and the tangent on ' +
'the upper boundary is infinity with keyframe easing producing values ' +
'greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate(
// http://cubic-bezier.com/#.5,1,.5,0
[ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
var keyframeEasing = function(x) {
assert_greater_than_equal(x, 0.0,
'This function should be called in [0, 1.0] range');
assert_less_than_equal(x, 1.0,
'This function should be called in [0, 1.0] range');
return cubicBezier(0.5, 1, 0.5, 0)(x);
}
var keyframeEasingExtrapolated = function(x) {
assert_less_than(x, 0.0,
'This function should be called in negative range');
// p0x + (p1y - p0y) / (p1x - p0x) * (x - p0x)
return (1 / 0.5) * x;
}
var effectEasing = function(x) {
return cubicBezier(0, -0.5, 1, -0.5)(x);
}
anim.pause();
// The effect-easing produces negative values in (0, 0.766312060)
assert_style_left_at(anim, 0, function(x) {
return keyframeEasing(effectEasing(x));
});
assert_style_left_at(anim, 10, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
// Near the extreme point of the effect-easing function
assert_style_left_at(anim, 300, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
assert_style_left_at(anim, 750, function(x) {
return keyframeEasingExtrapolated(effectEasing(x));
});
assert_style_left_at(anim, 770, function(x) {
return keyframeEasing(effectEasing(x));
});
assert_style_left_at(anim, 1000, function(x) {
return keyframeEasing(effectEasing(x));
});
}, 'effect easing produces negative values with keyframe easing ' +
'producing negative values');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate(
// http://cubic-bezier.com/#0,-0.5,1,-0.5
[ { left: '0px', easing: 'cubic-bezier(0, -0.5, 1, -0.5)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
var easing = function(x) {
assert_greater_than_equal(x, 0.0,
'This function should be called in [0, 1.0] range');
assert_less_than_equal(x, 1.0,
'This function should be called in [0, 1.0] range');
return cubicBezier(0, -0.5, 1, -0.5)(x);
}
var easingExtrapolated = function(x) {
assert_less_than(x, 0.0,
'This function should be called in negative range');
// For cubic-bezier(0, -0.5, 1, -0.5), the tangent at the
// endpoint (x = 0.0) is infinity so we should just return 0.0.
return 0.0;
}
anim.pause();
// The effect-easing produces negative values in (0, 0.766312060)
assert_style_left_at(anim, 0, function(x) {
return easing(easing(x))
});
assert_style_left_at(anim, 10, function(x) {
return easingExtrapolated(easing(x));
});
// Near the extreme point of the effect-easing function
assert_style_left_at(anim, 300, function(x) {
return easingExtrapolated(easing(x));
});
assert_style_left_at(anim, 750, function(x) {
return easingExtrapolated(easing(x));
});
assert_style_left_at(anim, 770, function(x) {
return easing(easing(x))
});
assert_style_left_at(anim, 1000, function(x) {
return easing(easing(x))
});
}, 'effect easing which produces negative values and the tangent on ' +
'the lower boundary is infinity with keyframe easing producing ' +
'negative values');
var gStepTimingFunctionTests = [
{
description: 'Test bounds point of step-start easing',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 0 },
{ currentTime: 999, progress: 0 },
{ currentTime: 1000, progress: 0.5 },
{ currentTime: 1499, progress: 0.5 },
{ currentTime: 1500, progress: 1 },
{ currentTime: 2000, progress: 1 }
]
},
{
description: 'Test bounds point of step-start easing with compositor',
keyframe: [ { opacity: 0 },
{ opacity: 1 } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 0 },
{ currentTime: 999, progress: 0 },
{ currentTime: 1000, progress: 0.5 },
{ currentTime: 1499, progress: 0.5 },
{ currentTime: 1500, progress: 1 },
{ currentTime: 2000, progress: 1 }
]
},
{
description: 'Test bounds point of step-start easing with reverse direction',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
direction: 'reverse',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 1001, progress: 1 },
{ currentTime: 1500, progress: 1 },
{ currentTime: 1501, progress: 0.5 },
{ currentTime: 2000, progress: 0 },
{ currentTime: 2500, progress: 0 }
]
},
{
description: 'Test bounds point of step-start easing ' +
'with iterationStart not at a transition point',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.25,
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 0.5 },
{ currentTime: 999, progress: 0.5 },
{ currentTime: 1000, progress: 0.5 },
{ currentTime: 1249, progress: 0.5 },
{ currentTime: 1250, progress: 1 },
{ currentTime: 1749, progress: 1 },
{ currentTime: 1750, progress: 0.5 },
{ currentTime: 2000, progress: 0.5 },
{ currentTime: 2500, progress: 0.5 },
]
},
{
description: 'Test bounds point of step-start easing ' +
'with iterationStart and delay',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.5,
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 0.5 },
{ currentTime: 999, progress: 0.5 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1499, progress: 1 },
{ currentTime: 1500, progress: 0.5 },
{ currentTime: 2000, progress: 1 }
]
},
{
description: 'Test bounds point of step-start easing ' +
'with iterationStart and reverse direction',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.5,
direction: 'reverse',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1001, progress: 0.5 },
{ currentTime: 1499, progress: 0.5 },
{ currentTime: 1500, progress: 1 },
{ currentTime: 1999, progress: 1 },
{ currentTime: 2000, progress: 0.5 },
{ currentTime: 2500, progress: 0.5 }
]
},
{
description: 'Test bounds point of step(4, start) easing ' +
'with iterationStart 0.75 and delay',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
duration: 1000,
fill: 'both',
delay: 1000,
iterationStart: 0.75,
easing: 'steps(4, start)'
},
conditions: [
{ currentTime: 0, progress: 0.75 },
{ currentTime: 999, progress: 0.75 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 2000, progress: 1 },
{ currentTime: 2500, progress: 1 }
]
},
{
description: 'Test bounds point of step-start easing ' +
'with alternate direction',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
duration: 1000,
fill: 'both',
delay: 1000,
iterations: 2,
iterationStart: 1.5,
direction: 'alternate',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1001, progress: 0.5 },
{ currentTime: 2999, progress: 1 },
{ currentTime: 3000, progress: 0.5 },
{ currentTime: 3500, progress: 0.5 }
]
},
{
description: 'Test bounds point of step-start easing ' +
'with alternate-reverse direction',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
duration: 1000,
fill: 'both',
delay: 1000,
iterations: 2,
iterationStart: 0.5,
direction: 'alternate-reverse',
easing: 'steps(2, start)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1001, progress: 0.5 },
{ currentTime: 2999, progress: 1 },
{ currentTime: 3000, progress: 0.5 },
{ currentTime: 3500, progress: 0.5 }
]
},
{
description: 'Test bounds point of step-start easing in keyframe',
keyframe: [ { width: '0px', easing: 'steps(2, start)' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
},
conditions: [
{ currentTime: 0, progress: 0, width: '0px' },
{ currentTime: 999, progress: 0, width: '0px' },
{ currentTime: 1000, progress: 0, width: '50px' },
{ currentTime: 1499, progress: 0.499, width: '50px' },
{ currentTime: 1500, progress: 0.5, width: '100px' },
{ currentTime: 2000, progress: 1, width: '100px' },
{ currentTime: 2500, progress: 1, width: '100px' }
]
},
{
description: 'Test bounds point of step-end easing ' +
'with iterationStart and delay',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
duration: 1000,
fill: 'both',
delay: 1000,
iterationStart: 0.5,
easing: 'steps(2, end)'
},
conditions: [
{ currentTime: 0, progress: 0 },
{ currentTime: 999, progress: 0 },
{ currentTime: 1000, progress: 0.5 },
{ currentTime: 1499, progress: 0.5 },
{ currentTime: 1500, progress: 0 },
{ currentTime: 1999, progress: 0 },
{ currentTime: 2000, progress: 0.5 },
{ currentTime: 2500, progress: 0.5 }
]
},
{
description: 'Test bounds point of step-end easing ' +
'with iterationStart not at a transition point',
keyframe: [ { width: '0px' },
{ width: '100px' } ],
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.75,
easing: 'steps(2, end)'
},
conditions: [
{ currentTime: 0, progress: 0.5 },
{ currentTime: 999, progress: 0.5 },
{ currentTime: 1000, progress: 0.5 },
{ currentTime: 1249, progress: 0.5 },
{ currentTime: 1250, progress: 0 },
{ currentTime: 1749, progress: 0 },
{ currentTime: 1750, progress: 0.5 },
{ currentTime: 2000, progress: 0.5 },
{ currentTime: 2500, progress: 0.5 },
]
}
];
gStepTimingFunctionTests.forEach(function(options) {
test(function(t) {
var target = createDiv(t);
var animation = target.animate(options.keyframe, options.effect);
options.conditions.forEach(function(condition) {
animation.currentTime = condition.currentTime;
if (typeof condition.progress !== 'undefined') {
assert_equals(animation.effect.getComputedTiming().progress,
condition.progress,
'Progress at ' + animation.currentTime + 'ms');
}
if (typeof condition.width !== 'undefined') {
assert_equals(getComputedStyle(target).width,
condition.width,
'Progress at ' + animation.currentTime + 'ms');
}
});
}, options.description);
});
</script>
</body>

View file

@ -0,0 +1,212 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffectReadOnly getComputedTiming() tests</title>
<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
<link rel="author" title="Boris Chiou" href="mailto:boris.chiou@gmail.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<body>
<div id="log"></div>
<div id="target"></div>
<script>
"use strict";
var target = document.getElementById("target");
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] });
var ct = effect.getComputedTiming();
assert_equals(ct.delay, 0, "computed delay");
assert_equals(ct.fill, "none", "computed fill");
assert_equals(ct.iterations, 1.0, "computed iterations");
assert_equals(ct.duration, 0, "computed duration");
assert_equals(ct.direction, "normal", "computed direction");
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
"constructed without any KeyframeEffectOptions object");
var gGetComputedTimingTests = [
{ desc: "an empty KeyframeEffectOptions object",
input: { },
expected: { } },
{ desc: "a normal KeyframeEffectOptions object",
input: { delay: 1000,
fill: "auto",
iterations: 5.5,
duration: "auto",
direction: "alternate" },
expected: { delay: 1000,
fill: "none",
iterations: 5.5,
duration: 0,
direction: "alternate" } },
{ desc: "a double value",
input: 3000,
timing: { duration: 3000 },
expected: { delay: 0,
fill: "none",
iterations: 1,
duration: 3000,
direction: "normal" } },
{ desc: "+Infinity",
input: Infinity,
expected: { duration: Infinity } },
{ desc: "an Infinity duration",
input: { duration: Infinity },
expected: { duration: Infinity } },
{ desc: "an auto duration",
input: { duration: "auto" },
expected: { duration: 0 } },
{ desc: "an Infinity iterations",
input: { iterations: Infinity },
expected: { iterations: Infinity } },
{ desc: "an auto fill",
input: { fill: "auto" },
expected: { fill: "none" } },
{ desc: "a forwards fill",
input: { fill: "forwards" },
expected: { fill: "forwards" } }
];
gGetComputedTimingTests.forEach(function(stest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] },
stest.input);
// Helper function to provide default expected values when the test does
// not supply them.
var expected = function(field, defaultValue) {
return field in stest.expected ? stest.expected[field] : defaultValue;
};
var ct = effect.getComputedTiming();
assert_equals(ct.delay, expected("delay", 0),
"computed delay");
assert_equals(ct.fill, expected("fill", "none"),
"computed fill");
assert_equals(ct.iterations, expected("iterations", 1),
"computed iterations");
assert_equals(ct.duration, expected("duration", 0),
"computed duration");
assert_equals(ct.direction, expected("direction", "normal"),
"computed direction");
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
"constructed by " + stest.desc);
});
var gActiveDurationTests = [
{ desc: "an empty KeyframeEffectOptions object",
input: { },
expected: 0 },
{ desc: "a non-zero duration and default iteration count",
input: { duration: 1000 },
expected: 1000 },
{ desc: "a non-zero duration and integral iteration count",
input: { duration: 1000, iterations: 7 },
expected: 7000 },
{ desc: "a non-zero duration and fractional iteration count",
input: { duration: 1000, iterations: 2.5 },
expected: 2500 },
{ desc: "an non-zero duration and infinite iteration count",
input: { duration: 1000, iterations: Infinity },
expected: Infinity },
{ desc: "an non-zero duration and zero iteration count",
input: { duration: 1000, iterations: 0 },
expected: 0 },
{ desc: "a zero duration and default iteration count",
input: { duration: 0 },
expected: 0 },
{ desc: "a zero duration and fractional iteration count",
input: { duration: 0, iterations: 2.5 },
expected: 0 },
{ desc: "a zero duration and infinite iteration count",
input: { duration: 0, iterations: Infinity },
expected: 0 },
{ desc: "a zero duration and zero iteration count",
input: { duration: 0, iterations: 0 },
expected: 0 },
{ desc: "an infinite duration and default iteration count",
input: { duration: Infinity },
expected: Infinity },
{ desc: "an infinite duration and zero iteration count",
input: { duration: Infinity, iterations: 0 },
expected: 0 },
{ desc: "an infinite duration and fractional iteration count",
input: { duration: Infinity, iterations: 2.5 },
expected: Infinity },
{ desc: "an infinite duration and infinite iteration count",
input: { duration: Infinity, iterations: Infinity },
expected: Infinity },
];
gActiveDurationTests.forEach(function(stest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] },
stest.input);
assert_equals(effect.getComputedTiming().activeDuration,
stest.expected);
}, "getComputedTiming().activeDuration for " + stest.desc);
});
var gEndTimeTests = [
{ desc: "an empty KeyframeEffectOptions object",
input: { },
expected: 0 },
{ desc: "a non-zero duration and default iteration count",
input: { duration: 1000 },
expected: 1000 },
{ desc: "a non-zero duration and non-default iteration count",
input: { duration: 1000, iterations: 2.5 },
expected: 2500 },
{ desc: "a non-zero duration and non-zero delay",
input: { duration: 1000, delay: 1500 },
expected: 2500 },
{ desc: "a non-zero duration, non-zero delay and non-default iteration",
input: { duration: 1000, delay: 1500, iterations: 2 },
expected: 3500 },
{ desc: "an infinite iteration count",
input: { duration: 1000, iterations: Infinity },
expected: Infinity },
{ desc: "an infinite duration",
input: { duration: Infinity, iterations: 10 },
expected: Infinity },
{ desc: "an infinite duration and delay",
input: { duration: Infinity, iterations: 10, delay: 1000 },
expected: Infinity },
{ desc: "an infinite duration and negative delay",
input: { duration: Infinity, iterations: 10, delay: -1000 },
expected: Infinity },
{ desc: "an non-zero duration and negative delay",
input: { duration: 1000, iterations: 2, delay: -1000 },
expected: 1000 },
{ desc: "an non-zero duration and negative delay greater than active " +
"duration",
input: { duration: 1000, iterations: 2, delay: -3000 },
expected: -1000 },
{ desc: "a zero duration and negative delay",
input: { duration: 0, iterations: 2, delay: -1000 },
expected: -1000 }
];
gEndTimeTests.forEach(function(stest) {
test(function(t) {
var effect = new KeyframeEffectReadOnly(target,
{ left: ["10px", "20px"] },
stest.input);
assert_equals(effect.getComputedTiming().endTime,
stest.expected);
}, "getComputedTiming().endTime for " + stest.desc);
});
done();
</script>
</body>

View file

@ -0,0 +1,89 @@
<!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>
<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',
];
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');
});
// FIXME: Test that non-enumerable properties are not accessed
// 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>

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffect setKeyframes() tests</title>
<link rel="help" href="https://w3c.github.io/web-animations/#dom-keyframeeffect-setkeyframes">
<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';
var target = document.getElementById('target');
test(function(t) {
gEmptyKeyframeListTests.forEach(function(frame) {
var effect = new KeyframeEffect(target, {});
effect.setKeyframes(frame);
assert_frame_lists_equal(effect.getKeyframes(), []);
});
}, 'Keyframes can be replaced with an empty keyframe');
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
test(function(t) {
var effect = new KeyframeEffect(target, {});
effect.setKeyframes(subtest.input);
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
}, 'Keyframes can be replaced with ' + subtest.desc);
});
gKeyframeSequenceTests.forEach(function(subtest) {
test(function(t) {
var effect = new KeyframeEffect(target, {});
effect.setKeyframes(subtest.input);
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
}, 'Keyframes can be replaced with ' + subtest.desc);
});
gInvalidKeyframesTests.forEach(function(subtest) {
test(function(t) {
var effect = new KeyframeEffect(target, {});
assert_throws(subtest.expected, function() {
effect.setKeyframes(subtest.input);
});
}, 'KeyframeEffect constructor throws with ' + subtest.desc);
});
</script>
</body>

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Writable effect.target tests</title>
<link rel="help"
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-target">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<body>
<div id="log"></div>
<script>
"use strict";
var gKeyFrames = { 'marginLeft': ['0px', '100px'] };
test(function(t) {
var div = createDiv(t);
var effect = new KeyframeEffect(null, gKeyFrames, 100 * MS_PER_SEC);
effect.target = div;
var anim = new Animation(effect, document.timeline);
anim.play();
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).marginLeft, '50px',
'Value at 50% progress');
}, 'Test setting target before constructing the associated animation');
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var effect = new KeyframeEffect(null, gKeyFrames, 100 * MS_PER_SEC);
var anim = new Animation(effect, document.timeline);
anim.play();
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).marginLeft, '10px',
'Value at 50% progress before setting new target');
effect.target = div;
assert_equals(getComputedStyle(div).marginLeft, '50px',
'Value at 50% progress after setting new target');
}, 'Test setting target from null to a valid target');
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var anim = div.animate(gKeyFrames, 100 * MS_PER_SEC);
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).marginLeft, '50px',
'Value at 50% progress before clearing the target')
anim.effect.target = null;
assert_equals(getComputedStyle(div).marginLeft, '10px',
'Value after clearing the target')
}, 'Test setting target from a valid target to null');
test(function(t) {
var a = createDiv(t);
var b = createDiv(t);
a.style.marginLeft = '10px';
b.style.marginLeft = '20px';
var anim = a.animate(gKeyFrames, 100 * MS_PER_SEC);
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(a).marginLeft, '50px',
'Value of 1st element (currently targeted) before ' +
'changing the effect target');
assert_equals(getComputedStyle(b).marginLeft, '20px',
'Value of 2nd element (currently not targeted) before ' +
'changing the effect target');
anim.effect.target = b;
assert_equals(getComputedStyle(a).marginLeft, '10px',
'Value of 1st element (currently not targeted) after ' +
'changing the effect target');
assert_equals(getComputedStyle(b).marginLeft, '50px',
'Value of 2nd element (currently targeted) after ' +
'changing the effect target');
// This makes sure the animation property is changed correctly on new
// targeted element.
anim.currentTime = 75 * MS_PER_SEC;
assert_equals(getComputedStyle(b).marginLeft, '75px',
'Value of 2nd target (currently targeted) after ' +
'changing the animation current time.');
}, 'Test setting target from a valid target to another target');
</script>
</body>