1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
<!doctype html>
<meta charset=utf-8>
<title>Timelines</title>
<link rel="help" href="https://drafts.csswg.org/web-animations/#timelines">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<style>
@keyframes opacity-animation {
from { opacity: 1; }
to { opacity: 0; }
}
</style>
<div id="log"></div>
<script>
'use strict';
promise_test(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(() => {
assert_greater_than(document.timeline.currentTime, valueAtStart,
'Timeline time increases between animation frames');
});
}, 'Timeline time increases once per animation frame');
async_test(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(t => {
const startTime = document.timeline.currentTime;
let firstRafTime;
requestAnimationFrame(() => {
t.step(() => {
assert_greater_than_equal(document.timeline.currentTime, startTime,
'Timeline time should have progressed');
firstRafTime = document.timeline.currentTime;
});
});
requestAnimationFrame(() => {
t.step(() => {
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');
promise_test(async t => {
// A microtask checkpoint is run as part of the process of updating
// timelines to ensure that any microtasks queued during promise
// resolution are handled before dispatching animation events.
const div = createDiv(t);
const events = [];
let microtaskFrameTime = undefined;
let finishFrameTime = undefined;
const waitForMicrotask = (animation) => {
return new Promise(resolve => {
queueMicrotask(() => {
events.push('microtask');
microtaskFrameTime = document.timeline.currentTime;
resolve();
});
});
}
const waitForFinishEvent = (animation) => {
return new Promise(resolve => {
animation.onfinish = (event) => {
events.push('finish');
finishFrameTime = event.timelineTime;
resolve();
};
});
}
await waitForNextFrame();
const animation = div.animate({ opacity: [0, 1] }, 1000 * MS_PER_SEC);
const finishPromise = waitForFinishEvent(animation);
await animation.ready;
// Advance the timing to effect end, to asynchronously queue up a finish task.
// Queue up microtask, which must be processed ahead of the finish event.
// See "Perform a microtask checkpoint" step in
// https://www.w3.org/TR/web-animations-1/#timelines.
animation.currentTime = animation.effect.getComputedTiming().duration;
const microtaskPromise = waitForMicrotask(animation);
await Promise.all([finishPromise, microtaskPromise]);
assert_array_equals(events, ['microtask', 'finish']);
assert_times_equal(microtaskFrameTime, finishFrameTime);
}, 'Performs a microtask checkpoint after updating timelines');
async_test(t => {
const div = createDiv(t);
let readyPromiseRan = false;
let finishedPromiseRan = false;
div.style.animation = 'opacity-animation 1ms';
let anim = div.getAnimations()[0];
anim.ready.then(t.step_func(() => {
readyPromiseRan = true;
}));
div.addEventListener('animationstart', t.step_func(() => {
assert_true(readyPromiseRan, 'It should run ready promise before animationstart event');
}));
anim.finished.then(t.step_func(() => {
finishedPromiseRan = true;
}));
div.addEventListener('animationend', t.step_func_done(() => {
assert_true(finishedPromiseRan, 'It should run finished promise before animationend event');
}));
}, 'Runs finished promise before animation events');
</script>
|