Bug 1416104 - Part 10: Add tests. r?gl
MozReview-Commit-ID: cqjceHqcYt
--- a/devtools/client/inspector/animation/components/AnimatedPropertyList.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyList.js
@@ -9,16 +9,17 @@ const dom = require("devtools/client/sha
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const AnimatedPropertyItem = createFactory(require("./AnimatedPropertyItem"));
class AnimatedPropertyList extends PureComponent {
static get propTypes() {
return {
animation: PropTypes.object.isRequired,
+ emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.state = {
@@ -30,20 +31,25 @@ class AnimatedPropertyList extends PureC
this.updateKeyframesList(this.props.animation);
}
componentWillReceiveProps(nextProps) {
this.updateKeyframesList(nextProps.animation);
}
async updateKeyframesList(animation) {
- const { getAnimatedPropertyMap } = this.props;
+ const {
+ getAnimatedPropertyMap,
+ emitEventForTest,
+ } = this.props;
const animatedPropertyMap = await getAnimatedPropertyMap(animation);
this.setState({ animatedPropertyMap });
+
+ emitEventForTest("animation-keyframes-rendered");
}
render() {
const { animatedPropertyMap } = this.state;
if (!animatedPropertyMap) {
return null;
}
--- a/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
@@ -10,34 +10,37 @@ const PropTypes = require("devtools/clie
const AnimatedPropertyList = createFactory(require("./AnimatedPropertyList"));
const AnimatedPropertyListHeader = createFactory(require("./AnimatedPropertyListHeader"));
class AnimatedPropertyListContainer extends PureComponent {
static get propTypes() {
return {
animation: PropTypes.object.isRequired,
+ emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired,
};
}
render() {
const {
animation,
+ emitEventForTest,
getAnimatedPropertyMap,
} = this.props;
return dom.div(
{
className: "animated-property-list-container"
},
AnimatedPropertyListHeader(),
AnimatedPropertyList(
{
animation,
+ emitEventForTest,
getAnimatedPropertyMap,
}
)
);
}
}
module.exports = AnimatedPropertyListContainer;
--- a/devtools/client/inspector/animation/components/AnimationDetailContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationDetailContainer.js
@@ -12,24 +12,26 @@ const PropTypes = require("devtools/clie
const AnimationDetailHeader = createFactory(require("./AnimationDetailHeader"));
const AnimatedPropertyListContainer =
createFactory(require("./AnimatedPropertyListContainer"));
class AnimationDetailContainer extends PureComponent {
static get propTypes() {
return {
animation: PropTypes.object.isRequired,
+ emitEventForTest: PropTypes.func.isRequired,
getAnimatedPropertyMap: PropTypes.func.isRequired,
setDetailVisibility: PropTypes.func.isRequired,
};
}
render() {
const {
animation,
+ emitEventForTest,
getAnimatedPropertyMap,
setDetailVisibility,
} = this.props;
return dom.div(
{
className: "animation-detail-container"
},
@@ -41,16 +43,17 @@ class AnimationDetailContainer extends P
}
)
:
null,
animation ?
AnimatedPropertyListContainer(
{
animation,
+ emitEventForTest,
getAnimatedPropertyMap,
}
)
:
null
);
}
}
--- a/devtools/client/inspector/animation/components/App.js
+++ b/devtools/client/inspector/animation/components/App.js
@@ -57,16 +57,17 @@ class App extends PureComponent {
id: "animation-container",
className: detailVisibility ? "animation-detail-visible" : "",
},
animations.length ?
SplitBox({
className: "animation-container-splitter",
endPanel: AnimationDetailContainer(
{
+ emitEventForTest,
getAnimatedPropertyMap,
setDetailVisibility,
}
),
endPanelControl: true,
initialHeight: "50%",
splitterSize: 1,
startPanel: AnimationListContainer(
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -6,16 +6,20 @@ 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_animated-property-list.js]
+[browser_animation_animation-detail_close-button.js]
+[browser_animation_animation-detail_title.js]
+[browser_animation_animation-detail_visibility.js]
[browser_animation_animation-list.js]
[browser_animation_animation-target.js]
[browser_animation_animation-timeline-tick.js]
[browser_animation_empty_on_invalid_nodes.js]
[browser_animation_inspector_exists.js]
[browser_animation_summary-graph_animation-name.js]
[browser_animation_summary-graph_compositor.js]
[browser_animation_summary-graph_computed-timing-path.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animated-property-list.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test following animated property list test.
+// 1. Existence for animated property list.
+// 2. Number of animated property item.
+
+const TEST_CASES = [
+ {
+ target: ".animated",
+ expectedNumber: 1,
+ },
+ {
+ target: ".compositor-notall",
+ expectedNumber: 3,
+ },
+];
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_simple_animation.html");
+ const { inspector, panel } = await openAnimationInspector();
+
+ info("Checking animated property list and items existence at initial");
+ ok(!panel.querySelector(".animated-property-list"),
+ "The animated-property-list should not be in the DOM at initial");
+
+ for (const testCase of TEST_CASES) {
+ info(`Checking animated-property-list and items existence at ${ testCase.target }`);
+ const animatedNode = await getNodeFront(testCase.target, inspector);
+ await selectNodeAndWaitForAnimations(animatedNode, inspector);
+ ok(panel.querySelector(".animated-property-list"),
+ `The animated-property-list should be in the DOM at ${ testCase.target }`);
+ const itemEls =
+ panel.querySelectorAll(".animated-property-list .animated-property-item");
+ is(itemEls.length, testCase.expectedNumber,
+ `The number of animated-property-list should be ${ testCase.expectedNumber } `
+ + `at ${ testCase.target }`);
+
+ if (itemEls.length < 2) {
+ continue;
+ }
+
+ info(`Checking the background color for `
+ + `the animated property item at ${ testCase.target }`);
+ const evenColor = panel.ownerGlobal.getComputedStyle(itemEls[0]).backgroundColor;
+ const oddColor = panel.ownerGlobal.getComputedStyle(itemEls[1]).backgroundColor;
+ isnot(evenColor, oddColor,
+ "Background color of an even animated property item "
+ + "should be different from odd");
+ }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-detail_close-button.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that whether close button in header of animation detail works.
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_multi_timings.html");
+ const { animationInspector, panel } = await openAnimationInspector();
+
+ info("Checking close button in header of animation detail");
+ await clickOnAnimation(animationInspector, panel, 0);
+ const detailEl = panel.querySelector("#animation-container .controlled");
+ const win = panel.ownerGlobal;
+ isnot(win.getComputedStyle(detailEl).display, "none",
+ "detailEl should be visibled before clicking close button");
+ clickOnDetailCloseButton(panel);
+ is(win.getComputedStyle(detailEl).display, "none",
+ "detailEl should be unvisibled after clicking close button");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-detail_title.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that whether title in header of animations detail.
+
+const TEST_CASES = [
+ {
+ target: ".cssanimation-normal",
+ expectedTitle: "cssanimation - CSS Animation",
+ },
+ {
+ target: ".delay-positive",
+ expectedTitle: "test-delay-animation - Script Animation",
+ },
+ {
+ target: ".easing-step",
+ expectedTitle: "Script Animation",
+ },
+];
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_multi_timings.html");
+ const { inspector, panel } = await openAnimationInspector();
+
+ info("Checking title in each header of animation detail");
+
+ for (const testCase of TEST_CASES) {
+ info(`Checking title at ${ testCase.target }`);
+ const animatedNode = await getNodeFront(testCase.target, inspector);
+ await selectNodeAndWaitForAnimations(animatedNode, inspector);
+ const titleEl = panel.querySelector(".animation-detail-title");
+ is(titleEl.textContent, testCase.expectedTitle,
+ `Title of "${ testCase.target }" should be "${ testCase.expectedTitle }"`);
+ }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-detail_visibility.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that whether animations detail could be displayed if there is selected animation.
+
+add_task(async function () {
+ await addTab(URL_ROOT + "doc_multi_timings.html");
+ const { animationInspector, inspector, panel } = await openAnimationInspector();
+
+ info("Checking animation detail visibility if animation was unselected");
+ const detailEl = panel.querySelector("#animation-container .controlled");
+ ok(detailEl, "The detail pane should be in the DOM");
+ const win = panel.ownerGlobal;
+ is(win.getComputedStyle(detailEl).display, "none", "detailEl should be unvisibled");
+
+ info("Checking animation detail visibility if animation was selected by click");
+ await clickOnAnimation(animationInspector, panel, 0);
+ isnot(win.getComputedStyle(detailEl).display, "none", "detailEl should be visibled");
+
+ info("Checking animation detail visibility when choose node which has animations");
+ const htmlNode = await getNodeFront("html", inspector);
+ await selectNodeAndWaitForAnimations(htmlNode, inspector);
+ is(win.getComputedStyle(detailEl).display, "none",
+ "detailEl should be unvisibled after choose html node");
+
+ info("Checking animation detail visibility when choose node which has an animation");
+ const animatedNode = await getNodeFront(".cssanimation-normal", inspector);
+ await selectNodeAndWaitForAnimations(animatedNode, inspector);
+ isnot(win.getComputedStyle(detailEl).display, "none",
+ "detailEl should be visibled after choose .cssanimation-normal node");
+});
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -65,32 +65,70 @@ const enableAnimationFeatures = function
["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
+ * @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;
};
/**
+ * Click on an animation in the timeline to select it.
+ *
+ * @param {AnimationInspector} animationInspector.
+ * @param {AnimationsPanel} panel
+ * The panel instance.
+ * @param {Number} index
+ * The index of the animation to click on.
+ */
+const clickOnAnimation = async function (animationInspector, panel, index) {
+ info("Click on animation " + index + " in the timeline");
+ const summaryGraphEl = panel.querySelectorAll(".animation-summary-graph")[index];
+ // Scroll to show the timeBlock since the element may be out of displayed area.
+ summaryGraphEl.scrollIntoView(false);
+ const bounds = summaryGraphEl.getBoundingClientRect();
+ const x = bounds.width / 2;
+ const y = bounds.height / 2;
+ EventUtils.synthesizeMouse(summaryGraphEl, x, y, {}, summaryGraphEl.ownerGlobal);
+
+ await waitForAnimationDetail(animationInspector);
+};
+
+/**
+ * Click on close button for animation detail pane.
+ *
+ * @param {AnimationsPanel} panel
+ * The panel instance.
+ */
+const clickOnDetailCloseButton = function (panel) {
+ info("Click on close button for animation detail pane");
+ const buttonEl = panel.querySelector(".animation-detail-close-button");
+ const bounds = buttonEl.getBoundingClientRect();
+ const x = bounds.width / 2;
+ const y = bounds.height / 2;
+ EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
+};
+
+/**
* 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
@@ -127,20 +165,32 @@ const setSidebarWidth = async function (
* Wait for rendering.
*
* @param {AnimationInspector} animationInspector
*/
const waitForRendering = async function (animationInspector) {
await Promise.all([
waitForAllAnimationTargets(animationInspector),
waitForAllSummaryGraph(animationInspector),
+ waitForAnimationDetail(animationInspector),
]);
};
/**
+ * Wait for rendering of animation keyframes.
+ *
+ * @param {AnimationInspector} inspector
+ */
+const waitForAnimationDetail = async function (animationInspector) {
+ if (animationInspector.animations.length === 1) {
+ await animationInspector.once("animation-keyframes-rendered");
+ }
+};
+
+/**
* Wait for all AnimationTarget components to be fully loaded
* (fetched their related actor and rendered).
*
* @param {AnimationInspector} animationInspector
*/
const waitForAllAnimationTargets = async function (animationInspector) {
for (let i = 0; i < animationInspector.animations.length; i++) {
await animationInspector.once("animation-target-rendered");