Bug 1404801 - Part 6: Add mochitests. r?gl,pbro
MozReview-Commit-ID: 6iskCXC4Fa8
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -59,26 +59,30 @@ class AnimationInspector {
}
async update() {
if (!this.inspector || !this.isPanelVisible()) {
// AnimationInspector was destroyed already or the panel is hidden.
return;
}
+ const done = this.inspector.updating("newanimationinspector");
+
const selection = this.inspector.selection;
const animations =
selection.isConnected() && selection.isElementNode()
? await this.animationsFront.getAnimationPlayersForNode(selection.nodeFront)
: [];
if (!this.animations || !isAllTimingEffectEqual(animations, this.animations)) {
this.inspector.store.dispatch(updateAnimations(animations));
this.animations = animations;
}
+
+ done();
}
isPanelVisible() {
return this.inspector && this.inspector.toolbox && this.inspector.sidebar &&
this.inspector.toolbox.currentToolId === "inspector" &&
this.inspector.sidebar.getCurrentTabID() === "newanimationinspector";
}
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -1,12 +1,15 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
+ doc_simple_animation.html
head.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/test-actor-registry.js
!/devtools/client/shared/test/test-actor.js
-[browser_animation_inspector_exists.js]
\ No newline at end of file
+[browser_animation_animation_list_exists.js]
+[browser_animation_empty_on_invalid_nodes.js]
+[browser_animation_inspector_exists.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation_list_exists.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Test that whether animations ui could be displayed
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_simple_animation.html");
+
+ const { animationInspector, inspector, panel } = await openAnimationInspector();
+
+ info("Checking animation list and items existence");
+ ok(panel.querySelector(".animation-list"),
+ "The animation-list is in the DOM");
+ is(panel.querySelectorAll(".animation-list .animation-item").length,
+ animationInspector.animations.length,
+ "The number of animations displayed matches the number of animations");
+
+ info("Checking the background color for the animation list items");
+ const animationItemEls = panel.querySelectorAll(".animation-list .animation-item");
+ const evenColor =
+ panel.ownerGlobal.getComputedStyle(animationItemEls[0]).backgroundColor;
+ const oddColor =
+ panel.ownerGlobal.getComputedStyle(animationItemEls[1]).backgroundColor;
+ isnot(evenColor, oddColor,
+ "Background color of an even animation should be different from odd");
+
+ info("Checking list and items existence after select a element which has an animation");
+ const animatedNode = await getNodeFront(".animated", inspector);
+ await selectNodeAndWaitForAnimations(animatedNode, inspector);
+ is(panel.querySelectorAll(".animation-list .animation-item").length, 1,
+ "The number of animations displayed should be 1 for .animated element");
+
+ // TODO: We need to add following tests after implement since this test has same role
+ // of animationinspector/test/browser_animation_timeline_ui.js
+ // * header existance.
+ // * name label in animation element existance.
+ // * target node in animation element existance.
+ // * summary graph in animation element existance.
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_empty_on_invalid_nodes.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+requestLongerTimeout(2);
+
+// Test that the panel shows no animation data for invalid or not animated nodes
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_simple_animation.html");
+
+ const { inspector, panel } = await openAnimationInspector();
+
+ info("Checking animation list and error message existence for a still node");
+ const stillNode = await getNodeFront(".still", inspector);
+ await selectNodeAndWaitForAnimations(stillNode, inspector);
+
+ ok(panel.querySelector(".animation-error-message"),
+ "Element which has animation-error-message class should exist for a still node");
+ is(panel.querySelector(".animation-error-message > p").textContent,
+ ANIMATION_L10N.getStr("panel.noAnimation"),
+ "The correct error message is displayed");
+ ok(!panel.querySelector(".animation-list"),
+ "Element which has animations class should not exist for a still node");
+
+ info("Checking animation list and error message existence for a text node");
+ const commentNode = await inspector.walker.previousSibling(stillNode);
+ await selectNodeAndWaitForAnimations(commentNode, inspector);
+
+ ok(panel.querySelector(".animation-error-message"),
+ "Element which has animation-error-message class should exist for a text node");
+ ok(!panel.querySelector(".animation-list"),
+ "Element which has animations class should not exist for a text node");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/doc_simple_animation.html
@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <style>
+ .ball {
+ width: 80px;
+ height: 80px;
+ /* Add a border here to avoid layout warnings in Linux debug builds: Bug 1329784 */
+ border: 1px solid transparent;
+ border-radius: 50%;
+ background: #f06;
+
+ position: absolute;
+ }
+
+ .still {
+ top: 0;
+ left: 10px;
+ }
+
+ .animated {
+ top: 100px;
+ left: 10px;
+
+ animation: simple-animation 2s infinite alternate;
+ }
+
+ .multi {
+ top: 200px;
+ left: 10px;
+
+ animation: simple-animation 2s infinite alternate,
+ other-animation 5s infinite alternate;
+ }
+
+ .delayed {
+ top: 300px;
+ left: 10px;
+ background: rebeccapurple;
+
+ animation: simple-animation 3s 60s 10;
+ }
+
+ .multi-finite {
+ top: 400px;
+ left: 10px;
+ background: yellow;
+
+ animation: simple-animation 3s,
+ other-animation 4s;
+ }
+
+ .short {
+ top: 500px;
+ left: 10px;
+ background: red;
+
+ animation: simple-animation 2s normal;
+ }
+
+ .long {
+ top: 600px;
+ left: 10px;
+ background: blue;
+
+ animation: simple-animation 120s;
+ }
+
+ .negative-delay {
+ top: 700px;
+ left: 10px;
+ background: gray;
+
+ animation: simple-animation 15s -10s;
+ animation-fill-mode: forwards;
+ }
+
+ .no-compositor {
+ top: 0;
+ right: 10px;
+ background: gold;
+
+ animation: no-compositor 10s cubic-bezier(.57,-0.02,1,.31) forwards;
+ }
+
+ .compositor-all {
+ animation: compositor-all 2s infinite;
+ }
+
+ .compositor-notall {
+ animation: compositor-notall 2s infinite;
+ }
+
+ @keyframes simple-animation {
+ 100% {
+ transform: translateX(300px);
+ }
+ }
+
+ @keyframes other-animation {
+ 100% {
+ background: blue;
+ }
+ }
+
+ @keyframes no-compositor {
+ 100% {
+ margin-right: 600px;
+ }
+ }
+
+ @keyframes compositor-all {
+ to { opacity: 0.5 }
+ }
+
+ @keyframes compositor-notall {
+ from {
+ opacity: 0;
+ width: 0px;
+ transform: translate(0px);
+ }
+ to {
+ opacity: 1;
+ width: 100px;
+ transform: translate(100px);
+ }
+ }
+ </style>
+</head>
+<body>
+ <!-- Comment node -->
+ <div class="ball still"></div>
+ <div class="ball animated"></div>
+ <div class="ball multi"></div>
+ <div class="ball delayed"></div>
+ <div class="ball multi-finite"></div>
+ <div class="ball short"></div>
+ <div class="ball long"></div>
+ <div class="ball negative-delay"></div>
+ <div class="ball no-compositor"></div>
+ <div class="ball" id="endDelayed"></div>
+ <div class="ball compositor-all"></div>
+ <div class="ball compositor-notall"></div>
+ <script>
+ /* globals KeyframeEffect, Animation */
+ "use strict";
+
+ var el = document.getElementById("endDelayed");
+ let effect = new KeyframeEffect(el, [
+ { opacity: 0, offset: 0 },
+ { opacity: 1, offset: 1 }
+ ], { duration: 1000000, endDelay: 500000, fill: "none" });
+ let animation = new Animation(effect, document.timeline);
+ animation.play();
+ </script>
+</body>
+</html>
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -4,18 +4,23 @@
"use strict";
/* import-globals-from ../../test/head.js */
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js", this);
+const COMMON_FRAME_SCRIPT_URL = "chrome://devtools/content/shared/frame-script-utils.js";
+const FRAME_SCRIPT_URL = CHROME_URL_ROOT + "doc_frame_script.js";
const TAB_NAME = "newanimationinspector";
+const ANIMATION_L10N =
+ new LocalizationHelper("devtools/client/locales/animationinspector.properties");
+
// Enable new animation inspector.
Services.prefs.setBoolPref("devtools.new-animationinspector.enabled", true);
// Auto clean-up when a test ends.
// Clean-up all prefs that might have been changed during a test run
// (safer here because if the test fails, then the pref is never reverted)
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.new-animationinspector.enabled");
@@ -24,22 +29,78 @@ registerCleanupFunction(() => {
/**
* Open the toolbox, with the inspector tool visible and the animationinspector
* sidebar selected.
*
* @return {Promise} that resolves when the inspector is ready.
*/
const openAnimationInspector = async function () {
const { inspector, toolbox } = await openInspectorSidebarTab(TAB_NAME);
+ await inspector.once("inspector-updated");
const { animationinspector: animationInspector } = inspector;
const panel = inspector.panelWin.document.getElementById("animation-container");
- return { toolbox, inspector, animationInspector, panel };
+ return { animationInspector, toolbox, inspector, panel };
};
/**
* Close the toolbox.
*
* @return {Promise} that resolves when the toolbox has closed.
*/
const closeAnimationInspector = async function () {
const target = TargetFactory.forTab(gBrowser.selectedTab);
return gDevTools.closeToolbox(target);
};
+
+/**
+ * Some animation features are not enabled by default in release/beta channels
+ * yet including:
+ * * parts of the Web Animations API (Bug 1264101), and
+ * * the frames() timing function (Bug 1379582).
+ */
+const enableAnimationFeatures = function () {
+ return new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.animations-api.core.enabled", true],
+ ["layout.css.frames-timing.enabled", true],
+ ]}, resolve);
+ });
+};
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ *
+ * @param {String} url The url to be loaded in the new tab
+ * @return a promise that resolves to the tab object when the url is loaded
+ */
+const _addTab = addTab;
+addTab = async function (url) {
+ await enableAnimationFeatures();
+ const tab = await _addTab(url);
+ const browser = tab.linkedBrowser;
+ info("Loading the helper frame script " + FRAME_SCRIPT_URL);
+ browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
+ info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
+ browser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
+ return tab;
+};
+
+/**
+ * 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
+ *
+ * @param {String|NodeFront}
+ * data The node to select
+ * @param {InspectorPanel} inspector
+ * The instance of InspectorPanel currently loaded in the toolbox
+ * @param {String} reason
+ * Defaults to "test" which instructs the inspector not
+ * to highlight the node upon selection
+ * @return {Promise} Resolves when the inspector is updated with the new node
+ * and animations of its subtree are properly displayed.
+ */
+const selectNodeAndWaitForAnimations = async function (data, inspector, reason = "test") {
+ // We want to make sure the rest of the test waits for the animations to
+ // be properly displayed (wait for all target DOM nodes to be previewed).
+ const onUpdated = inspector.once("inspector-updated");
+ await selectNode(data, inspector, reason);
+ await onUpdated;
+};