Bug 1431573 - Part 12: Add tests. r=gl

MozReview-Commit-ID: E9WzhYeUm5R
This commit is contained in:
Daisuke Akatsuka 2018-03-13 16:45:20 +09:00
parent c4bdd329b4
commit 9bff79382a
11 changed files with 718 additions and 1 deletions

View File

@ -2,6 +2,7 @@
tags = devtools
subsuite = devtools
support-files =
doc_custom_playback_rate.html
doc_multi_easings.html
doc_multi_keyframes.html
doc_multi_timings.html
@ -22,11 +23,19 @@ support-files =
[browser_animation_animation-list.js]
[browser_animation_animation-target.js]
[browser_animation_animation-timeline-tick.js]
[browser_animation_current-time-label.js]
[browser_animation_current-time-scrubber.js]
[browser_animation_empty_on_invalid_nodes.js]
[browser_animation_inspector_exists.js]
[browser_animation_keyframes-graph_computed-value-path.js]
[browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
[browser_animation_keyframes-graph_keyframe-marker.js]
[browser_animation_keyframes-progress-bar.js]
[browser_animation_logic_auto-stop.js]
[browser_animation_pause-resume-button.js]
[browser_animation_pause-resume-button_spacebar.js]
[browser_animation_playback-rate-selector.js]
[browser_animation_rewind-button.js]
[browser_animation_summary-graph_animation-name.js]
[browser_animation_summary-graph_compositor.js]
[browser_animation_summary-graph_computed-timing-path.js]

View File

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following CurrentTimeLabel component:
// * element existence
// * label content at plural timing
add_task(async function () {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking current time label existence");
const labelEl = panel.querySelector(".current-time-label");
ok(labelEl, "current time label should exist");
info("Checking current time label content");
await selectNodeAndWaitForAnimations(".keyframes-easing-step", inspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
assertLabelContent(labelEl, animationInspector.state.animations[0].state.currentTime);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.2);
assertLabelContent(labelEl, animationInspector.state.animations[0].state.currentTime);
info("Checking current time label content during running");
// Resume
await clickOnPauseResumeButton(animationInspector, panel);
const previousContent = labelEl.textContent;
await wait(1000);
const currentContent = labelEl.textContent;
isnot(previousContent, currentContent, "Current time label should change");
});
function assertLabelContent(labelEl, time) {
const expected = formatStopwatchTime(time);
is(labelEl.textContent, expected, `Content of label should be ${ expected }`);
}
function formatStopwatchTime(time) {
// Format falsy values as 0
if (!time) {
return "00:00.000";
}
let milliseconds = parseInt(time % 1000, 10);
let seconds = parseInt((time / 1000) % 60, 10);
let minutes = parseInt((time / (1000 * 60)), 10);
let pad = (nb, max) => {
if (nb < max) {
return new Array((max + "").length - (nb + "").length + 1).join("0") + nb;
}
return nb;
};
minutes = pad(minutes, 10);
seconds = pad(seconds, 10);
milliseconds = pad(milliseconds, 100);
return `${minutes}:${seconds}.${milliseconds}`;
}

View File

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following CurrentTimeScrubber and CurrentTimeScrubberController components:
// * element existence
// * scrubber position validity
// * make animations currentTime to change by click on the controller
// * mouse drag on the scrubber
add_task(async function () {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking scrubber controller existence");
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
ok(controllerEl, "scrubber controller should exist");
info("Checking scrubber existence");
const scrubberEl = controllerEl.querySelector(".current-time-scrubber");
ok(scrubberEl, "scrubber should exist");
info("Checking scrubber changes current time of animation and the position");
await selectNodeAndWaitForAnimations(".enddelay-with-iterations-infinity", inspector);
const duration = animationInspector.state.timeScale.getDuration();
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0);
assertAnimationsCurrentTime(animationInspector, 0);
assertPosition(scrubberEl, controllerEl, 0, animationInspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
assertAnimationsCurrentTime(animationInspector, duration);
assertPosition(scrubberEl, controllerEl, duration, animationInspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
assertAnimationsCurrentTime(animationInspector, duration * 0.5);
assertPosition(scrubberEl, controllerEl, duration * 0.5, animationInspector);
info("Checking current time scrubber position during running");
// Running again
await clickOnPauseResumeButton(animationInspector, panel);
let previousX = scrubberEl.getBoundingClientRect().x;
await wait(100);
let currentX = scrubberEl.getBoundingClientRect().x;
isnot(previousX, currentX, "Scrubber should be moved");
info("Checking draggable on scrubber over animation list");
await clickOnPauseResumeButton(animationInspector, panel);
previousX = scrubberEl.getBoundingClientRect().x;
await dragOnCurrentTimeScrubber(animationInspector, panel, 0.5, 2, 30);
currentX = scrubberEl.getBoundingClientRect().x;
isnot(previousX, currentX, "Scrubber should be draggable");
info("Checking a behavior which mouse out from animation inspector area " +
"during dragging from controller");
await dragOnCurrentTimeScrubberController(animationInspector, panel, 0.5, 2);
ok(!panel.querySelector(".animation-list-container")
.classList.contains("active-scrubber"), "Click and DnD should be inactive");
});
function assertPosition(scrubberEl, controllerEl, time, animationInspector) {
const controllerBounds = controllerEl.getBoundingClientRect();
const scrubberBounds = scrubberEl.getBoundingClientRect();
const scrubberX = scrubberBounds.x + scrubberBounds.width / 2 - controllerBounds.x;
const timeScale = animationInspector.state.timeScale;
const expected = Math.round(time / timeScale.getDuration() * controllerBounds.width);
is(scrubberX, expected, `Position should be ${ expected } at ${ time }ms`);
}

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following KeyframesProgressBar:
// * element existence
// * progress bar position in multi effect timings
// * progress bar position after changing playback rate
// * progress bar position when select another animation
const POSITION_TESTCASES = [
{
targetClassName: "cssanimation-linear",
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
expectedPositions: [0, 0.25, 0.5, 0.75, 0],
},
{
targetClassName: "easing-step",
scrubberPositions: [0, 0.49, 0.5, 0.99],
expectedPositions: [0, 0, 0.5, 0.5],
},
{
targetClassName: "delay-positive",
scrubberPositions: [0, 0.33, 0.5],
expectedPositions: [0, 0, 0.25],
},
{
targetClassName: "delay-negative",
scrubberPositions: [0, 0.49, 0.5, 0.75],
expectedPositions: [0, 0, 0.5, 0.75],
},
{
targetClassName: "enddelay-positive",
scrubberPositions: [0, 0.66, 0.67, 0.99],
expectedPositions: [0, 0.99, 0, 0],
},
{
targetClassName: "enddelay-negative",
scrubberPositions: [0, 0.49, 0.5, 0.99],
expectedPositions: [0, 0.49, 0, 0],
},
{
targetClassName: "direction-reverse-with-iterations-infinity",
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
expectedPositions: [1, 0.75, 0.5, 0.25, 1],
},
{
targetClassName: "fill-both-width-delay-iterationstart",
scrubberPositions: [0, 0.33, 0.66, 0.833, 1],
expectedPositions: [0.5, 0.5, 0.99, 0.25, 0.5],
},
];
add_task(async function () {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking progress bar position in multi effect timings");
await clickOnPauseResumeButton(animationInspector, panel);
for (const testcase of POSITION_TESTCASES) {
info(`Checking progress bar position for ${ testcase.targetClassName }`);
await selectNodeAndWaitForAnimations(`.${ testcase.targetClassName }`, inspector);
info("Checking progress bar existence");
const areaEl = panel.querySelector(".keyframes-progress-bar-area");
ok(areaEl, "progress bar area should exist");
const barEl = areaEl.querySelector(".keyframes-progress-bar");
ok(barEl, "progress bar should exist");
const scrubberPositions = testcase.scrubberPositions;
const expectedPositions = testcase.expectedPositions;
for (let i = 0; i < scrubberPositions.length; i++) {
info(`Scrubber position is ${ scrubberPositions[i] }`);
await clickOnCurrentTimeScrubberController(animationInspector,
panel, scrubberPositions[i]);
assertPosition(barEl, areaEl, expectedPositions[i], animationInspector);
}
}
});
function assertPosition(barEl, areaEl, expectedRate, animationInspector) {
const controllerBounds = areaEl.getBoundingClientRect();
const barBounds = barEl.getBoundingClientRect();
const barX = barBounds.x + barBounds.width / 2 - controllerBounds.x;
const expected = controllerBounds.width * expectedRate;
ok(expected - 1 < barX && barX < expected + 1,
`Position should apploximately be ${ expected } (x of bar is ${ barX })`);
}

View File

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Animation inspector makes the current time to stop
// after end of animation duration except iterations infinity.
// Test followings:
// * state of animations and UI components after end of animation duration
// * state of animations and UI components after end of animation duration
// but iteration count is infinity
add_task(async function () {
await addTab(URL_ROOT + "doc_multi_timings.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking state after end of animation duration");
await selectNodeAndWaitForAnimations(".easing-step", inspector);
const pixelsData = getDurationAndRate(animationInspector, panel, 5);
await clickOnCurrentTimeScrubberController(animationInspector,
panel, 1 - pixelsData.rate);
await clickOnPauseResumeButton(animationInspector, panel);
// Must be able to catch rendering event after stopping the animation.
await waitForSummaryAndDetail(animationInspector);
await assertStates(animationInspector, panel, false);
info("Checking state after end of animation duration and infinity iterations");
await clickOnPauseResumeButton(animationInspector, panel);
await selectNodeAndWaitForAnimations(".enddelay-with-iterations-infinity", inspector);
await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
await clickOnPauseResumeButton(animationInspector, panel);
await assertStates(animationInspector, panel, true);
});
async function assertStates(animationInspector, panel, shouldRunning) {
const buttonEl = panel.querySelector(".pause-resume-button");
const labelEl = panel.querySelector(".current-time-label");
const scrubberEl = panel.querySelector(".current-time-scrubber");
const previousLabelContent = labelEl.textContent;
const previousScrubberX = scrubberEl.getBoundingClientRect().x;
await wait(100);
const currentLabelContent = labelEl.textContent;
const currentScrubberX = scrubberEl.getBoundingClientRect().x;
if (shouldRunning) {
isnot(previousLabelContent, currentLabelContent,
"Current time label content should change");
isnot(previousScrubberX, currentScrubberX,
"Current time scrubber position should change");
ok(!buttonEl.classList.contains("paused"),
"State of button should be running");
assertAnimationsRunning(animationInspector, panel);
} else {
is(previousLabelContent, currentLabelContent,
"Current time label Content should not change");
is(previousScrubberX, currentScrubberX,
"Current time scrubber position should not change");
ok(buttonEl.classList.contains("paused"),
"State of button should be paused");
assertAnimationsPausing(animationInspector, panel);
}
}

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PauseResumeButton component:
// * element existence
// * state during running animations
// * state during pausing animations
// * make animations to pause by push button
// * make animations to resume by push button
add_task(async function () {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking pause/resume button existence");
const buttonEl = panel.querySelector(".pause-resume-button");
ok(buttonEl, "pause/resume button should exist");
info("Checking state during running animations");
ok(!buttonEl.classList.contains("paused"), "State of button should be running");
info("Checking button makes animations to pause");
await clickOnPauseResumeButton(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
ok(buttonEl.classList.contains("paused"), "State of button should be paused");
info("Checking button makes animations to resume");
await clickOnPauseResumeButton(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
ok(!buttonEl.classList.contains("paused"), "State of button should be resumed");
});

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PauseResumeButton component with spacebar:
// * make animations to pause/resume by spacebar
// * combination with other UI components
add_task(async function () {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking spacebar makes animations to pause");
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
info("Checking spacebar works with other UI components");
// To pause
await clickOnPauseResumeButton(animationInspector, panel);
// To resume
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsRunning(animationInspector, panel);
// To pause
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
// To resume
await clickOnPauseResumeButton(animationInspector, panel);
// To pause
await sendSpaceKeyEvent(animationInspector, panel);
assertAnimationsPausing(animationInspector, panel);
});

View File

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following PlaybackRateSelector component:
// * element existence
// * make playback rate of animations by the selector
// * in case of animations have mixed playback rate
// * in case of animations have playback rate which is not default selectable value
add_task(async function () {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, inspector, panel } = await openAnimationInspector();
info("Checking playback rate selector existence");
const selectEl = panel.querySelector(".playback-rate-selector");
ok(selectEl, "scrubber controller should exist");
info("Checking playback rate existence which includes custom rate of animations");
const selectableRates = [0.1, 0.25, 0.5, 1, 1.5, 2, 5, 10];
is(selectEl.options.length, selectableRates.length,
`Length of options should be ${ selectableRates.length }`);
for (let i = 0; i < selectEl.options.length; i++) {
const optionEl = selectEl.options[i];
const selectableRate = selectableRates[i];
is(Number(optionEl.value), selectableRate,
`Option of index[${ i }] should be ${ selectableRate }`);
}
info("Checking selected playback rate");
is(Number(selectEl.value), 1.5, "Selected option should be 1.5");
info("Checking playback rate of animations");
await clickOnPlaybackRateSelector(animationInspector, panel, 0.5);
assertPlaybackRate(animationInspector, 0.5);
info("Checking mixed playback rate");
await selectNodeAndWaitForAnimations("div", inspector);
await clickOnPlaybackRateSelector(animationInspector, panel, 2);
assertPlaybackRate(animationInspector, 2);
await selectNodeAndWaitForAnimations("body", inspector);
is(selectEl.value, "", "Selected option should be empty");
info("Checking playback rate after re-setting");
await clickOnPlaybackRateSelector(animationInspector, panel, 1);
assertPlaybackRate(animationInspector, 1);
});
async function assertPlaybackRate(animationInspector, rate) {
const isRateEqual =
animationInspector.state.animations.every(({state}) => state.playbackRate === rate);
ok(isRateEqual, `Playback rate of animations should be ${ rate }`);
}

View File

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test for following RewindButton component:
// * element existence
// * make animations to rewind to zero
// * the state should be always paused after rewinding
add_task(async function () {
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
const { animationInspector, panel } = await openAnimationInspector();
info("Checking button existence");
ok(panel.querySelector(".rewind-button"), "Rewind button should exist");
info("Checking rewind button makes animations to rewind to zero");
await clickOnRewindButton(animationInspector, panel);
assertAnimationsCurrentTime(animationInspector, 0);
assertAnimationsPausing(animationInspector, panel);
info("Checking rewind button makes animations after clicking scrubber");
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
await clickOnRewindButton(animationInspector, panel);
assertAnimationsCurrentTime(animationInspector, 0);
assertAnimationsPausing(animationInspector, panel);
});

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
div {
background-color: lime;
height: 100px;
}
</style>
</head>
<body>
<script>
"use strict";
const duration = 100000;
function createAnimation() {
const div = document.createElement("div");
document.body.appendChild(div);
const animation = div.animate([{ opacity: 0 }], duration);
animation.playbackRate = 1.5;
}
createAnimation();
createAnimation();
</script>
</body>
</html>

View File

@ -121,6 +121,178 @@ const clickOnDetailCloseButton = function (panel) {
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
};
/**
* Click on pause/resume button.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* The panel instance.
*/
const clickOnPauseResumeButton = async function (animationInspector, panel) {
info("Click on pause/resume button");
const buttonEl = panel.querySelector(".pause-resume-button");
const bounds = buttonEl.getBoundingClientRect();
const x = bounds.width / 2;
const y = bounds.height / 2;
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on rewind button.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* The panel instance.
*/
const clickOnRewindButton = async function (animationInspector, panel) {
info("Click on rewind button");
const buttonEl = panel.querySelector(".rewind-button");
const bounds = buttonEl.getBoundingClientRect();
const x = bounds.width / 2;
const y = bounds.height / 2;
EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on the scrubber controller pane to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
*/
const clickOnCurrentTimeScrubberController = async function (animationInspector,
panel,
mouseDownPosition,
mouseMovePosition) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
info(`Click ${ mousedonwX } on scrubber controller`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, 0, {}, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Click on playback rate selector to select given rate.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} rate
*/
const clickOnPlaybackRateSelector = async function (animationInspector, panel, rate) {
info(`Click on playback rate selector to select ${rate}`);
const selectEl = panel.querySelector(".playback-rate-selector");
const optionEl = [...selectEl.options].filter(o => Number(o.value) === rate)[0];
if (!optionEl) {
ok(false, `Could not find an option for rate ${ rate } in the rate selector. ` +
`Values are: ${ [...selectEl.options].map(o => o.value) }`);
return;
}
const win = selectEl.ownerGlobal;
EventUtils.synthesizeMouseAtCenter(selectEl, { type: "mousedown" }, win);
EventUtils.synthesizeMouseAtCenter(optionEl, { type: "mouseup" }, win);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Drag on the scrubber to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
* @param {Number} mouseMovePosition
* Dispatch mousemove event with mouseMovePosition after mousedown.
* Calculation for clinetX is same to above.
* @param {Number} mouseYPixel
* Y of mouse in pixel.
*/
const dragOnCurrentTimeScrubber = async function (animationInspector,
panel,
mouseDownPosition,
mouseMovePosition,
mouseYPixel) {
const controllerEl = panel.querySelector(".current-time-scrubber");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
const mousemoveX = bounds.width * mouseMovePosition;
info(`Drag on scrubber from ${ mousedonwX } to ${ mousemoveX }`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, mouseYPixel,
{ type: "mousedown" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, mouseYPixel,
{ type: "mousemove" }, controllerEl.ownerGlobal);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, mouseYPixel,
{ type: "mouseup" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Drag on the scrubber controller pane to update the animation current time.
*
* @param {AnimationsPanel} panel
* @param {Number} mouseDownPosition
* rate on scrubber controller pane.
* This method calculates
* `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
* as the clientX of MouseEvent.
* @param {Number} mouseMovePosition
* Dispatch mousemove event with mouseMovePosition after mousedown.
* Calculation for clinetX is same to above.
*/
const dragOnCurrentTimeScrubberController = async function (animationInspector,
panel,
mouseDownPosition,
mouseMovePosition) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const mousedonwX = bounds.width * mouseDownPosition;
const mousemoveX = bounds.width * mouseMovePosition;
info(`Drag on scrubber controller from ${ mousedonwX } to ${ mousemoveX }`);
EventUtils.synthesizeMouse(controllerEl, mousedonwX, 0,
{ type: "mousedown" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, 0,
{ type: "mousemove" }, controllerEl.ownerGlobal);
EventUtils.synthesizeMouse(controllerEl, mousemoveX, 0,
{ type: "mouseup" }, controllerEl.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Get current animation duration and rate of
* clickOrDragOnCurrentTimeScrubberController in given pixels.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} pixels
* @return {Object}
* {
* duration,
* rate,
* }
*/
const getDurationAndRate = function (animationInspector, panel, pixels) {
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
const bounds = controllerEl.getBoundingClientRect();
const duration =
animationInspector.state.timeScale.getDuration() / bounds.width * pixels;
const rate = 1 / bounds.width * pixels;
return { duration, rate };
};
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector and wait for the animations to be displayed
@ -144,6 +316,18 @@ const selectNodeAndWaitForAnimations = async function (data, inspector, reason =
await waitForRendering(inspector.animationinspector);
};
/**
* Send keyboard event of space to given panel.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
const sendSpaceKeyEvent = async function (animationInspector, panel) {
panel.focus();
EventUtils.sendKey("SPACE", panel.ownerGlobal);
await waitForSummaryAndDetail(animationInspector);
};
/**
* Set the sidebar width by given parameter.
*
@ -178,7 +362,8 @@ const waitForRendering = async function (animationInspector) {
* @param {AnimationInspector} inspector
*/
const waitForAnimationDetail = async function (animationInspector) {
if (animationInspector.state.animations.length === 1) {
if (animationInspector.state.selectedAnimation &&
animationInspector.state.detailVisibility) {
await animationInspector.once("animation-keyframes-rendered");
}
};
@ -206,6 +391,69 @@ const waitForAllSummaryGraph = async function (animationInspector) {
}
};
/**
* Wait for rendering of all summary graph and detail.
*
* @param {AnimationInspector} inspector
*/
const waitForSummaryAndDetail = async function (animationInspector) {
await Promise.all([
waitForAllSummaryGraph(animationInspector),
waitForAnimationDetail(animationInspector),
]);
};
/**
* Check whether current time of all animations and UI are given specified time.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {Number} time
*/
function assertAnimationsCurrentTime(animationInspector, time) {
const isTimeEqual =
animationInspector.state.animations.every(({state}) => state.currentTime === time);
ok(isTimeEqual, `Current time of animations should be ${ time }`);
}
/**
* Check whether the animations are pausing.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
function assertAnimationsPausing(animationInspector, panel) {
assertAnimationsPausingOrRunning(animationInspector, panel, true);
}
/**
* Check whether the animations are pausing/running.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
* @param {boolean} shouldPause
*/
function assertAnimationsPausingOrRunning(animationInspector, panel, shouldPause) {
const hasRunningAnimation =
animationInspector.state.animations.some(({state}) => state.playState === "running");
if (shouldPause) {
is(hasRunningAnimation, false, "All animations should be paused");
} else {
is(hasRunningAnimation, true, "Animations should be running at least one");
}
}
/**
* Check whether the animations are running.
*
* @param {AnimationInspector} animationInspector
* @param {AnimationsPanel} panel
*/
function assertAnimationsRunning(animationInspector, panel) {
assertAnimationsPausingOrRunning(animationInspector, panel, false);
}
/**
* Check the <stop> element in the given linearGradientEl for the correct offset
* and color attributes.