mirror of
https://github.com/servo/servo.git
synced 2025-08-30 09:38:19 +01:00
Update web-platform-tests to revision 44702f2bc8ea98bc32b5b244f2fe63c6ce66d49d
This commit is contained in:
parent
85fa6409bb
commit
c227604a2c
997 changed files with 45660 additions and 14650 deletions
|
@ -7,6 +7,7 @@
|
|||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/easing-tests.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<script src="../../resources/keyframe-tests.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<iframe width="10" height="10" id="iframe"></iframe>
|
||||
|
@ -81,15 +82,7 @@ gEmptyKeyframeListTests.forEach(function(subTest) {
|
|||
`(input: ${JSON.stringify(subTest)})`);
|
||||
});
|
||||
|
||||
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim = div.animate(subtest.input, 2000);
|
||||
assert_frame_lists_equal(anim.effect.getKeyframes(), subtest.output);
|
||||
}, 'Element.animate() accepts ' + subtest.desc);
|
||||
});
|
||||
|
||||
gKeyframeSequenceTests.forEach(function(subtest) {
|
||||
gKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim = div.animate(subtest.input, 2000);
|
||||
|
@ -100,7 +93,7 @@ gKeyframeSequenceTests.forEach(function(subtest) {
|
|||
gInvalidKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
assert_throws(subtest.expected, function() {
|
||||
assert_throws(new TypeError, function() {
|
||||
div.animate(subtest.input, 2000);
|
||||
});
|
||||
}, 'Element.animate() does not accept ' + subtest.desc);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Animation interface automated IDL tests</title>
|
||||
<title>Animation IDL</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#animation">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/WebIDLParser.js"></script>
|
||||
<script src="/resources/idlharness.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<script type="text/plain" id="Animation-IDL">
|
||||
enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
|
||||
|
@ -34,18 +34,14 @@ interface Animation : EventTarget {
|
|||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
const idlArray = new IdlArray();
|
||||
const idlArray = new IdlArray();
|
||||
|
||||
idlArray.add_untested_idls('interface AnimationTimeline {};');
|
||||
idlArray.add_untested_idls('interface EventHandler {};');
|
||||
idlArray.add_untested_idls('interface EventTarget {};');
|
||||
idlArray.add_idls(
|
||||
document.getElementById('Animation-IDL').textContent);
|
||||
idlArray.add_untested_idls('interface AnimationTimeline {};');
|
||||
idlArray.add_untested_idls('interface EventHandler {};');
|
||||
idlArray.add_untested_idls('interface EventTarget {};');
|
||||
idlArray.add_idls(document.getElementById('Animation-IDL').textContent);
|
||||
idlArray.add_objects( { Animation: ['new Animation()'] } );
|
||||
|
||||
// const animation = createDiv(t).animate(null);
|
||||
idlArray.add_objects( { Animation: ['new Animation()'] } );
|
||||
idlArray.test();
|
||||
});
|
||||
idlArray.test();
|
||||
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>AnimationEffectTiming and AnimationEffectTimingReadOnly IDL</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#animationeffecttiming">
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#animationeffecttimingreadonly">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/WebIDLParser.js"></script>
|
||||
<script src="/resources/idlharness.js"></script>
|
||||
<div id="log"></div>
|
||||
<script type="text/plain" id="AnimationEffectTimingReadOnly-IDL">
|
||||
enum FillMode { "none", "forwards", "backwards", "both", "auto" };
|
||||
enum PlaybackDirection {
|
||||
"normal",
|
||||
"reverse",
|
||||
"alternate",
|
||||
"alternate-reverse"
|
||||
};
|
||||
|
||||
dictionary AnimationEffectTimingProperties {
|
||||
double delay = 0.0;
|
||||
double endDelay = 0.0;
|
||||
FillMode fill = "auto";
|
||||
double iterationStart = 0.0;
|
||||
unrestricted double iterations = 1.0;
|
||||
(unrestricted double or DOMString) duration = "auto";
|
||||
PlaybackDirection direction = "normal";
|
||||
DOMString easing = "linear";
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectTimingReadOnly {
|
||||
readonly attribute double delay;
|
||||
readonly attribute double endDelay;
|
||||
readonly attribute FillMode fill;
|
||||
readonly attribute double iterationStart;
|
||||
readonly attribute unrestricted double iterations;
|
||||
readonly attribute (unrestricted double or DOMString) duration;
|
||||
readonly attribute PlaybackDirection direction;
|
||||
readonly attribute DOMString easing;
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="AnimationEffectTiming-IDL">
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
|
||||
inherit attribute double delay;
|
||||
inherit attribute double endDelay;
|
||||
inherit attribute FillMode fill;
|
||||
inherit attribute double iterationStart;
|
||||
inherit attribute unrestricted double iterations;
|
||||
inherit attribute (unrestricted double or DOMString) duration;
|
||||
inherit attribute PlaybackDirection direction;
|
||||
inherit attribute DOMString easing;
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const idlArray = new IdlArray();
|
||||
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationEffectTimingReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationEffectTiming-IDL').textContent
|
||||
);
|
||||
|
||||
idlArray.add_objects({
|
||||
AnimationEffectTiming: [
|
||||
'(new KeyframeEffect(null, null)).timing'
|
||||
],
|
||||
AnimationEffectTimingReadOnly: [
|
||||
'(new KeyframeEffectReadOnly(null, null)).timing'
|
||||
],
|
||||
});
|
||||
idlArray.test();
|
||||
|
||||
</script>
|
|
@ -0,0 +1,30 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>AnimationPlaybackEvent constructor</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-animationplaybackevent-animationplaybackevent">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
const evt = new AnimationPlaybackEvent('finish');
|
||||
assert_equals(evt.type, 'finish');
|
||||
assert_equals(evt.currentTime, null);
|
||||
assert_equals(evt.timelineTime, null);
|
||||
}, 'Event created without an event parameter has null time values');
|
||||
|
||||
test(function(t) {
|
||||
const evt =
|
||||
new AnimationPlaybackEvent('cancel', {
|
||||
currentTime: -100,
|
||||
timelineTime: 100,
|
||||
});
|
||||
assert_equals(evt.type, 'cancel');
|
||||
assert_equals(evt.currentTime, -100);
|
||||
assert_equals(evt.timelineTime, 100);
|
||||
}, 'Created event reflects times specified in constructor');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,46 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>AnimationPlaybackEvent IDL</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#animationplaybackevent">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/WebIDLParser.js"></script>
|
||||
<script src="/resources/idlharness.js"></script>
|
||||
<div id="log"></div>
|
||||
<script type="text/plain" id="AnimationPlaybackEvent-IDL">
|
||||
dictionary EventInit {
|
||||
boolean bubbles = false;
|
||||
boolean cancelable = false;
|
||||
boolean composed = false;
|
||||
};
|
||||
dictionary AnimationPlaybackEventInit : EventInit {
|
||||
double? currentTime = null;
|
||||
double? timelineTime = null;
|
||||
};
|
||||
|
||||
[Exposed=Window,
|
||||
Constructor (DOMString type,
|
||||
optional AnimationPlaybackEventInit eventInitDict
|
||||
)]
|
||||
interface AnimationPlaybackEvent : Event {
|
||||
readonly attribute double? currentTime;
|
||||
readonly attribute double? timelineTime;
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const idlArray = new IdlArray();
|
||||
|
||||
idlArray.add_untested_idls('interface Event {};');
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationPlaybackEvent-IDL').textContent
|
||||
);
|
||||
idlArray.add_objects({
|
||||
AnimationPlaybackEvent: [ 'new AnimationPlaybackEvent(\'cancel\')' ],
|
||||
});
|
||||
|
||||
idlArray.test();
|
||||
|
||||
</script>
|
|
@ -1,111 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Default document timeline tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#the-documents-default-timeline">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<iframe width="10" height="10" id="iframe"></iframe>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.timeline, document.timeline,
|
||||
'document.timeline returns the same object every time');
|
||||
var iframe = document.getElementById('iframe');
|
||||
assert_not_equals(document.timeline, iframe.contentDocument.timeline,
|
||||
'document.timeline returns a different object for each document');
|
||||
assert_not_equals(iframe.contentDocument.timeline, null,
|
||||
'document.timeline on an iframe is not null');
|
||||
}, 'document.timeline identity tests');
|
||||
|
||||
async_test(function(t) {
|
||||
assert_true(document.timeline.currentTime > 0,
|
||||
'document.timeline.currentTime is positive');
|
||||
// document.timeline.currentTime should be set even before document
|
||||
// load fires. We expect this code to be run before document load and hence
|
||||
// the above assertion is sufficient.
|
||||
// If the following assertion fails, this test needs to be redesigned.
|
||||
assert_true(document.readyState !== 'complete',
|
||||
'Test is running prior to document load');
|
||||
|
||||
// Test that the document timeline's current time is measured from
|
||||
// navigationStart.
|
||||
//
|
||||
// We can't just compare document.timeline.currentTime to
|
||||
// window.performance.now() because currentTime is only updated on a sample
|
||||
// so we use requestAnimationFrame instead.
|
||||
window.requestAnimationFrame(function(rafTime) {
|
||||
t.step(function() {
|
||||
assert_equals(document.timeline.currentTime, rafTime,
|
||||
'document.timeline.currentTime matches' +
|
||||
' requestAnimationFrame time');
|
||||
});
|
||||
t.done();
|
||||
});
|
||||
}, 'document.timeline.currentTime value tests');
|
||||
|
||||
promise_test(function(t) {
|
||||
var valueAtStart = document.timeline.currentTime;
|
||||
var timeAtStart = window.performance.now();
|
||||
while (window.performance.now() - timeAtStart < 50) {
|
||||
// Wait 50ms
|
||||
}
|
||||
assert_equals(document.timeline.currentTime, valueAtStart,
|
||||
'document.timeline.currentTime does not change within a script block');
|
||||
return waitForAnimationFrames(1).then(function() {
|
||||
assert_greater_than(document.timeline.currentTime, valueAtStart,
|
||||
'document.timeline.currentTime increases between script blocks');
|
||||
});
|
||||
}, 'document.timeline.currentTime liveness tests');
|
||||
|
||||
async_test(function(t) {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.width = 10;
|
||||
iframe.height = 10;
|
||||
|
||||
iframe.addEventListener('load', t.step_func(() => {
|
||||
const iframeTimeline = iframe.contentDocument.timeline;
|
||||
const valueAtStart = iframeTimeline.currentTime;
|
||||
const timeAtStart = window.performance.now();
|
||||
while (iframe.contentWindow.performance.now() - timeAtStart < 50) {
|
||||
// Wait 50ms
|
||||
}
|
||||
assert_equals(iframeTimeline.currentTime, valueAtStart,
|
||||
'iframe document.timeline.currentTime does not change within a '
|
||||
+ ' script block');
|
||||
|
||||
iframe.contentWindow.requestAnimationFrame(t.step_func_done(() => {
|
||||
assert_greater_than(iframeTimeline.currentTime, valueAtStart,
|
||||
'iframe document.timeline.currentTime increases between script blocks');
|
||||
iframe.remove();
|
||||
}));
|
||||
}));
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}, 'iframe document.timeline.currentTime liveness tests');
|
||||
|
||||
async_test(function(t) {
|
||||
var startTime = document.timeline.currentTime;
|
||||
var firstRafTime;
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
t.step(function() {
|
||||
assert_greater_than_equal(document.timeline.currentTime, startTime,
|
||||
'currentTime should have progressed');
|
||||
firstRafTime = document.timeline.currentTime;
|
||||
});
|
||||
});
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
t.step(function() {
|
||||
assert_equals(document.timeline.currentTime, firstRafTime,
|
||||
'currentTime should be the same');
|
||||
});
|
||||
t.done();
|
||||
});
|
||||
}, 'document.timeline.currentTime time should be the same for all RAF'
|
||||
+ ' callbacks in a frame');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,23 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Document.timeline</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#dom-document-timeline">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<iframe width="10" height="10" id="iframe"></iframe>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.timeline, document.timeline,
|
||||
'Document.timeline returns the same object every time');
|
||||
const iframe = document.getElementById('iframe');
|
||||
assert_not_equals(document.timeline, iframe.contentDocument.timeline,
|
||||
'Document.timeline returns a different object for each document');
|
||||
assert_not_equals(iframe.contentDocument.timeline, null,
|
||||
'Document.timeline on an iframe is not null');
|
||||
}, 'Document.timeline returns the default document timeline');
|
||||
|
||||
</script>
|
|
@ -1,6 +1,7 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Web Animations API: DocumentTimeline tests</title>
|
||||
<title>DocumentTimeline IDL</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#documenttimeline">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/WebIDLParser.js"></script>
|
||||
|
@ -22,15 +23,14 @@ interface DocumentTimeline : AnimationTimeline {
|
|||
<script>
|
||||
'use strict';
|
||||
|
||||
var idlArray;
|
||||
test(function() {
|
||||
idlArray = new IdlArray();
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationTimeline-IDL').textContent);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('DocumentTimeline-IDL').textContent);
|
||||
idlArray.add_objects( { DocumentTimeline: ['document.timeline'] } );
|
||||
});
|
||||
const idlArray = new IdlArray();
|
||||
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationTimeline-IDL').textContent);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('DocumentTimeline-IDL').textContent);
|
||||
idlArray.add_objects( { DocumentTimeline: ['document.timeline'] } );
|
||||
|
||||
idlArray.test();
|
||||
|
||||
</script>
|
|
@ -1,45 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffectReadOnly constructor tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#the-keyframeeffect-interfaces">
|
||||
<title>KeyframeEffect and KeyframeEffectReadOnly constructor</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-keyframeeffect">
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/easing-tests.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<script src="../../resources/keyframe-tests.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";
|
||||
'use strict';
|
||||
|
||||
var target = document.getElementById("target");
|
||||
const 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));
|
||||
0, 'number of frames for ' + JSON.stringify(frames));
|
||||
});
|
||||
}, "a KeyframeEffectReadOnly can be constructed with no frames");
|
||||
}, 'A KeyframeEffectReadOnly can be constructed with no frames');
|
||||
|
||||
test(function(t) {
|
||||
gEasingParsingTests.forEach(function(subtest) {
|
||||
var easing = subtest[0];
|
||||
var expected = subtest[1];
|
||||
var effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"]
|
||||
const easing = subtest[0];
|
||||
const expected = subtest[1];
|
||||
const effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ['10px', '20px']
|
||||
}, { easing: easing });
|
||||
assert_equals(effect.timing.easing, expected,
|
||||
"resulting easing for '" + easing + "'");
|
||||
`resulting easing for '${easing}'`);
|
||||
});
|
||||
}, "easing values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in KeyframeEffectOptions");
|
||||
}, 'easing values are parsed correctly when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in KeyframeEffectOptions');
|
||||
|
||||
test(function(t) {
|
||||
gInvalidEasings.forEach(invalidEasing => {
|
||||
|
@ -47,183 +46,160 @@ test(function(t) {
|
|||
new KeyframeEffectReadOnly(target, null, { easing: invalidEasing });
|
||||
}, `TypeError is thrown for easing '${invalidEasing}'`);
|
||||
});
|
||||
}, 'invalid easing values are correctly rejected when passed to the ' +
|
||||
}, 'Invalid easing values are correctly rejected when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in KeyframeEffectOptions');
|
||||
|
||||
test(function(t) {
|
||||
var getKeyframe = function(composite) {
|
||||
return { left: [ "10px", "20px" ], composite: composite };
|
||||
const getKeyframe = function(composite) {
|
||||
return { left: [ '10px', '20px' ], composite: composite };
|
||||
};
|
||||
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
|
||||
var effect = new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
const effect = new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
"resulting composite for '" + 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");
|
||||
}, 'composite values are parsed correctly when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in property-indexed keyframes');
|
||||
|
||||
test(function(t) {
|
||||
var getKeyframes = function(composite) {
|
||||
const getKeyframes = function(composite) {
|
||||
return [
|
||||
{ offset: 0, left: "10px", composite: composite },
|
||||
{ offset: 1, left: "20px" }
|
||||
{ offset: 0, left: '10px', composite: composite },
|
||||
{ offset: 1, left: '20px' }
|
||||
];
|
||||
};
|
||||
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
|
||||
var effect = new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
const effect = new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
"resulting composite for '" + 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");
|
||||
}, '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"]
|
||||
const effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ['10px', '20px']
|
||||
}, { composite: composite });
|
||||
assert_equals(effect.getKeyframes()[0].composite, undefined,
|
||||
"resulting composite for '" + composite + "'");
|
||||
`resulting composite for '${composite}'`);
|
||||
});
|
||||
gBadCompositeValueTests.forEach(function(composite) {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"]
|
||||
left: ['10px', '20px']
|
||||
}, { composite: composite });
|
||||
});
|
||||
});
|
||||
}, "composite value is absent if the composite operation specified on the " +
|
||||
"keyframe effect is being used");
|
||||
}, 'composite value is absent if the composite operation specified on the ' +
|
||||
'keyframe effect is being used');
|
||||
|
||||
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
|
||||
gKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
const effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
|
||||
}, `A KeyframeEffectReadOnly can be constructed with ${subtest.desc}`);
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
var secondEffect =
|
||||
const effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
const secondEffect =
|
||||
new KeyframeEffectReadOnly(target, effect.getKeyframes());
|
||||
assert_frame_lists_equal(secondEffect.getKeyframes(),
|
||||
effect.getKeyframes());
|
||||
}, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
|
||||
" roundtrips");
|
||||
});
|
||||
|
||||
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");
|
||||
}, `A KeyframeEffectReadOnly constructed with ${subtest.desc} roundtrips`);
|
||||
});
|
||||
|
||||
gInvalidKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
assert_throws(subtest.expected, function() {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, subtest.input);
|
||||
});
|
||||
}, "KeyframeEffectReadOnly constructor throws with " + subtest.desc);
|
||||
}, `KeyframeEffectReadOnly constructor throws with ${subtest.desc}`);
|
||||
});
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] });
|
||||
const 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");
|
||||
const 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");
|
||||
}, "a KeyframeEffectReadOnly constructed without any " +
|
||||
"KeyframeEffectOptions object");
|
||||
assert_equals(effect.composite, 'replace', 'default composite');
|
||||
assert_equals(effect.iterationComposite, 'replace',
|
||||
'default iterationComposite');
|
||||
}, 'A KeyframeEffectReadOnly constructed without any ' +
|
||||
'KeyframeEffectOptions object');
|
||||
|
||||
gKeyframeEffectOptionTests.forEach(function(stest) {
|
||||
gKeyframeEffectOptionTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
const effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ['10px', '20px'] },
|
||||
subtest.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;
|
||||
const expected = (field, defaultValue) => {
|
||||
return field in subtest.expected ? subtest.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");
|
||||
const 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);
|
||||
}, `A KeyframeEffectReadOnly constructed by ${subtest.desc}`);
|
||||
});
|
||||
|
||||
gInvalidKeyframeEffectOptionTests.forEach(function(stest) {
|
||||
gInvalidKeyframeEffectOptionTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
assert_throws(stest.expected, function() {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
{ left: ['10px', '20px'] },
|
||||
subtest.input);
|
||||
});
|
||||
}, "Invalid KeyframeEffectReadOnly option by " + stest.desc);
|
||||
}, `Invalid KeyframeEffectReadOnly option by ${subtest.desc}`);
|
||||
});
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(null,
|
||||
{ left: ["10px", "20px"] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
fill: "forwards" });
|
||||
const 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");
|
||||
'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" };
|
||||
const 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");
|
||||
}, 'KeyframeEffect constructor propagates exceptions generated by accessing'
|
||||
+ ' the options object');
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -1,27 +1,106 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect copy constructor tests</title>
|
||||
<title>KeyframeEffect and KeyframeEffectReadOnly copy constructor</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-keyframeeffect-source">
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-keyframeeffect-source">
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly-source">
|
||||
<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";
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
const effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
assert_equals(copiedEffect.target, effect.target, 'same target');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same target');
|
||||
|
||||
test(function(t) {
|
||||
const effect =
|
||||
new KeyframeEffectReadOnly(null,
|
||||
[ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px', easing: 'ease-in',
|
||||
offset: 0.1 },
|
||||
{ marginLeft: '100px', easing: 'ease-out' },
|
||||
{ marginLeft: '50px' } ]);
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const keyframesA = effect.getKeyframes();
|
||||
const keyframesB = copiedEffect.getKeyframes();
|
||||
assert_equals(keyframesA.length, keyframesB.length, 'same keyframes length');
|
||||
|
||||
for (let i = 0; i < keyframesA.length; ++i) {
|
||||
assert_equals(keyframesA[i].offset, keyframesB[i].offset,
|
||||
`Keyframe ${i} has the same offset`);
|
||||
assert_equals(keyframesA[i].computedOffset, keyframesB[i].computedOffset,
|
||||
`Keyframe ${i} has the same computedOffset`);
|
||||
assert_equals(keyframesA[i].easing, keyframesB[i].easing,
|
||||
`Keyframe ${i} has the same easing`);
|
||||
assert_equals(keyframesA[i].composite, keyframesB[i].composite,
|
||||
`Keyframe ${i} has the same composite`);
|
||||
|
||||
assert_true(!!keyframesA[i].marginLeft,
|
||||
`Original keyframe ${i} has a valid property value`);
|
||||
assert_true(!!keyframesB[i].marginLeft,
|
||||
`New keyframe ${i} has a valid property value`);
|
||||
assert_equals(keyframesA[i].marginLeft, keyframesB[i].marginLeft,
|
||||
`Keyframe ${i} has the same property value pair`);
|
||||
}
|
||||
}, 'Copied KeyframeEffectReadOnly has the same keyframes');
|
||||
|
||||
test(function(t) {
|
||||
const effect =
|
||||
new KeyframeEffectReadOnly(null, null,
|
||||
{ iterationComposite: 'accumulate' });
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
assert_equals(copiedEffect.iterationComposite, effect.iterationComposite,
|
||||
'same iterationCompositeOperation');
|
||||
assert_equals(copiedEffect.composite, effect.composite,
|
||||
'same compositeOperation');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same KeyframeEffectOptions');
|
||||
|
||||
test(function(t) {
|
||||
const effect = new KeyframeEffectReadOnly(null, null,
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
delay: -1 * MS_PER_SEC,
|
||||
endDelay: 2 * MS_PER_SEC,
|
||||
fill: 'forwards',
|
||||
iterationStart: 2,
|
||||
iterations: 20,
|
||||
easing: 'ease-out',
|
||||
direction: 'alternate' } );
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const timingA = effect.timing;
|
||||
const timingB = copiedEffect.timing;
|
||||
assert_not_equals(timingA, timingB, 'different timing objects');
|
||||
assert_equals(timingA.delay, timingB.delay, 'same delay');
|
||||
assert_equals(timingA.endDelay, timingB.endDelay, 'same endDelay');
|
||||
assert_equals(timingA.fill, timingB.fill, 'same fill');
|
||||
assert_equals(timingA.iterationStart, timingB.iterationStart,
|
||||
'same iterationStart');
|
||||
assert_equals(timingA.iterations, timingB.iterations, 'same iterations');
|
||||
assert_equals(timingA.duration, timingB.duration, 'same duration');
|
||||
assert_equals(timingA.direction, timingB.direction, 'same direction');
|
||||
assert_equals(timingA.easing, timingB.easing, 'same easing');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same timing content');
|
||||
|
||||
test(function(t) {
|
||||
const effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
assert_equals(effect.constructor.name, 'KeyframeEffectReadOnly');
|
||||
assert_equals(effect.timing.constructor.name,
|
||||
'AnimationEffectTimingReadOnly');
|
||||
|
||||
// Make a mutable copy
|
||||
var copiedEffect = new KeyframeEffect(effect);
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
assert_equals(copiedEffect.constructor.name, 'KeyframeEffect');
|
||||
assert_equals(copiedEffect.timing.constructor.name, 'AnimationEffectTiming');
|
||||
}, 'Test mutable copy from a KeyframeEffectReadOnly source');
|
||||
}, 'KeyframeEffect constructed from a KeyframeEffectReadOnly is mutable');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect IDL</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#keyframeeffect">
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#keyframeeffectreadonly">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/WebIDLParser.js"></script>
|
||||
<script src="/resources/idlharness.js"></script>
|
||||
<div id="log"></div>
|
||||
<script type="text/plain" id="AnimationEffectTimingReadOnly-IDL">
|
||||
enum FillMode { "none", "forwards", "backwards", "both", "auto" };
|
||||
enum PlaybackDirection {
|
||||
"normal",
|
||||
"reverse",
|
||||
"alternate",
|
||||
"alternate-reverse"
|
||||
};
|
||||
|
||||
dictionary AnimationEffectTimingProperties {
|
||||
double delay = 0.0;
|
||||
double endDelay = 0.0;
|
||||
FillMode fill = "auto";
|
||||
double iterationStart = 0.0;
|
||||
unrestricted double iterations = 1.0;
|
||||
(unrestricted double or DOMString) duration = "auto";
|
||||
PlaybackDirection direction = "normal";
|
||||
DOMString easing = "linear";
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectTimingReadOnly {
|
||||
readonly attribute double delay;
|
||||
readonly attribute double endDelay;
|
||||
readonly attribute FillMode fill;
|
||||
readonly attribute double iterationStart;
|
||||
readonly attribute unrestricted double iterations;
|
||||
readonly attribute (unrestricted double or DOMString) duration;
|
||||
readonly attribute PlaybackDirection direction;
|
||||
readonly attribute DOMString easing;
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="AnimationEffectReadOnly-IDL">
|
||||
dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
|
||||
unrestricted double endTime;
|
||||
unrestricted double activeDuration;
|
||||
double? localTime;
|
||||
double? progress;
|
||||
unrestricted double? currentIteration;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectReadOnly {
|
||||
readonly attribute AnimationEffectTimingReadOnly timing;
|
||||
ComputedTimingProperties getComputedTiming();
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="KeyframeEffectReadOnly-IDL">
|
||||
enum IterationCompositeOperation { "replace", "accumulate" };
|
||||
enum CompositeOperation { "replace", "add", "accumulate" };
|
||||
|
||||
dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
|
||||
IterationCompositeOperation iterationComposite = "replace";
|
||||
CompositeOperation composite = "replace";
|
||||
};
|
||||
|
||||
[Exposed=Window,
|
||||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
|
||||
readonly attribute (Element or CSSPseudoElement)? target;
|
||||
readonly attribute IterationCompositeOperation iterationComposite;
|
||||
readonly attribute CompositeOperation composite;
|
||||
sequence<object> getKeyframes ();
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="KeyframeEffect-IDL">
|
||||
[Exposed=Window,
|
||||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffect : KeyframeEffectReadOnly {
|
||||
inherit attribute (Element or CSSPseudoElement)? target;
|
||||
inherit attribute IterationCompositeOperation iterationComposite;
|
||||
inherit attribute CompositeOperation composite;
|
||||
void setKeyframes (object? keyframes);
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const idlArray = new IdlArray();
|
||||
|
||||
idlArray.add_untested_idls('interface CSSPseudoElement {};');
|
||||
idlArray.add_untested_idls('interface Element {};');
|
||||
idlArray.add_untested_idls(
|
||||
document.getElementById('AnimationEffectTimingReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationEffectReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('KeyframeEffectReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('KeyframeEffect-IDL').textContent
|
||||
);
|
||||
idlArray.add_objects({
|
||||
KeyframeEffect: ['new KeyframeEffect(null, null)'],
|
||||
KeyframeEffectReadOnly: ['new KeyframeEffectReadOnly(null, null)'],
|
||||
});
|
||||
|
||||
idlArray.test();
|
||||
|
||||
</script>
|
|
@ -6,6 +6,7 @@
|
|||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<script src="../../resources/keyframe-tests.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
|
@ -22,15 +23,7 @@ test(function(t) {
|
|||
});
|
||||
}, '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) {
|
||||
gKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
effect.setKeyframes(subtest.input);
|
||||
|
@ -41,7 +34,7 @@ gKeyframeSequenceTests.forEach(function(subtest) {
|
|||
gInvalidKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
assert_throws(subtest.expected, function() {
|
||||
assert_throws(new TypeError, function() {
|
||||
effect.setKeyframes(subtest.input);
|
||||
});
|
||||
}, 'KeyframeEffect constructor throws with ' + subtest.desc);
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffectReadOnly copy constructor tests</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly-source">
|
||||
<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";
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
var copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
assert_equals(copiedEffect.target, effect.target, 'same target');
|
||||
}, 'Test copied keyframeEffectReadOnly has the same target');
|
||||
|
||||
test(function(t) {
|
||||
var effect =
|
||||
new KeyframeEffectReadOnly(null,
|
||||
[ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px', easing: 'ease-in',
|
||||
offset: 0.1 },
|
||||
{ marginLeft: '100px', easing: 'ease-out' },
|
||||
{ marginLeft: '50px' } ],
|
||||
{ spacing: 'paced(margin-left)' });
|
||||
|
||||
var copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
var KeyframesA = effect.getKeyframes();
|
||||
var KeyframesB = copiedEffect.getKeyframes();
|
||||
assert_equals(KeyframesA.length, KeyframesB.length, 'same keyframes length');
|
||||
|
||||
for (var i = 0; i < KeyframesA.length; ++i) {
|
||||
assert_equals(KeyframesA[i].offset, KeyframesB[i].offset,
|
||||
'Keyframe ' + i + ' has the same offset');
|
||||
assert_equals(KeyframesA[i].computedOffset, KeyframesB[i].computedOffset,
|
||||
'keyframe ' + i + ' has the same computedOffset');
|
||||
assert_equals(KeyframesA[i].easing, KeyframesB[i].easing,
|
||||
'keyframe ' + i + ' has the same easing');
|
||||
assert_equals(KeyframesA[i].composite, KeyframesB[i].composite,
|
||||
'keyframe ' + i + ' has the same composite');
|
||||
|
||||
assert_true(!!KeyframesA[i].marginLeft,
|
||||
'original keyframe ' + i + ' has the valid property value');
|
||||
assert_true(!!KeyframesB[i].marginLeft,
|
||||
'new keyframe ' + i + ' has the valid property value');
|
||||
assert_equals(KeyframesA[i].marginLeft, KeyframesB[i].marginLeft,
|
||||
'keyframe ' + i + ' has the same property value pair');
|
||||
}
|
||||
}, 'Test copied keyframeEffectReadOnly has the same keyframes');
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(null, null,
|
||||
{ spacing: 'paced(margin-left)',
|
||||
iterationComposite: 'accumulate' });
|
||||
|
||||
var copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
assert_equals(copiedEffect.spacing, effect.spacing, 'same spacing');
|
||||
assert_equals(copiedEffect.iterationComposite, effect.iterationComposite,
|
||||
'same iterationCompositeOperation');
|
||||
assert_equals(copiedEffect.composite, effect.composite,
|
||||
'same compositeOperation');
|
||||
}, 'Test copied keyframeEffectReadOnly has the same keyframeEffectOptions');
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(null, null,
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
delay: -1 * MS_PER_SEC,
|
||||
endDelay: 2 * MS_PER_SEC,
|
||||
fill: 'forwards',
|
||||
iterationStart: 2,
|
||||
iterations: 20,
|
||||
easing: 'ease-out',
|
||||
direction: 'alternate' } );
|
||||
|
||||
var copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
var timingA = effect.timing;
|
||||
var timingB = copiedEffect.timing;
|
||||
assert_not_equals(timingA, timingB, 'different timing objects');
|
||||
assert_equals(timingA.delay, timingB.delay, 'same delay');
|
||||
assert_equals(timingA.endDelay, timingB.endDelay, 'same endDelay');
|
||||
assert_equals(timingA.fill, timingB.fill, 'same fill');
|
||||
assert_equals(timingA.iterationStart, timingB.iterationStart,
|
||||
'same iterationStart');
|
||||
assert_equals(timingA.iterations, timingB.iterations, 'same iterations');
|
||||
assert_equals(timingA.duration, timingB.duration, 'same duration');
|
||||
assert_equals(timingA.direction, timingB.direction, 'same direction');
|
||||
assert_equals(timingA.easing, timingB.easing, 'same easing');
|
||||
}, 'Test copied keyframeEffectReadOnly has the same timing content');
|
||||
|
||||
</script>
|
||||
</body>
|
|
@ -0,0 +1,760 @@
|
|||
'use strict';
|
||||
|
||||
// ==============================
|
||||
//
|
||||
// Common keyframe test data
|
||||
//
|
||||
// ==============================
|
||||
|
||||
|
||||
// ------------------------------
|
||||
// Composite values
|
||||
// ------------------------------
|
||||
|
||||
const gGoodKeyframeCompositeValueTests = [
|
||||
'replace', 'add', 'accumulate', undefined
|
||||
];
|
||||
|
||||
const gGoodOptionsCompositeValueTests = [
|
||||
'replace', 'add', 'accumulate'
|
||||
];
|
||||
|
||||
const gBadCompositeValueTests = [
|
||||
'unrecognised', 'replace ', 'Replace', null
|
||||
];
|
||||
|
||||
// ------------------------------
|
||||
// Keyframes
|
||||
// ------------------------------
|
||||
|
||||
const gEmptyKeyframeListTests = [
|
||||
[],
|
||||
null,
|
||||
undefined,
|
||||
];
|
||||
|
||||
// Helper methods to make defining computed keyframes more readable.
|
||||
|
||||
const offset = offset => ({
|
||||
offset,
|
||||
computedOffset: offset,
|
||||
});
|
||||
|
||||
const computedOffset = computedOffset => ({
|
||||
offset: null,
|
||||
computedOffset,
|
||||
});
|
||||
|
||||
const keyframe = (offset, props, easing='linear', composite) => {
|
||||
// The object spread operator is not yet available in all browsers so we use
|
||||
// Object.assign instead.
|
||||
const result = {};
|
||||
Object.assign(result, offset, props, { easing });
|
||||
if (composite) {
|
||||
result.composite = composite;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const gKeyframesTests = [
|
||||
|
||||
// ----------- Property-indexed keyframes: property handling -----------
|
||||
|
||||
{
|
||||
desc: 'a one property two value property-indexed keyframes specification',
|
||||
input: { left: ['10px', '20px'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(1), { left: '20px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one shorthand property two value property-indexed keyframes'
|
||||
+ ' specification',
|
||||
input: { margin: ['10px', '10px 20px 30px 40px'] },
|
||||
output: [keyframe(computedOffset(0), { margin: '10px' }),
|
||||
keyframe(computedOffset(1), { margin: '10px 20px 30px 40px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property (one shorthand and one of its longhand components)'
|
||||
+ ' two value property-indexed keyframes specification',
|
||||
input: { marginTop: ['50px', '60px'],
|
||||
margin: ['10px', '10px 20px 30px 40px'] },
|
||||
output: [keyframe(computedOffset(0),
|
||||
{ marginTop: '50px', margin: '10px' }),
|
||||
keyframe(computedOffset(1),
|
||||
{ marginTop: '60px', margin: '10px 20px 30px 40px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property two value property-indexed keyframes specification',
|
||||
input: { left: ['10px', '20px'],
|
||||
top: ['30px', '40px'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px', top: '30px' }),
|
||||
keyframe(computedOffset(1), { left: '20px', top: '40px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property property-indexed keyframes specification with'
|
||||
+ ' different numbers of values',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
top: ['40px', '50px'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px', top: '40px' }),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px', top: '50px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframes specification with an invalid value',
|
||||
input: { left: ['10px', '20px', '30px', '40px', '50px'],
|
||||
top: ['15px', '25px', 'invalid', '45px', '55px'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px', top: '15px' }),
|
||||
keyframe(computedOffset(0.25), { left: '20px', top: '25px' }),
|
||||
keyframe(computedOffset(0.5), { left: '30px' }),
|
||||
keyframe(computedOffset(0.75), { left: '40px', top: '45px' }),
|
||||
keyframe(computedOffset(1), { left: '50px', top: '55px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property two value property-indexed keyframes specification'
|
||||
+ ' that needs to stringify its values',
|
||||
input: { opacity: [0, 1] },
|
||||
output: [keyframe(computedOffset(0), { opacity: '0' }),
|
||||
keyframe(computedOffset(1), { opacity: '1' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframes specification with a CSS variable'
|
||||
+ ' reference',
|
||||
input: { left: [ 'var(--dist)', 'calc(var(--dist) + 100px)' ] },
|
||||
output: [keyframe(computedOffset(0), { left: 'var(--dist)' }),
|
||||
keyframe(computedOffset(1), { left: 'calc(var(--dist) + 100px)' })]
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframes specification with a CSS variable'
|
||||
+ ' reference in a shorthand property',
|
||||
input: { margin: [ 'var(--dist)', 'calc(var(--dist) + 100px)' ] },
|
||||
output: [keyframe(computedOffset(0),
|
||||
{ margin: 'var(--dist)' }),
|
||||
keyframe(computedOffset(1),
|
||||
{ margin: 'calc(var(--dist) + 100px)' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property one value property-indexed keyframes specification',
|
||||
input: { left: ['10px'] },
|
||||
output: [keyframe(computedOffset(1), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property one non-array value property-indexed keyframes'
|
||||
+ ' specification',
|
||||
input: { left: '10px' },
|
||||
output: [keyframe(computedOffset(1), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property two value property-indexed keyframes specification'
|
||||
+ ' where the first value is invalid',
|
||||
input: { left: ['invalid', '10px'] },
|
||||
output: [keyframe(computedOffset(0), {}),
|
||||
keyframe(computedOffset(1), { left: '10px' })]
|
||||
},
|
||||
{
|
||||
desc: 'a one property two value property-indexed keyframes specification'
|
||||
+ ' where the second value is invalid',
|
||||
input: { left: ['10px', 'invalid'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(1), {})]
|
||||
},
|
||||
|
||||
// ----------- Property-indexed keyframes: offset handling -----------
|
||||
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single offset',
|
||||
input: { left: ['10px', '20px', '30px'], offset: 0.5 },
|
||||
output: [keyframe(offset(0.5), { left: '10px' }),
|
||||
keyframe(computedOffset(0.75), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets',
|
||||
input: { left: ['10px', '20px', '30px'], offset: [ 0.1, 0.25, 0.8 ] },
|
||||
output: [keyframe(offset(0.1), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(offset(0.8), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets that is too'
|
||||
+ ' short',
|
||||
input: { left: ['10px', '20px', '30px'], offset: [ 0, 0.25 ] },
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets that is too'
|
||||
+ ' long',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ 0, 0.25, 0.5, 0.75, 1 ] },
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(offset(0.5), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an empty array of offsets',
|
||||
input: { left: ['10px', '20px', '30px'], offset: [] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets with an'
|
||||
+ ' embedded null value',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ 0, null, 0.5 ] },
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.25), { left: '20px' }),
|
||||
keyframe(offset(0.5), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets with a'
|
||||
+ ' trailing null value',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ 0, 0.25, null ] },
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets with leading'
|
||||
+ ' and trailing null values',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ null, 0.25, null ] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets with'
|
||||
+ ' adjacent null values',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ null, null, 0.5 ] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.25), { left: '20px' }),
|
||||
keyframe(offset(0.5), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets with'
|
||||
+ ' all null values (and too many at that)',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ null, null, null, null, null ] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single null offset',
|
||||
input: { left: ['10px', '20px', '30px'], offset: null },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }),
|
||||
keyframe(computedOffset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of offsets that is not'
|
||||
+ ' strictly ascending in the unused part of the array',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
offset: [ 0, 0.2, 0.8, 0.6 ] },
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.2), { left: '20px' }),
|
||||
keyframe(offset(0.8), { left: '30px' })],
|
||||
},
|
||||
|
||||
// ----------- Property-indexed keyframes: easing handling -----------
|
||||
|
||||
{
|
||||
desc: 'a property-indexed keyframe without any specified easing',
|
||||
input: { left: ['10px', '20px', '30px'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'linear'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'linear'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'linear')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single easing',
|
||||
input: { left: ['10px', '20px', '30px'], easing: 'ease-in' },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'ease-in'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'ease-in'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'ease-in')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of easings',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
easing: ['ease-in', 'ease-out', 'ease-in-out'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'ease-in'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'ease-out'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'ease-in-out')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of easings that is too'
|
||||
+ ' short',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
easing: ['ease-in', 'ease-out'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'ease-in'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'ease-out'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'ease-in')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single-element array of'
|
||||
+ ' easings',
|
||||
input: { left: ['10px', '20px', '30px'], easing: ['ease-in'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'ease-in'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'ease-in'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'ease-in')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an empty array of easings',
|
||||
input: { left: ['10px', '20px', '30px'], easing: [] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'linear'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'linear'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'linear')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with an array of easings that is too'
|
||||
+ ' long',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
easing: ['steps(1)', 'steps(2)', 'steps(3)', 'steps(4)'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'steps(1)'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'steps(2)'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'steps(3)')],
|
||||
},
|
||||
|
||||
// ----------- Property-indexed keyframes: composite handling -----------
|
||||
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single composite operation',
|
||||
input: { left: ['10px', '20px', '30px'], composite: 'add' },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'linear', 'add'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'linear', 'add'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'linear', 'add')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a composite array',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
composite: ['add', 'replace', 'accumulate'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' },
|
||||
'linear', 'add'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' },
|
||||
'linear', 'replace'),
|
||||
keyframe(computedOffset(1), { left: '30px' },
|
||||
'linear', 'accumulate')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a composite array that is too'
|
||||
+ ' short',
|
||||
input: { left: ['10px', '20px', '30px', '40px', '50px'],
|
||||
composite: ['add', 'replace'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' },
|
||||
'linear', 'add'),
|
||||
keyframe(computedOffset(0.25), { left: '20px' },
|
||||
'linear', 'replace'),
|
||||
keyframe(computedOffset(0.5), { left: '30px' },
|
||||
'linear', 'add'),
|
||||
keyframe(computedOffset(0.75), { left: '40px' },
|
||||
'linear', 'replace'),
|
||||
keyframe(computedOffset(1), { left: '50px' },
|
||||
'linear', 'add')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a composite array that is too'
|
||||
+ ' long',
|
||||
input: { left: ['10px', '20px'],
|
||||
composite: ['add', 'replace', 'accumulate'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' },
|
||||
'linear', 'add'),
|
||||
keyframe(computedOffset(1), { left: '20px' },
|
||||
'linear', 'replace')],
|
||||
},
|
||||
{
|
||||
desc: 'a property-indexed keyframe with a single-element composite array',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
composite: ['add'] },
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }, 'linear', 'add'),
|
||||
keyframe(computedOffset(0.5), { left: '20px' }, 'linear', 'add'),
|
||||
keyframe(computedOffset(1), { left: '30px' }, 'linear', 'add')],
|
||||
},
|
||||
|
||||
// ----------- Keyframe sequence: property handling -----------
|
||||
|
||||
{
|
||||
desc: 'a one property one keyframe sequence',
|
||||
input: [{ offset: 1, left: '10px' }],
|
||||
output: [keyframe(offset(1), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property two keyframe sequence',
|
||||
input: [{ offset: 0, left: '10px' },
|
||||
{ offset: 1, left: '20px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(1), { left: '20px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property two keyframe sequence',
|
||||
input: [{ offset: 0, left: '10px', top: '30px' },
|
||||
{ offset: 1, left: '20px', top: '40px' }],
|
||||
output: [keyframe(offset(0), { left: '10px', top: '30px' }),
|
||||
keyframe(offset(1), { left: '20px', top: '40px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one shorthand property two keyframe sequence',
|
||||
input: [{ offset: 0, margin: '10px' },
|
||||
{ offset: 1, margin: '20px 30px 40px 50px' }],
|
||||
output: [keyframe(offset(0), { margin: '10px' }),
|
||||
keyframe(offset(1), { margin: '20px 30px 40px 50px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property (a shorthand and one of its component longhands)'
|
||||
+ ' two keyframe sequence',
|
||||
input: [{ offset: 0, margin: '10px', marginTop: '20px' },
|
||||
{ offset: 1, marginTop: '70px', margin: '30px 40px 50px 60px' }],
|
||||
output: [keyframe(offset(0), { margin: '10px', marginTop: '20px' }),
|
||||
keyframe(offset(1), { marginTop: '70px',
|
||||
margin: '30px 40px 50px 60px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property keyframe sequence where one property is missing'
|
||||
+ ' from the first keyframe',
|
||||
input: [{ offset: 0, left: '10px' },
|
||||
{ offset: 1, left: '20px', top: '30px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(1), { left: '20px', top: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property keyframe sequence where one property is missing'
|
||||
+ ' from the last keyframe',
|
||||
input: [{ offset: 0, left: '10px', top: '20px' },
|
||||
{ offset: 1, left: '30px' }],
|
||||
output: [keyframe(offset(0), { left: '10px', top: '20px' }),
|
||||
keyframe(offset(1), { left: '30px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property two keyframe sequence that needs to stringify'
|
||||
+ ' its values',
|
||||
input: [{ offset: 0, opacity: 0 },
|
||||
{ offset: 1, opacity: 1 }],
|
||||
output: [keyframe(offset(0), { opacity: '0' }),
|
||||
keyframe(offset(1), { opacity: '1' })],
|
||||
},
|
||||
{
|
||||
desc: 'a keyframe sequence with a CSS variable reference',
|
||||
input: [{ left: 'var(--dist)' },
|
||||
{ left: 'calc(var(--dist) + 100px)' }],
|
||||
output: [keyframe(computedOffset(0), { left: 'var(--dist)' }),
|
||||
keyframe(computedOffset(1), { left: 'calc(var(--dist) + 100px)' })]
|
||||
},
|
||||
{
|
||||
desc: 'a keyframe sequence with a CSS variable reference in a shorthand'
|
||||
+ ' property',
|
||||
input: [{ margin: 'var(--dist)' },
|
||||
{ margin: 'calc(var(--dist) + 100px)' }],
|
||||
output: [keyframe(computedOffset(0),
|
||||
{ margin: 'var(--dist)' }),
|
||||
keyframe(computedOffset(1),
|
||||
{ margin: 'calc(var(--dist) + 100px)' })],
|
||||
},
|
||||
|
||||
// ----------- Keyframe sequence: offset handling -----------
|
||||
|
||||
{
|
||||
desc: 'a keyframe sequence with duplicate values for a given interior'
|
||||
+ ' offset',
|
||||
input: [{ offset: 0.0, left: '10px' },
|
||||
{ offset: 0.5, left: '20px' },
|
||||
{ offset: 0.5, left: '30px' },
|
||||
{ offset: 0.5, left: '40px' },
|
||||
{ offset: 1.0, left: '50px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.5), { left: '20px' }),
|
||||
keyframe(offset(0.5), { left: '30px' }),
|
||||
keyframe(offset(0.5), { left: '40px' }),
|
||||
keyframe(offset(1), { left: '50px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a keyframe sequence with duplicate values for offsets 0 and 1',
|
||||
input: [{ offset: 0, left: '10px' },
|
||||
{ offset: 0, left: '20px' },
|
||||
{ offset: 0, left: '30px' },
|
||||
{ offset: 1, left: '40px' },
|
||||
{ offset: 1, left: '50px' },
|
||||
{ offset: 1, left: '60px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0), { left: '20px' }),
|
||||
keyframe(offset(0), { left: '30px' }),
|
||||
keyframe(offset(1), { left: '40px' }),
|
||||
keyframe(offset(1), { left: '50px' }),
|
||||
keyframe(offset(1), { left: '60px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property four keyframe sequence',
|
||||
input: [{ offset: 0, left: '10px' },
|
||||
{ offset: 0, top: '20px' },
|
||||
{ offset: 1, top: '30px' },
|
||||
{ offset: 1, left: '40px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0), { top: '20px' }),
|
||||
keyframe(offset(1), { top: '30px' }),
|
||||
keyframe(offset(1), { left: '40px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a single keyframe sequence with omitted offset',
|
||||
input: [{ left: '10px' }],
|
||||
output: [keyframe(computedOffset(1), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a single keyframe sequence with null offset',
|
||||
input: [{ offset: null, left: '10px' }],
|
||||
output: [keyframe(computedOffset(1), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a single keyframe sequence with string offset',
|
||||
input: [{ offset: '0.5', left: '10px' }],
|
||||
output: [keyframe(offset(0.5), { left: '10px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property keyframe sequence with some omitted offsets',
|
||||
input: [{ offset: 0.00, left: '10px' },
|
||||
{ offset: 0.25, left: '20px' },
|
||||
{ left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ offset: 1.00, left: '50px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(0.5), { left: '30px' }),
|
||||
keyframe(computedOffset(0.75), { left: '40px' }),
|
||||
keyframe(offset(1), { left: '50px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property keyframe sequence with some null offsets',
|
||||
input: [{ offset: 0.00, left: '10px' },
|
||||
{ offset: 0.25, left: '20px' },
|
||||
{ offset: null, left: '30px' },
|
||||
{ offset: null, left: '40px' },
|
||||
{ offset: 1.00, left: '50px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }),
|
||||
keyframe(offset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(0.5), { left: '30px' }),
|
||||
keyframe(computedOffset(0.75), { left: '40px' }),
|
||||
keyframe(offset(1), { left: '50px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a two property keyframe sequence with some omitted offsets',
|
||||
input: [{ offset: 0.00, left: '10px', top: '20px' },
|
||||
{ offset: 0.25, left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ left: '50px', top: '60px' },
|
||||
{ offset: 1.00, left: '70px', top: '80px' }],
|
||||
output: [keyframe(offset(0), { left: '10px', top: '20px' }),
|
||||
keyframe(offset(0.25), { left: '30px' }),
|
||||
keyframe(computedOffset(0.5), { left: '40px' }),
|
||||
keyframe(computedOffset(0.75), { left: '50px', top: '60px' }),
|
||||
keyframe(offset(1), { left: '70px', top: '80px' })],
|
||||
},
|
||||
{
|
||||
desc: 'a one property keyframe sequence with all omitted offsets',
|
||||
input: [{ left: '10px' },
|
||||
{ left: '20px' },
|
||||
{ left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ left: '50px' }],
|
||||
output: [keyframe(computedOffset(0), { left: '10px' }),
|
||||
keyframe(computedOffset(0.25), { left: '20px' }),
|
||||
keyframe(computedOffset(0.5), { left: '30px' }),
|
||||
keyframe(computedOffset(0.75), { left: '40px' }),
|
||||
keyframe(computedOffset(1), { left: '50px' })],
|
||||
},
|
||||
|
||||
// ----------- Keyframe sequence: easing handling -----------
|
||||
|
||||
{
|
||||
desc: 'a keyframe sequence with different easing values, but the same'
|
||||
+ ' easing value for a given offset',
|
||||
input: [{ offset: 0.0, easing: 'ease', left: '10px'},
|
||||
{ offset: 0.0, easing: 'ease', top: '20px'},
|
||||
{ offset: 0.5, easing: 'linear', left: '30px' },
|
||||
{ offset: 0.5, easing: 'linear', top: '40px' },
|
||||
{ offset: 1.0, easing: 'step-end', left: '50px' },
|
||||
{ offset: 1.0, easing: 'step-end', top: '60px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }, 'ease'),
|
||||
keyframe(offset(0), { top: '20px' }, 'ease'),
|
||||
keyframe(offset(0.5), { left: '30px' }, 'linear'),
|
||||
keyframe(offset(0.5), { top: '40px' }, 'linear'),
|
||||
keyframe(offset(1), { left: '50px' }, 'steps(1)'),
|
||||
keyframe(offset(1), { top: '60px' }, 'steps(1)')],
|
||||
},
|
||||
|
||||
// ----------- Keyframe sequence: composite handling -----------
|
||||
|
||||
{
|
||||
desc: 'a keyframe sequence with different composite values, but the'
|
||||
+ ' same composite value for a given offset',
|
||||
input: [{ offset: 0.0, composite: 'replace', left: '10px' },
|
||||
{ offset: 0.0, composite: 'replace', top: '20px' },
|
||||
{ offset: 0.5, composite: 'add', left: '30px' },
|
||||
{ offset: 0.5, composite: 'add', top: '40px' },
|
||||
{ offset: 1.0, composite: 'replace', left: '50px' },
|
||||
{ offset: 1.0, composite: 'replace', top: '60px' }],
|
||||
output: [keyframe(offset(0), { left: '10px' }, 'linear', 'replace'),
|
||||
keyframe(offset(0), { top: '20px' }, 'linear', 'replace'),
|
||||
keyframe(offset(0.5), { left: '30px' }, 'linear', 'add'),
|
||||
keyframe(offset(0.5), { top: '40px' }, 'linear', 'add'),
|
||||
keyframe(offset(1), { left: '50px' }, 'linear', 'replace'),
|
||||
keyframe(offset(1), { top: '60px' }, 'linear', 'replace')],
|
||||
},
|
||||
];
|
||||
|
||||
const gInvalidKeyframesTests = [
|
||||
{
|
||||
desc: 'keyframes with an out-of-bounded positive offset',
|
||||
input: [ { opacity: 0 },
|
||||
{ opacity: 0.5, offset: 2 },
|
||||
{ opacity: 1 } ],
|
||||
},
|
||||
{
|
||||
desc: 'keyframes with an out-of-bounded negative offset',
|
||||
input: [ { opacity: 0 },
|
||||
{ opacity: 0.5, offset: -1 },
|
||||
{ opacity: 1 } ],
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes not loosely sorted by offset',
|
||||
input: { opacity: [ 0, 1 ], offset: [ 1, 0 ] },
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes not loosely sorted by offset even'
|
||||
+ ' though not all offsets are specified',
|
||||
input: { opacity: [ 0, 0.5, 1 ], offset: [ 0.5, 0 ] },
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes with offsets out of range',
|
||||
input: { opacity: [ 0, 0.5, 1 ], offset: [ 0, 1.1 ] },
|
||||
},
|
||||
{
|
||||
desc: 'keyframes not loosely sorted by offset',
|
||||
input: [ { opacity: 0, offset: 1 },
|
||||
{ opacity: 1, offset: 0 } ],
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes with an invalid easing value',
|
||||
input: { opacity: [ 0, 0.5, 1 ],
|
||||
easing: 'inherit' },
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes with an invalid easing value as one of'
|
||||
+ ' the array values',
|
||||
input: { opacity: [ 0, 0.5, 1 ],
|
||||
easing: [ 'ease-in', 'inherit' ] },
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframe with an invalid easing in the unused'
|
||||
+ ' part of the array of easings',
|
||||
input: { left: ['10px', '20px', '30px'],
|
||||
easing: ['steps(1)', 'steps(2)', 'steps(3)', 'invalid'] },
|
||||
},
|
||||
{
|
||||
desc: 'empty property-indexed keyframe with an invalid easing',
|
||||
input: { easing: 'invalid' },
|
||||
},
|
||||
{
|
||||
desc: 'empty property-indexed keyframe with an invalid easings array',
|
||||
input: { easing: ['invalid'] },
|
||||
},
|
||||
{
|
||||
desc: 'a keyframe sequence with an invalid easing value',
|
||||
input: [ { opacity: 0, easing: 'jumpy' },
|
||||
{ opacity: 1 } ],
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes with an invalid composite value',
|
||||
input: { opacity: [ 0, 0.5, 1 ],
|
||||
composite: 'alternate' },
|
||||
},
|
||||
{
|
||||
desc: 'property-indexed keyframes with an invalid composite value as one'
|
||||
+ ' of the array values',
|
||||
input: { opacity: [ 0, 0.5, 1 ],
|
||||
composite: [ 'add', 'alternate' ] },
|
||||
},
|
||||
{
|
||||
desc: 'keyframes with an invalid composite value',
|
||||
input: [ { opacity: 0, composite: 'alternate' },
|
||||
{ opacity: 1 } ],
|
||||
},
|
||||
];
|
||||
|
||||
// ------------------------------
|
||||
// KeyframeEffectOptions
|
||||
// ------------------------------
|
||||
|
||||
const gKeyframeEffectOptionTests = [
|
||||
{
|
||||
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: 'auto',
|
||||
iterations: 5.5,
|
||||
duration: 'auto',
|
||||
direction: 'alternate' },
|
||||
},
|
||||
{
|
||||
desc: 'a double value',
|
||||
input: 3000,
|
||||
expected: { duration: 3000 },
|
||||
},
|
||||
{
|
||||
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: 'auto' },
|
||||
},
|
||||
{
|
||||
desc: 'an Infinity iterations',
|
||||
input: { iterations: Infinity },
|
||||
expected: { iterations: Infinity },
|
||||
},
|
||||
{
|
||||
desc: 'an auto fill',
|
||||
input: { fill: 'auto' },
|
||||
expected: { fill: 'auto' },
|
||||
},
|
||||
{
|
||||
desc: 'a forwards fill',
|
||||
input: { fill: 'forwards' },
|
||||
expected: { fill: 'forwards' },
|
||||
}
|
||||
];
|
||||
|
||||
const gInvalidKeyframeEffectOptionTests = [
|
||||
{ desc: '-Infinity', input: -Infinity },
|
||||
{ desc: 'NaN', input: NaN },
|
||||
{ desc: 'a negative value', input: -1 },
|
||||
{ desc: 'a negative Infinity duration', input: { duration: -Infinity } },
|
||||
{ desc: 'a NaN duration', input: { duration: NaN } },
|
||||
{ desc: 'a negative duration', input: { duration: -1 } },
|
||||
{ desc: 'a string duration', input: { duration: 'merrychristmas' } },
|
||||
{ desc: 'a negative Infinity iterations', input: { iterations: -Infinity} },
|
||||
{ desc: 'a NaN iterations', input: { iterations: NaN } },
|
||||
{ desc: 'a negative iterations', input: { iterations: -1 } },
|
||||
{ desc: 'a blank easing', input: { easing: '' } },
|
||||
{ desc: 'an unrecognized easing', input: { easing: 'unrecognised' } },
|
||||
{ desc: 'an \'initial\' easing', input: { easing: 'initial' } },
|
||||
{ desc: 'an \'inherit\' easing', input: { easing: 'inherit' } },
|
||||
{ desc: 'a variable easing', input: { easing: 'var(--x)' } },
|
||||
{ desc: 'a multi-value easing', input: { easing: 'ease-in-out, ease-out' } },
|
||||
];
|
|
@ -1,6 +1,11 @@
|
|||
"use strict";
|
||||
'use strict';
|
||||
|
||||
// =======================================
|
||||
//
|
||||
// Utility functions for testing keyframes
|
||||
//
|
||||
// =======================================
|
||||
|
||||
// Utility functions and common keyframe test data.
|
||||
|
||||
// ------------------------------
|
||||
// Helper functions
|
||||
|
@ -12,543 +17,18 @@
|
|||
* @param {Array.<ComputedKeyframe>} b - expected computed keyframes
|
||||
*/
|
||||
function assert_frame_lists_equal(a, b) {
|
||||
assert_equals(a.length, b.length, "number of frames");
|
||||
for (var i = 0; i < Math.min(a.length, b.length); i++) {
|
||||
assert_frames_equal(a[i], b[i], "ComputedKeyframe #" + i);
|
||||
assert_equals(a.length, b.length, 'number of frames');
|
||||
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
||||
assert_frames_equal(a[i], b[i], `ComputedKeyframe #${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper */
|
||||
/** Helper for assert_frame_lists_equal */
|
||||
function assert_frames_equal(a, b, name) {
|
||||
assert_equals(Object.keys(a).sort().toString(),
|
||||
Object.keys(b).sort().toString(),
|
||||
"properties on " + name);
|
||||
for (var p in a) {
|
||||
assert_equals(a[p], b[p], "value for '" + p + "' on " + name);
|
||||
`properties on ${name} should match`);
|
||||
for (const p in a) {
|
||||
assert_equals(a[p], b[p], `value for '${p}' on ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// Composite values
|
||||
// ------------------------------
|
||||
|
||||
var gGoodKeyframeCompositeValueTests = [
|
||||
"replace", "add", "accumulate", undefined
|
||||
];
|
||||
|
||||
var gGoodOptionsCompositeValueTests = [
|
||||
"replace", "add", "accumulate"
|
||||
];
|
||||
|
||||
var gBadCompositeValueTests = [
|
||||
"unrecognised", "replace ", "Replace", null
|
||||
];
|
||||
|
||||
// ------------------------------
|
||||
// Keyframes
|
||||
// ------------------------------
|
||||
|
||||
var gEmptyKeyframeListTests = [
|
||||
[],
|
||||
null,
|
||||
undefined,
|
||||
];
|
||||
|
||||
var gPropertyIndexedKeyframesTests = [
|
||||
{ desc: "a one property two value property-indexed keyframes specification",
|
||||
input: { left: ["10px", "20px"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "20px" }] },
|
||||
{ desc: "a one shorthand property two value property-indexed keyframes"
|
||||
+ " specification",
|
||||
input: { margin: ["10px", "10px 20px 30px 40px"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
margin: "10px" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
margin: "10px 20px 30px 40px" }] },
|
||||
{ desc: "a two property (one shorthand and one of its longhand components)"
|
||||
+ " two value property-indexed keyframes specification",
|
||||
input: { marginTop: ["50px", "60px"],
|
||||
margin: ["10px", "10px 20px 30px 40px"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
marginTop: "50px", margin: "10px" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
marginTop: "60px", margin: "10px 20px 30px 40px" }] },
|
||||
{ desc: "a two property two value property-indexed keyframes specification",
|
||||
input: { left: ["10px", "20px"],
|
||||
top: ["30px", "40px"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
left: "10px", top: "30px" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "20px", top: "40px" }] },
|
||||
{ desc: "a two property property-indexed keyframes specification with"
|
||||
+ " different numbers of values",
|
||||
input: { left: ["10px", "20px", "30px"],
|
||||
top: ["40px", "50px"] },
|
||||
output: [{ offset: null, computedOffset: 0.0, easing: "linear",
|
||||
left: "10px", top: "40px" },
|
||||
{ offset: null, computedOffset: 0.5, easing: "linear",
|
||||
left: "20px" },
|
||||
{ offset: null, computedOffset: 1.0, easing: "linear",
|
||||
left: "30px", top: "50px" }] },
|
||||
{ desc: "a property-indexed keyframes specification with an invalid value",
|
||||
input: { left: ["10px", "20px", "30px", "40px", "50px"],
|
||||
top: ["15px", "25px", "invalid", "45px", "55px"] },
|
||||
output: [{ offset: null, computedOffset: 0.00, easing: "linear",
|
||||
left: "10px", top: "15px" },
|
||||
{ offset: null, computedOffset: 0.25, easing: "linear",
|
||||
left: "20px", top: "25px" },
|
||||
{ offset: null, computedOffset: 0.50, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: null, computedOffset: 0.75, easing: "linear",
|
||||
left: "40px", top: "45px" },
|
||||
{ offset: null, computedOffset: 1.00, easing: "linear",
|
||||
left: "50px", top: "55px" }] },
|
||||
{ desc: "a one property two value property-indexed keyframes specification"
|
||||
+ " that needs to stringify its values",
|
||||
input: { opacity: [0, 1] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
opacity: "0" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
opacity: "1" }] },
|
||||
{ desc: "a property-indexed keyframes specification with a CSS variable"
|
||||
+ " reference",
|
||||
input: { left: [ "var(--dist)", "calc(var(--dist) + 100px)" ] },
|
||||
output: [{ offset: null, computedOffset: 0.0, easing: "linear",
|
||||
left: "var(--dist)" },
|
||||
{ offset: null, computedOffset: 1.0, easing: "linear",
|
||||
left: "calc(var(--dist) + 100px)" }] },
|
||||
{ desc: "a property-indexed keyframes specification with a CSS variable"
|
||||
+ " reference in a shorthand property",
|
||||
input: { margin: [ "var(--dist)", "calc(var(--dist) + 100px)" ] },
|
||||
output: [{ offset: null, computedOffset: 0.0, easing: "linear",
|
||||
margin: "var(--dist)" },
|
||||
{ offset: null, computedOffset: 1.0, easing: "linear",
|
||||
margin: "calc(var(--dist) + 100px)" }] },
|
||||
{ desc: "a one property one value property-indexed keyframes specification",
|
||||
input: { left: ["10px"] },
|
||||
output: [{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a one property one non-array value property-indexed keyframes"
|
||||
+ " specification",
|
||||
input: { left: "10px" },
|
||||
output: [{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a one property two value property-indexed keyframes specification"
|
||||
+ " where the first value is invalid",
|
||||
input: { left: ["invalid", "10px"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a one property two value property-indexed keyframes specification"
|
||||
+ " where the second value is invalid",
|
||||
input: { left: ["10px", "invalid"] },
|
||||
output: [{ offset: null, computedOffset: 0, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: null, computedOffset: 1, easing: "linear" }] },
|
||||
];
|
||||
|
||||
var gKeyframeSequenceTests = [
|
||||
{ desc: "a one property one keyframe sequence",
|
||||
input: [{ offset: 1, left: "10px" }],
|
||||
output: [{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a one property two keyframe sequence",
|
||||
input: [{ offset: 0, left: "10px" },
|
||||
{ offset: 1, left: "20px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", left: "20px" }]
|
||||
},
|
||||
{ desc: "a two property two keyframe sequence",
|
||||
input: [{ offset: 0, left: "10px", top: "30px" },
|
||||
{ offset: 1, left: "20px", top: "40px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
left: "10px", top: "30px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
left: "20px", top: "40px" }] },
|
||||
{ desc: "a one shorthand property two keyframe sequence",
|
||||
input: [{ offset: 0, margin: "10px" },
|
||||
{ offset: 1, margin: "20px 30px 40px 50px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
margin: "10px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
margin: "20px 30px 40px 50px" }] },
|
||||
{ desc: "a two property (a shorthand and one of its component longhands)"
|
||||
+ " two keyframe sequence",
|
||||
input: [{ offset: 0, margin: "10px", marginTop: "20px" },
|
||||
{ offset: 1, marginTop: "70px", margin: "30px 40px 50px 60px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
margin: "10px", marginTop: "20px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
marginTop: "70px", margin: "30px 40px 50px 60px" }] },
|
||||
{ desc: "a keyframe sequence with duplicate values for a given interior"
|
||||
+ " offset",
|
||||
input: [{ offset: 0.0, left: "10px" },
|
||||
{ offset: 0.5, left: "20px" },
|
||||
{ offset: 0.5, left: "30px" },
|
||||
{ offset: 0.5, left: "40px" },
|
||||
{ offset: 1.0, left: "50px" }],
|
||||
output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "20px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "40px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "linear",
|
||||
left: "50px" }] },
|
||||
{ desc: "a keyframe sequence with duplicate values for offsets 0 and 1",
|
||||
input: [{ offset: 0, left: "10px" },
|
||||
{ offset: 0, left: "20px" },
|
||||
{ offset: 0, left: "30px" },
|
||||
{ offset: 1, left: "40px" },
|
||||
{ offset: 1, left: "50px" },
|
||||
{ offset: 1, left: "60px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" },
|
||||
{ offset: 0, computedOffset: 0, easing: "linear", left: "20px" },
|
||||
{ offset: 0, computedOffset: 0, easing: "linear", left: "30px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", left: "40px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", left: "50px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", left: "60px" }]
|
||||
},
|
||||
{ desc: "a two property four keyframe sequence",
|
||||
input: [{ offset: 0, left: "10px" },
|
||||
{ offset: 0, top: "20px" },
|
||||
{ offset: 1, top: "30px" },
|
||||
{ offset: 1, left: "40px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" },
|
||||
{ offset: 0, computedOffset: 0, easing: "linear", top: "20px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", top: "30px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", left: "40px" }]
|
||||
},
|
||||
{ desc: "a single keyframe sequence with omitted offset",
|
||||
input: [{ left: "10px" }],
|
||||
output: [{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a single keyframe sequence with null offset",
|
||||
input: [{ offset: null, left: "10px" }],
|
||||
output: [{ offset: null, computedOffset: 1, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a single keyframe sequence with string offset",
|
||||
input: [{ offset: '0.5', left: "10px" }],
|
||||
output: [{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "10px" }] },
|
||||
{ desc: "a one property keyframe sequence with some omitted offsets",
|
||||
input: [{ offset: 0.00, left: "10px" },
|
||||
{ offset: 0.25, left: "20px" },
|
||||
{ left: "30px" },
|
||||
{ left: "40px" },
|
||||
{ offset: 1.00, left: "50px" }],
|
||||
output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: 0.25, computedOffset: 0.25, easing: "linear",
|
||||
left: "20px" },
|
||||
{ offset: null, computedOffset: 0.50, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: null, computedOffset: 0.75, easing: "linear",
|
||||
left: "40px" },
|
||||
{ offset: 1.00, computedOffset: 1.00, easing: "linear",
|
||||
left: "50px" }] },
|
||||
{ desc: "a one property keyframe sequence with some null offsets",
|
||||
input: [{ offset: 0.00, left: "10px" },
|
||||
{ offset: 0.25, left: "20px" },
|
||||
{ offset: null, left: "30px" },
|
||||
{ offset: null, left: "40px" },
|
||||
{ offset: 1.00, left: "50px" }],
|
||||
output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: 0.25, computedOffset: 0.25, easing: "linear",
|
||||
left: "20px" },
|
||||
{ offset: null, computedOffset: 0.50, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: null, computedOffset: 0.75, easing: "linear",
|
||||
left: "40px" },
|
||||
{ offset: 1.00, computedOffset: 1.00, easing: "linear",
|
||||
left: "50px" }] },
|
||||
{ desc: "a two property keyframe sequence with some omitted offsets",
|
||||
input: [{ offset: 0.00, left: "10px", top: "20px" },
|
||||
{ offset: 0.25, left: "30px" },
|
||||
{ left: "40px" },
|
||||
{ left: "50px", top: "60px" },
|
||||
{ offset: 1.00, left: "70px", top: "80px" }],
|
||||
output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear",
|
||||
left: "10px", top: "20px" },
|
||||
{ offset: 0.25, computedOffset: 0.25, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: null, computedOffset: 0.50, easing: "linear",
|
||||
left: "40px" },
|
||||
{ offset: null, computedOffset: 0.75, easing: "linear",
|
||||
left: "50px", top: "60px" },
|
||||
{ offset: 1.00, computedOffset: 1.00, easing: "linear",
|
||||
left: "70px", top: "80px" }] },
|
||||
{ desc: "a one property keyframe sequence with all omitted offsets",
|
||||
input: [{ left: "10px" },
|
||||
{ left: "20px" },
|
||||
{ left: "30px" },
|
||||
{ left: "40px" },
|
||||
{ left: "50px" }],
|
||||
output: [{ offset: null, computedOffset: 0.00, easing: "linear",
|
||||
left: "10px" },
|
||||
{ offset: null, computedOffset: 0.25, easing: "linear",
|
||||
left: "20px" },
|
||||
{ offset: null, computedOffset: 0.50, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: null, computedOffset: 0.75, easing: "linear",
|
||||
left: "40px" },
|
||||
{ offset: null, computedOffset: 1.00, easing: "linear",
|
||||
left: "50px" }] },
|
||||
{ desc: "a keyframe sequence with different easing values, but the same"
|
||||
+ " easing value for a given offset",
|
||||
input: [{ offset: 0.0, easing: "ease", left: "10px"},
|
||||
{ offset: 0.0, easing: "ease", top: "20px"},
|
||||
{ offset: 0.5, easing: "linear", left: "30px" },
|
||||
{ offset: 0.5, easing: "linear", top: "40px" },
|
||||
{ offset: 1.0, easing: "step-end", left: "50px" },
|
||||
{ offset: 1.0, easing: "step-end", top: "60px" }],
|
||||
output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",
|
||||
left: "10px" },
|
||||
{ offset: 0.0, computedOffset: 0.0, easing: "ease",
|
||||
top: "20px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "30px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
top: "40px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
|
||||
left: "50px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
|
||||
top: "60px" }] },
|
||||
{ desc: "a keyframe sequence with different composite values, but the"
|
||||
+ " same composite value for a given offset",
|
||||
input: [{ offset: 0.0, composite: "replace", left: "10px" },
|
||||
{ offset: 0.0, composite: "replace", top: "20px" },
|
||||
{ offset: 0.5, composite: "add", left: "30px" },
|
||||
{ offset: 0.5, composite: "add", top: "40px" },
|
||||
{ offset: 1.0, composite: "replace", left: "50px" },
|
||||
{ offset: 1.0, composite: "replace", top: "60px" }],
|
||||
output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear",
|
||||
composite: "replace", left: "10px" },
|
||||
{ offset: 0.0, computedOffset: 0.0, easing: "linear",
|
||||
composite: "replace", top: "20px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
composite: "add", left: "30px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
composite: "add", top: "40px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "linear",
|
||||
composite: "replace", left: "50px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "linear",
|
||||
composite: "replace", top: "60px" }] },
|
||||
{ desc: "a one property two keyframe sequence that needs to stringify"
|
||||
+ " its values",
|
||||
input: [{ offset: 0, opacity: 0 },
|
||||
{ offset: 1, opacity: 1 }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear", opacity: "0" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear", opacity: "1" }]
|
||||
},
|
||||
{ desc: "a keyframe sequence with a CSS variable reference",
|
||||
input: [{ left: "var(--dist)" },
|
||||
{ left: "calc(var(--dist) + 100px)" }],
|
||||
output: [{ offset: null, computedOffset: 0.0, easing: "linear",
|
||||
left: "var(--dist)" },
|
||||
{ offset: null, computedOffset: 1.0, easing: "linear",
|
||||
left: "calc(var(--dist) + 100px)" }] },
|
||||
{ desc: "a keyframe sequence with a CSS variable reference in a shorthand"
|
||||
+ " property",
|
||||
input: [{ margin: "var(--dist)" },
|
||||
{ margin: "calc(var(--dist) + 100px)" }],
|
||||
output: [{ offset: null, computedOffset: 0.0, easing: "linear",
|
||||
margin: "var(--dist)" },
|
||||
{ offset: null, computedOffset: 1.0, easing: "linear",
|
||||
margin: "calc(var(--dist) + 100px)" }] },
|
||||
{ desc: "a keyframe sequence where shorthand precedes longhand",
|
||||
input: [{ offset: 0, margin: "10px", marginRight: "20px" },
|
||||
{ offset: 1, margin: "30px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
margin: "10px", marginRight: "20px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
margin: "30px" }] },
|
||||
{ desc: "a keyframe sequence where longhand precedes shorthand",
|
||||
input: [{ offset: 0, marginRight: "20px", margin: "10px" },
|
||||
{ offset: 1, margin: "30px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
marginRight: "20px", margin: "10px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
margin: "30px" }] },
|
||||
{ desc: "a keyframe sequence where lesser shorthand precedes greater"
|
||||
+ " shorthand",
|
||||
input: [{ offset: 0,
|
||||
borderLeft: "1px solid rgb(1, 2, 3)",
|
||||
border: "2px dotted rgb(4, 5, 6)" },
|
||||
{ offset: 1, border: "3px dashed rgb(7, 8, 9)" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
borderLeft: "1px solid rgb(1, 2, 3)",
|
||||
border: "2px dotted rgb(4, 5, 6)" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
border: "3px dashed rgb(7, 8, 9)" }] },
|
||||
{ desc: "a keyframe sequence where greater shorthand precedes lesser"
|
||||
+ " shorthand",
|
||||
input: [{ offset: 0, border: "2px dotted rgb(4, 5, 6)",
|
||||
borderLeft: "1px solid rgb(1, 2, 3)" },
|
||||
{ offset: 1, border: "3px dashed rgb(7, 8, 9)" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
border: "2px dotted rgb(4, 5, 6)",
|
||||
borderLeft: "1px solid rgb(1, 2, 3)" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
border: "3px dashed rgb(7, 8, 9)" }] },
|
||||
{ desc: "a two property keyframe sequence where one property is missing"
|
||||
+ " from the first keyframe",
|
||||
input: [{ offset: 0, left: "10px" },
|
||||
{ offset: 1, left: "20px", top: "30px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear", left: "10px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
left: "20px", top: "30px" }] },
|
||||
{ desc: "a two property keyframe sequence where one property is missing"
|
||||
+ " from the last keyframe",
|
||||
input: [{ offset: 0, left: "10px", top: "20px" },
|
||||
{ offset: 1, left: "30px" }],
|
||||
output: [{ offset: 0, computedOffset: 0, easing: "linear",
|
||||
left: "10px" , top: "20px" },
|
||||
{ offset: 1, computedOffset: 1, easing: "linear",
|
||||
left: "30px" }] },
|
||||
{ desc: "a keyframe sequence with repeated values at offset 1 with"
|
||||
+ " different easings",
|
||||
input: [{ offset: 0.0, left: "100px", easing: "ease" },
|
||||
{ offset: 0.0, left: "200px", easing: "ease" },
|
||||
{ offset: 0.5, left: "300px", easing: "linear" },
|
||||
{ offset: 1.0, left: "400px", easing: "ease-out" },
|
||||
{ offset: 1.0, left: "500px", easing: "step-end" }],
|
||||
output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",
|
||||
left: "100px" },
|
||||
{ offset: 0.0, computedOffset: 0.0, easing: "ease",
|
||||
left: "200px" },
|
||||
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
|
||||
left: "300px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "ease-out",
|
||||
left: "400px" },
|
||||
{ offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
|
||||
left: "500px" }] },
|
||||
];
|
||||
|
||||
var gInvalidKeyframesTests = [
|
||||
{ desc: "keyframes with an out-of-bounded positive offset",
|
||||
input: [ { opacity: 0 },
|
||||
{ opacity: 0.5, offset: 2 },
|
||||
{ opacity: 1 } ],
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "keyframes with an out-of-bounded negative offset",
|
||||
input: [ { opacity: 0 },
|
||||
{ opacity: 0.5, offset: -1 },
|
||||
{ opacity: 1 } ],
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "keyframes not loosely sorted by offset",
|
||||
input: [ { opacity: 0, offset: 1 },
|
||||
{ opacity: 1, offset: 0 } ],
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "property-indexed keyframes with an invalid easing value",
|
||||
input: { opacity: [ 0, 0.5, 1 ],
|
||||
easing: "inherit" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a keyframe sequence with an invalid easing value",
|
||||
input: [ { opacity: 0, easing: "jumpy" },
|
||||
{ opacity: 1 } ],
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "keyframes with an invalid composite value",
|
||||
input: [ { opacity: 0, composite: "alternate" },
|
||||
{ opacity: 1 } ],
|
||||
expected: { name: "TypeError" } }
|
||||
];
|
||||
|
||||
// ------------------------------
|
||||
// KeyframeEffectOptions
|
||||
// ------------------------------
|
||||
|
||||
var gKeyframeEffectOptionTests = [
|
||||
{ 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: "auto",
|
||||
iterations: 5.5,
|
||||
duration: "auto",
|
||||
direction: "alternate" } },
|
||||
{ desc: "a double value",
|
||||
input: 3000,
|
||||
expected: { duration: 3000 } },
|
||||
{ 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: "auto" } },
|
||||
{ desc: "an Infinity iterations",
|
||||
input: { iterations: Infinity },
|
||||
expected: { iterations: Infinity } },
|
||||
{ desc: "an auto fill",
|
||||
input: { fill: "auto" },
|
||||
expected: { fill: "auto" } },
|
||||
{ desc: "a forwards fill",
|
||||
input: { fill: "forwards" },
|
||||
expected: { fill: "forwards" } }
|
||||
];
|
||||
|
||||
var gInvalidKeyframeEffectOptionTests = [
|
||||
{ desc: "-Infinity",
|
||||
input: -Infinity,
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "NaN",
|
||||
input: NaN,
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a negative value",
|
||||
input: -1,
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a negative Infinity duration",
|
||||
input: { duration: -Infinity },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a NaN duration",
|
||||
input: { duration: NaN },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a negative duration",
|
||||
input: { duration: -1 },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a string duration",
|
||||
input: { duration: "merrychristmas" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a negative Infinity iterations",
|
||||
input: { iterations: -Infinity},
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a NaN iterations",
|
||||
input: { iterations: NaN },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a negative iterations",
|
||||
input: { iterations: -1 },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a blank easing",
|
||||
input: { easing: "" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "an unrecognized easing",
|
||||
input: { easing: "unrecognised" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "an 'initial' easing",
|
||||
input: { easing: "initial" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "an 'inherit' easing",
|
||||
input: { easing: "inherit" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a variable easing",
|
||||
input: { easing: "var(--x)" },
|
||||
expected: { name: "TypeError" } },
|
||||
{ desc: "a multi-value easing",
|
||||
input: { easing: "ease-in-out, ease-out" },
|
||||
expected: { name: "TypeError" } }
|
||||
];
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Document timelines</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#document-timelines">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
async_test(function(t) {
|
||||
assert_true(document.timeline.currentTime > 0,
|
||||
'The current time is initially is positive');
|
||||
// document.timeline.currentTime should be set even before document
|
||||
// load fires. We expect this code to be run before document load and hence
|
||||
// the above assertion is sufficient.
|
||||
// If the following assertion fails, this test needs to be redesigned.
|
||||
assert_true(document.readyState !== 'complete',
|
||||
'Test is running prior to document load');
|
||||
|
||||
// Test that the document timeline's current time is measured from
|
||||
// navigationStart.
|
||||
//
|
||||
// We can't just compare document.timeline.currentTime to
|
||||
// window.performance.now() because currentTime is only updated on a sample
|
||||
// so we use requestAnimationFrame instead.
|
||||
window.requestAnimationFrame(function(rafTime) {
|
||||
t.step(function() {
|
||||
assert_equals(document.timeline.currentTime, rafTime,
|
||||
'The current time matches requestAnimationFrame time');
|
||||
});
|
||||
t.done();
|
||||
});
|
||||
}, 'Document timelines report current time relative to navigationStart');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Timelines</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#timelines">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
promise_test(function(t) {
|
||||
const valueAtStart = document.timeline.currentTime;
|
||||
const timeAtStart = window.performance.now();
|
||||
while (window.performance.now() - timeAtStart < 50) {
|
||||
// Wait 50ms
|
||||
}
|
||||
assert_equals(document.timeline.currentTime, valueAtStart,
|
||||
'Timeline time does not change within an animation frame');
|
||||
return waitForAnimationFrames(1).then(function() {
|
||||
assert_greater_than(document.timeline.currentTime, valueAtStart,
|
||||
'Timeline time increases between animation frames');
|
||||
});
|
||||
}, 'Timeline time increases once per animation frame');
|
||||
|
||||
async_test(function(t) {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.width = 10;
|
||||
iframe.height = 10;
|
||||
|
||||
iframe.addEventListener('load', t.step_func(() => {
|
||||
const iframeTimeline = iframe.contentDocument.timeline;
|
||||
const valueAtStart = iframeTimeline.currentTime;
|
||||
const timeAtStart = window.performance.now();
|
||||
while (iframe.contentWindow.performance.now() - timeAtStart < 50) {
|
||||
// Wait 50ms
|
||||
}
|
||||
assert_equals(iframeTimeline.currentTime, valueAtStart,
|
||||
'Timeline time within an iframe does not change within an '
|
||||
+ ' animation frame');
|
||||
|
||||
iframe.contentWindow.requestAnimationFrame(t.step_func_done(() => {
|
||||
assert_greater_than(iframeTimeline.currentTime, valueAtStart,
|
||||
'Timeline time within an iframe increases between animation frames');
|
||||
iframe.remove();
|
||||
}));
|
||||
}));
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}, 'Timeline time increases once per animation frame in an iframe');
|
||||
|
||||
async_test(function(t) {
|
||||
const startTime = document.timeline.currentTime;
|
||||
let firstRafTime;
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
t.step(function() {
|
||||
assert_greater_than_equal(document.timeline.currentTime, startTime,
|
||||
'Timeline time should have progressed');
|
||||
firstRafTime = document.timeline.currentTime;
|
||||
});
|
||||
});
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
t.step(function() {
|
||||
assert_equals(document.timeline.currentTime, firstRafTime,
|
||||
'Timeline time should be the same');
|
||||
});
|
||||
t.done();
|
||||
});
|
||||
}, 'Timeline time should be the same for all RAF callbacks in an animation'
|
||||
+ ' frame');
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue