122 lines
4.3 KiB
JavaScript
122 lines
4.3 KiB
JavaScript
/*
|
|
* Copyright (C) 2020 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
class AnimationTest
|
|
{
|
|
|
|
// Expects a dictionary with an Element (target) and a Function (styleExtractor) used to extract
|
|
// the recorded value from a computed style.
|
|
constructor(options)
|
|
{
|
|
this._records = [];
|
|
this._target = options.target;
|
|
this._styleExtractor = options.styleExtractor;
|
|
}
|
|
|
|
// Public
|
|
|
|
// Returns the Animation object. Currently, this expects a single animation is running on the
|
|
// provided element.
|
|
get animation()
|
|
{
|
|
return this._target.getAnimations()[0];
|
|
}
|
|
|
|
// Returns the requested value from the computed style using the provided style extractor.
|
|
get value()
|
|
{
|
|
return this._styleExtractor(getComputedStyle(this._target));
|
|
}
|
|
|
|
// Returns the requested value from the computed style after waiting a certain delay.
|
|
// This method runs independently of the animation play state and waits at a minimum
|
|
// for an animation frame to have elapsed.
|
|
async valueAfterWaitingFor(delay)
|
|
{
|
|
await Promise.all([
|
|
new Promise(requestAnimationFrame),
|
|
new Promise(resolve => setTimeout(resolve, delay))
|
|
]);
|
|
return this.value;
|
|
}
|
|
|
|
// Records the requested value from the computed style after a given delay has elapsed while the
|
|
// animation is running. The record stored will be checked when checkRecordedValues() is called.
|
|
async recordValueAfterRunningFor(delay)
|
|
{
|
|
const animation = this.animation;
|
|
await animation.ready;
|
|
|
|
const targetTime = animation.currentTime + delay;
|
|
await this._tickUntil(elapsedTime => animation.currentTime >= targetTime);
|
|
|
|
const value = this.value;
|
|
this._records.push({
|
|
currentTime: animation.currentTime,
|
|
value: value
|
|
});
|
|
|
|
return value;
|
|
}
|
|
|
|
// Check that all requested values recorded using recordValueAfterRunningFor() match the same values
|
|
// when the animation is paused and seeked at the same animation currentTime as when the record was made.
|
|
checkRecordedValues()
|
|
{
|
|
const animation = this.animation;
|
|
|
|
// Reset the animation.
|
|
animation.cancel();
|
|
|
|
// Now seek to each of the recorded times and assert the value.
|
|
this._records.forEach((record, index) => {
|
|
animation.currentTime = record.currentTime;
|
|
assert_equals(record.value, this.value, `Recorded value #${index} is correct.`);
|
|
});
|
|
}
|
|
|
|
// Private
|
|
|
|
// Wait until the provided condition is true using animation frames.
|
|
_tickUntil(condition)
|
|
{
|
|
return new Promise(resolve => {
|
|
if (!this._startTime)
|
|
this._startTime = performance.now();
|
|
|
|
const tick = timestamp => {
|
|
const elapsedTime = timestamp - this._startTime;
|
|
if (condition(elapsedTime)) {
|
|
delete this._startTime;
|
|
resolve();
|
|
}
|
|
requestAnimationFrame(tick);
|
|
}
|
|
requestAnimationFrame(tick);
|
|
});
|
|
}
|
|
|
|
}
|