Bug 1366989 - Part 2: Modify tests to correspond with changing the animation-timeline. r?pbro draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Tue, 19 Sep 2017 10:29:22 +0900
changeset 666620 631dcebc00a1f12db0638913c9d163a98f4cc4e0
parent 666619 97abed338415ce3209290230c0417d5f1780557d
child 666621 b6df9659ec1b9ec71440486dcc827aace7510dcb
push id80475
push userbmo:dakatsuka@mozilla.com
push dateTue, 19 Sep 2017 02:05:07 +0000
reviewerspbro
bugs1366989
milestone57.0a1
Bug 1366989 - Part 2: Modify tests to correspond with changing the animation-timeline. r?pbro MozReview-Commit-ID: GN5oS5KRfrc
devtools/client/animationinspector/test/browser_animation_animated_properties_path.js
devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
devtools/client/animationinspector/test/browser_animation_pseudo_elements.js
devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js
devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js
devtools/client/animationinspector/test/browser_animation_refresh_when_active.js
devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js
devtools/client/animationinspector/test/browser_animation_summarygraph_for_multiple_easings.js
devtools/client/animationinspector/test/browser_animation_target_highlight_select.js
devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js
devtools/client/animationinspector/test/browser_animation_timeline_pause_button_03.js
devtools/client/animationinspector/test/browser_animation_timeline_setCurrentTime.js
devtools/client/animationinspector/test/browser_animation_timeline_short_duration.js
devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js
devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js
devtools/client/animationinspector/test/head.js
--- a/devtools/client/animationinspector/test/browser_animation_animated_properties_path.js
+++ b/devtools/client/animationinspector/test/browser_animation_animated_properties_path.js
@@ -308,17 +308,17 @@ add_task(function* () {
   const {panel} = yield openAnimationInspector();
   const timelineComponent = panel.animationsTimelineComponent;
   const detailEl = timelineComponent.details.containerEl;
   const hasClosePath = true;
 
   for (let i = 0; i < TEST_CASES.length; i++) {
     info(`Click to select the animation[${ i }]`);
     yield clickOnAnimation(panel, i);
-    const timeBlock = timelineComponent.timeBlocks[0];
+    const timeBlock = getAnimationTimeBlocks(panel)[0];
     const state = timeBlock.animation.state;
     const properties = TEST_CASES[i];
     for (let property in properties) {
       const testcase = properties[property];
       info(`Test path of ${ property }`);
       const className = testcase.expectedClass;
       const pathEl = detailEl.querySelector(`path.${ className }`);
       ok(pathEl, `Path element with class '${ className }' should exis`);
--- a/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
@@ -28,17 +28,20 @@ function checkDocumentTimeIsCorrect(cont
   }
   is(controller.documentCurrentTime, time,
      "The documentCurrentTime is correct");
 }
 
 function* startNewAnimation(controller, panel) {
   info("Add a new animation to the page and check the time again");
   let onPlayerAdded = controller.once(controller.PLAYERS_UPDATED_EVENT);
+  let onRendered = waitForAnimationTimelineRendering(panel);
+
   yield executeInContent("devtools:test:setAttribute", {
     selector: ".still",
     attributeName: "class",
     attributeValue: "ball still short"
   });
+
   yield onPlayerAdded;
-  yield waitForAnimationTimelineRendering(panel);
+  yield onRendered;
   yield waitForAllAnimationTargets(panel);
 }
--- a/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
+++ b/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
@@ -9,33 +9,29 @@ requestLongerTimeout(2);
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel, window} = yield openAnimationInspector();
   let {document} = window;
 
   info("Select node .still and check that the panel is empty");
   let stillNode = yield getNodeFront(".still", inspector);
-  let onUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNodeAndWaitForAnimations(stillNode, inspector);
-  yield onUpdated;
 
   is(panel.animationsTimelineComponent.animations.length, 0,
      "No animation players stored in the timeline component for a still node");
   is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
      "No animation displayed in the timeline component for a still node");
   is(document.querySelector("#error-type").textContent,
      ANIMATION_L10N.getStr("panel.invalidElementSelected"),
      "The correct error message is displayed");
 
   info("Select the comment text node and check that the panel is empty");
   let commentNode = yield inspector.walker.previousSibling(stillNode);
-  onUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNodeAndWaitForAnimations(commentNode, inspector);
-  yield onUpdated;
 
   is(panel.animationsTimelineComponent.animations.length, 0,
      "No animation players stored in the timeline component for a text node");
   is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
      "No animation displayed in the timeline component for a text node");
   is(document.querySelector("#error-type").textContent,
      ANIMATION_L10N.getStr("panel.invalidElementSelected"),
      "The correct error message is displayed");
--- a/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
+++ b/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
@@ -9,26 +9,29 @@
 // displayed (which should be true as long as these animations apply to
 // different nodes).
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_negative_animation.html");
   const {controller, panel} = yield openAnimationInspector();
   const timeline = panel.animationsTimelineComponent;
 
-  const areTracksReady = () => timeline.animations.every(a => timeline.tracksMap.has(a));
+  const areTracksReady = () => timeline.animations.every(a => {
+    return timeline.componentsMap[a.actorID];
+  });
 
   // We need to wait for all tracks to be ready, cause this is an async part of the init
   // of the panel.
   while (controller.animationPlayers.length < 3 || !areTracksReady()) {
     yield waitForAnimationTimelineRendering(panel);
   }
+
   // Same for animation targets, they're retrieved asynchronously.
   yield waitForAllAnimationTargets(panel);
 
   is(panel.animationsTimelineComponent.animations.length, 3,
      "The timeline shows 3 animations too");
 
   // Reduce the known nodeFronts to a set to make them unique.
-  let nodeFronts = new Set(panel.animationsTimelineComponent
-                                .targetNodes.map(n => n.previewer.nodeFront));
+  let nodeFronts =
+    new Set(getAnimationTargetNodes(panel).map(n => n.previewer.nodeFront));
   is(nodeFronts.size, 3, "The animations are applied to 3 different node fronts");
 });
--- a/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
+++ b/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
@@ -10,17 +10,17 @@ requestLongerTimeout(2);
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select the simple animated node");
   yield selectNodeAndWaitForAnimations(".animated", inspector);
 
-  let targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
+  let targetNodeComponent = getAnimationTargetNodes(panel)[0];
   let {previewer} = targetNodeComponent;
 
   // Make sure to wait for the target-retrieved event if the nodeFront hasn't
   // yet been retrieved by the TargetNodeComponent.
   if (!previewer.nodeFront) {
     yield targetNodeComponent.once("target-retrieved");
   }
 
--- a/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js
+++ b/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js
@@ -4,23 +4,23 @@
 
 "use strict";
 
 // Test that animated pseudo-elements do show in the timeline.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_pseudo_elements.html");
   let {inspector, panel} = yield openAnimationInspector();
-  let timeline = panel.animationsTimelineComponent;
 
   info("With <body> selected by default check the content of the timeline");
-  is(timeline.timeBlocks.length, 3, "There are 3 animations in the timeline");
+  is(getAnimationTimeBlocks(panel).length, 3, "There are 3 animations in the timeline");
 
+  let targetNodes = getAnimationTargetNodes(panel);
   let getTargetNodeText = index => {
-    let el = timeline.targetNodes[index].previewer.previewEl;
+    let el = targetNodes[index].previewer.previewEl;
     return [...el.childNodes]
            .map(n => n.style.display === "none" ? "" : n.textContent)
            .join("");
   };
 
   is(getTargetNodeText(0), "body", "The first animated node is <body>");
   is(getTargetNodeText(1), "::before", "The second animated node is ::before");
   is(getTargetNodeText(2), "::after", "The third animated node is ::after");
@@ -30,20 +30,20 @@ add_task(function* () {
   let getBodyChildNodeFront = index => {
     return bodyContainer.elt.children[1].childNodes[index].container.node;
   };
   let beforeNode = getBodyChildNodeFront(0);
   let afterNode = getBodyChildNodeFront(1);
 
   info("Select the ::before pseudo-element in the inspector");
   yield selectNodeAndWaitForAnimations(beforeNode, inspector);
-  is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
-  is(timeline.targetNodes[0].previewer.nodeFront,
+  is(getAnimationTimeBlocks(panel).length, 1, "There is 1 animation in the timeline");
+  is(getAnimationTargetNodes(panel)[0].previewer.nodeFront,
      inspector.selection.nodeFront,
      "The right node front is displayed in the timeline");
 
   info("Select the ::after pseudo-element in the inspector");
   yield selectNodeAndWaitForAnimations(afterNode, inspector);
-  is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
-  is(timeline.targetNodes[0].previewer.nodeFront,
+  is(getAnimationTimeBlocks(panel).length, 1, "There is 1 animation in the timeline");
+  is(getAnimationTargetNodes(panel)[0].previewer.nodeFront,
      inspector.selection.nodeFront,
      "The right node front is displayed in the timeline");
 });
--- a/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js
@@ -13,22 +13,26 @@ add_task(function* () {
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select a non animated node");
   yield selectNodeAndWaitForAnimations(".still", inspector);
 
   assertAnimationsDisplayed(panel, 0);
 
   info("Start an animation on the node");
+  let onRendered = waitForAnimationTimelineRendering(panel);
   yield changeElementAndWait({
     selector: ".still",
     attributeName: "class",
     attributeValue: "ball animated"
   }, panel, inspector);
 
+  yield onRendered;
+  yield waitForAllAnimationTargets(panel);
+
   assertAnimationsDisplayed(panel, 1);
 
   info("Remove the animation class on the node");
   yield changeElementAndWait({
     selector: ".ball.animated",
     attributeName: "class",
     attributeValue: "ball still"
   }, panel, inspector);
@@ -37,12 +41,10 @@ add_task(function* () {
 });
 
 function* changeElementAndWait(options, panel, inspector) {
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   let onInspectorUpdated = inspector.once("inspector-updated");
 
   yield executeInContent("devtools:test:setAttribute", options);
 
-  yield promise.all([onInspectorUpdated, onPanelUpdated,
-                     waitForAllAnimationTargets(panel),
-                     waitForAnimationTimelineRendering(panel)]);
+  yield promise.all([onInspectorUpdated, onPanelUpdated]);
 }
--- a/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js
@@ -39,12 +39,11 @@ function* testRefreshOnRemove(inspector,
   info("Add an finite animation on the node again, and wait for it to appear");
   onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield executeInContent("devtools:test:setAttribute", {
     selector: ".test-node",
     attributeName: "class",
     attributeValue: "ball short test-node"
   });
   yield onPanelUpdated;
-  yield waitForAllAnimationTargets(panel);
   yield waitForAnimationSelecting(panel);
   assertAnimationsDisplayed(panel, 1);
 }
--- a/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js
@@ -18,24 +18,26 @@ add_task(function* () {
 function* testRefresh(inspector, panel) {
   info("Select a non animated node");
   yield selectNodeAndWaitForAnimations(".still", inspector);
 
   info("Switch to the rule-view panel");
   inspector.sidebar.select("ruleview");
 
   info("Select the animated node now");
-  yield selectNodeAndWaitForAnimations(".animated", inspector);
+  yield selectNode(".animated", inspector);
 
   assertAnimationsDisplayed(panel, 0,
     "The panel doesn't show the animation data while inactive");
 
   info("Switch to the animation panel");
+  let onRendered = waitForAnimationTimelineRendering(panel);
   inspector.sidebar.select("animationinspector");
   yield panel.once(panel.UI_UPDATED_EVENT);
+  yield onRendered;
 
   assertAnimationsDisplayed(panel, 1,
     "The panel shows the animation data after selecting it");
 
   info("Switch again to the rule-view");
   inspector.sidebar.select("ruleview");
 
   info("Select the non animated node again");
--- a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js
+++ b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js
@@ -22,24 +22,22 @@ add_task(function* () {
 
   // ensure the focus is on the animation panel
   window.focus();
 
   info("Simulate spacebar stroke and check playResume button" +
        " is in paused state");
 
   // sending the key will lead to render animation timeline
-  let onUpdated = waitForAnimationTimelineRendering(panel);
   EventUtils.sendKey("SPACE", window);
-  yield onUpdated;
+  yield waitForAnimationTimelineRendering(panel);
   ok(playTimelineButtonEl.classList.contains("paused"),
     "The play/resume button is in its paused state");
 
   info("Simulate spacebar stroke and check playResume button" +
        " is in playing state");
 
   // sending the key will lead to render animation timeline
-  onUpdated = waitForAnimationTimelineRendering(panel);
   EventUtils.sendKey("SPACE", window);
-  yield onUpdated;
+  yield waitForAnimationTimelineRendering(panel);
   ok(!playTimelineButtonEl.classList.contains("paused"),
     "The play/resume button is in its play state again");
 });
--- a/devtools/client/animationinspector/test/browser_animation_summarygraph_for_multiple_easings.js
+++ b/devtools/client/animationinspector/test/browser_animation_summarygraph_for_multiple_easings.js
@@ -120,18 +120,17 @@ const TEST_CASES = {
       ]
     ]
   }
 };
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_multiple_easings.html");
   const { panel } = yield openAnimationInspector();
-  const timelineComponent = panel.animationsTimelineComponent;
-  timelineComponent.timeBlocks.forEach(timeBlock => {
+  getAnimationTimeBlocks(panel).forEach(timeBlock => {
     const state = timeBlock.animation.state;
     const testcase = TEST_CASES[state.name];
     if (!testcase) {
       return;
     }
 
     info(`Test effect easing graph of ${ state.name }`);
     const effectEl = timeBlock.containerEl.querySelector(".effect-easing");
--- a/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js
+++ b/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js
@@ -10,21 +10,19 @@ requestLongerTimeout(2);
 // be used to highlight elements in the DOM and select them in the inspector.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {toolbox, inspector, panel} = yield openAnimationInspector();
 
   info("Select the simple animated node");
-  let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNodeAndWaitForAnimations(".animated", inspector);
-  yield onPanelUpdated;
 
-  let targets = yield waitForAllAnimationTargets(panel);
+  let targets = getAnimationTargetNodes(panel);
   // Arbitrary select the first one
   let targetNodeComponent = targets[0];
 
   info("Retrieve the part of the widget that highlights the node on hover");
   let highlightingEl = targetNodeComponent.previewer.previewEl;
 
   info("Listen to node-highlight event and mouse over the widget");
   let onHighlight = toolbox.once("node-highlight");
@@ -44,31 +42,27 @@ add_task(function* () {
   is(nodeFront.tagName, "DIV",
     "The highlighted node has the correct tagName");
   is(nodeFront.attributes[0].name, "class",
     "The highlighted node has the correct attributes");
   is(nodeFront.attributes[0].value, "ball animated",
     "The highlighted node has the correct class");
 
   info("Select the body node in order to have the list of all animations");
-  onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNodeAndWaitForAnimations("body", inspector);
-  yield onPanelUpdated;
 
-  targets = yield waitForAllAnimationTargets(panel);
+  targets = getAnimationTargetNodes(panel);
   targetNodeComponent = targets[0];
 
   info("Click on the first animated node component and wait for the " +
        "selection to change");
   let onSelection = inspector.selection.once("new-node-front");
-  onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
+  let onRendered = waitForAnimationTimelineRendering(panel);
   let nodeEl = targetNodeComponent.previewer.previewEl;
   EventUtils.sendMouseEvent({type: "click"}, nodeEl,
                             nodeEl.ownerDocument.defaultView);
   yield onSelection;
 
   is(inspector.selection.nodeFront, targetNodeComponent.previewer.nodeFront,
     "The selected node is the one stored on the animation widget");
 
-  yield onPanelUpdated;
-  yield waitForAllAnimationTargets(panel);
-  yield waitForAnimationSelecting(panel);
+  yield onRendered;
 });
--- a/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
+++ b/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
@@ -8,17 +8,17 @@ requestLongerTimeout(2);
 
 // Test that the DOM element targets displayed in animation player widgets can
 // be used to highlight elements in the DOM and select them in the inspector.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
-  let targets = panel.animationsTimelineComponent.targetNodes;
+  let targets = getAnimationTargetNodes(panel);
 
   info("Click on the highlighter icon for the first animated node");
   let domNodePreview1 = targets[0].previewer;
   yield lockHighlighterOn(domNodePreview1);
   ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
      "The highlighter icon is selected");
 
   info("Click on the highlighter icon for the second animated node");
--- a/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js
@@ -5,17 +5,17 @@
 "use strict";
 
 // Check that the iteration start is displayed correctly in time blocks.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_script_animation.html");
   let {panel} = yield openAnimationInspector();
   let timelineComponent = panel.animationsTimelineComponent;
-  let timeBlockComponents = timelineComponent.timeBlocks;
+  let timeBlockComponents = getAnimationTimeBlocks(panel);
   let detailsComponent = timelineComponent.details;
 
   for (let i = 0; i < timeBlockComponents.length; i++) {
     info(`Expand time block ${i} so its keyframes are visible`);
     yield clickOnAnimation(panel, i);
 
     info(`Check the state of time block ${i}`);
     let {containerEl, animation: {state}} = timeBlockComponents[i];
--- a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button_03.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button_03.js
@@ -10,30 +10,29 @@ requestLongerTimeout(2);
 // reached the end of the timeline: continues to be in playing mode for infinite
 // animations, goes to paused mode otherwise.
 // And test that clicking the button once the scrubber has reached the end of
 // the timeline does the right thing.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
 
-  let {panel, controller, inspector} = yield openAnimationInspector();
+  let {panel, inspector} = yield openAnimationInspector();
   let btn = panel.playTimelineButtonEl;
 
   // For a finite animation, once the scrubber reaches the end of the timeline, the pause
   // button should go back to paused mode.
   info("Select a finite animation and wait for the animation to complete");
   yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
 
-  let onButtonPaused = waitForButtonPaused(btn);
-  let onTimelineUpdated = controller.once(controller.PLAYERS_UPDATED_EVENT);
-  // The page is reloaded to avoid missing the animation.
   yield reloadTab(inspector);
-  yield onTimelineUpdated;
-  yield onButtonPaused;
+
+  if (!btn.classList.contains("paused")) {
+    yield waitForButtonPaused(btn);
+  }
 
   ok(btn.classList.contains("paused"),
      "The button is in paused state once finite animations are done");
   yield assertScrubberMoving(panel, false);
 
   info("Click again on the button to play the animation from the start again");
   yield clickTimelinePlayPauseButton(panel);
 
--- a/devtools/client/animationinspector/test/browser_animation_timeline_setCurrentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_setCurrentTime.js
@@ -19,18 +19,17 @@ requestLongerTimeout(2);
 // we confirm the behavior of setCurrentTime by delay and endDelay.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_timing_combination_animation.html");
   const { panel, controller } = yield openAnimationInspector();
 
   yield clickTimelinePlayPauseButton(panel);
 
-  const timelineComponent = panel.animationsTimelineComponent;
-  const timeBlockComponents = timelineComponent.timeBlocks;
+  const timeBlockComponents = getAnimationTimeBlocks(panel);
 
   // Test -5000ms.
   let time = -5000;
   yield controller.setCurrentTimeAll(time, true);
   for (let i = 0; i < timeBlockComponents.length; i++) {
     yield timeBlockComponents[i].animation.refreshState();
     const state = yield timeBlockComponents[i].animation.state;
     info(`Check the state at ${ time }ms with `
--- a/devtools/client/animationinspector/test/browser_animation_timeline_short_duration.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_short_duration.js
@@ -7,36 +7,35 @@
 requestLongerTimeout(2);
 
 // Test short duration (e.g. 1ms) animation.
 
 add_task(function* () {
   yield addTab(URL_ROOT + "doc_short_duration_animation.html");
   const { panel, inspector } = yield openAnimationInspector();
 
-  const timelineComponent = panel.animationsTimelineComponent;
-
   info("Check the listed time blocks");
-  for (let i = 0; i < timelineComponent.timeBlocks.length; i++) {
+  const timeBlocks = getAnimationTimeBlocks(panel);
+  for (let i = 0; i < timeBlocks.length; i++) {
     info(`Check the time block ${i}`);
-    const {containerEl, animation: {state}} = timelineComponent.timeBlocks[i];
+    const {containerEl, animation: {state}} = timeBlocks[i];
     checkSummaryGraph(containerEl, state);
   }
 
   info("Check the time block one by one");
   info("Check #onetime");
   yield selectNodeAndWaitForAnimations("#onetime", inspector);
-  let timeBlock = timelineComponent.timeBlocks[0];
+  let timeBlock = getAnimationTimeBlocks(panel)[0];
   let containerEl = timeBlock.containerEl;
   let state = timeBlock.animation.state;
   checkSummaryGraph(containerEl, state, true);
 
   info("Check #infinite");
   yield selectNodeAndWaitForAnimations("#infinite", inspector);
-  timeBlock = timelineComponent.timeBlocks[0];
+  timeBlock = getAnimationTimeBlocks(panel)[0];
   containerEl = timeBlock.containerEl;
   state = timeBlock.animation.state;
   checkSummaryGraph(containerEl, state, true);
 });
 
 function checkSummaryGraph(el, state, isDetail) {
   info("Check the coordinates of summary graph");
   const groupEls = el.querySelectorAll("svg g");
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js
@@ -15,31 +15,31 @@ add_task(function* () {
   yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Selecting a delayed animated node");
   yield selectNodeAndWaitForAnimations(".delayed", inspector);
   let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
   checkDelayAndName(timelineEl, true);
   let animationEl = timelineEl.querySelector(".animation");
-  let state = panel.animationsTimelineComponent.timeBlocks[0].animation.state;
+  let state = getAnimationTimeBlocks(panel)[0].animation.state;
   checkPath(animationEl, state);
 
   info("Selecting a no-delay animated node");
   yield selectNodeAndWaitForAnimations(".animated", inspector);
   checkDelayAndName(timelineEl, false);
   animationEl = timelineEl.querySelector(".animation");
-  state = panel.animationsTimelineComponent.timeBlocks[0].animation.state;
+  state = getAnimationTimeBlocks(panel)[0].animation.state;
   checkPath(animationEl, state);
 
   info("Selecting a negative-delay animated node");
   yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
   checkDelayAndName(timelineEl, true);
   animationEl = timelineEl.querySelector(".animation");
-  state = panel.animationsTimelineComponent.timeBlocks[0].animation.state;
+  state = getAnimationTimeBlocks(panel)[0].animation.state;
   checkPath(animationEl, state);
 });
 
 function checkDelayAndName(timelineEl, hasDelay) {
   let delay = timelineEl.querySelector(".delay");
 
   is(!!delay, hasDelay, "The timeline " +
                         (hasDelay ? "contains" : "does not contain") +
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js
@@ -18,18 +18,17 @@ add_task(function* () {
   let selectors = ["#target1", "#target2", "#target3", "#target4"];
   for (let i = 0; i < selectors.length; i++) {
     let selector = selectors[i];
     yield selectNode(selector, inspector);
     yield waitForAnimationSelecting(panel);
     let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
     let animationEl = timelineEl.querySelector(".animation");
     checkEndDelayAndName(animationEl);
-    const state =
-      panel.animationsTimelineComponent.timeBlocks[0].animation.state;
+    const state = getAnimationTimeBlocks(panel)[0].animation.state;
     checkPath(animationEl, state);
   }
 });
 
 function checkEndDelayAndName(animationEl) {
   let endDelay = animationEl.querySelector(".end-delay");
   let name = animationEl.querySelector(".name");
   let targetNode = animationEl.querySelector(".target");
--- a/devtools/client/animationinspector/test/head.js
+++ b/devtools/client/animationinspector/test/head.js
@@ -85,25 +85,29 @@ function* reloadTab(inspector) {
  * @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.
  */
 var selectNodeAndWaitForAnimations = Task.async(
   function* (data, inspector, reason = "test") {
-    yield selectNode(data, inspector, reason);
-
     // 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).
-    let {AnimationsPanel} = inspector.sidebar.getWindowForTab(TAB_NAME);
-    yield waitForAllAnimationTargets(AnimationsPanel);
+    let {AnimationsController, AnimationsPanel} =
+      inspector.sidebar.getWindowForTab(TAB_NAME);
+    let onUiUpdated = AnimationsPanel.once(AnimationsPanel.UI_UPDATED_EVENT);
+
+    yield selectNode(data, inspector, reason);
 
-    // Wait for animation timeline rendering.
-    yield waitForAnimationTimelineRendering(AnimationsPanel);
+    yield onUiUpdated;
+    if (AnimationsController.animationPlayers.length !== 0) {
+      yield waitForAnimationTimelineRendering(AnimationsPanel);
+      yield waitForAllAnimationTargets(AnimationsPanel);
+    }
   }
 );
 
 /**
  * Check if there are the expected number of animations being displayed in the
  * panel right now.
  * @param {AnimationsPanel} panel
  * @param {Number} nbAnimations The expected number of animations.
@@ -155,22 +159,20 @@ var openAnimationInspector = Task.async(
 
   info("Waiting for the animation controller and panel to be ready");
   if (AnimationsPanel.initialized) {
     yield AnimationsPanel.initialized;
   } else {
     yield AnimationsPanel.once(AnimationsPanel.PANEL_INITIALIZED);
   }
 
-  // Make sure we wait for all animations to be loaded (especially their target
-  // nodes to be lazily displayed). This is safe to do even if there are no
-  // animations displayed.
-  yield waitForAllAnimationTargets(AnimationsPanel);
-  // Also, wait for timeline redering.
-  yield waitForAnimationTimelineRendering(AnimationsPanel);
+  if (AnimationsController.animationPlayers.length !== 0) {
+    yield waitForAnimationTimelineRendering(AnimationsPanel);
+    yield waitForAllAnimationTargets(AnimationsPanel);
+  }
 
   return {
     toolbox: toolbox,
     inspector: inspector,
     controller: AnimationsController,
     panel: AnimationsPanel,
     window: win
   };
@@ -247,21 +249,23 @@ var getAnimationPlayerState = Task.async
  */
 function isNodeVisible(node) {
   return !!node.getClientRects().length;
 }
 
 /**
  * Wait for all AnimationTargetNode instances to be fully loaded
  * (fetched their related actor and rendered), and return them.
+ * This method should be called after "animation-timeline-rendering-completed" is emitted,
+ * since we get all the AnimationTargetNode instances using getAnimationTargetNodes().
  * @param {AnimationsPanel} panel
  * @return {Array} all AnimationTargetNode instances
  */
 var waitForAllAnimationTargets = Task.async(function* (panel) {
-  let targets = panel.animationsTimelineComponent.targetNodes;
+  let targets = getAnimationTargetNodes(panel);
   yield promise.all(targets.map(t => {
     if (!t.previewer.nodeFront) {
       return t.once("target-retrieved");
     }
     return false;
   }));
   return targets;
 });
@@ -294,54 +298,54 @@ function* assertScrubberMoving(panel, is
 
 /**
  * Click the play/pause button in the timeline toolbar and wait for animations
  * to update.
  * @param {AnimationsPanel} panel
  */
 function* clickTimelinePlayPauseButton(panel) {
   let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  const onAnimationTimelineRendered = waitForAnimationTimelineRendering(panel);
+  let onRendered = waitForAnimationTimelineRendering(panel);
 
   let btn = panel.playTimelineButtonEl;
   let win = btn.ownerDocument.defaultView;
   EventUtils.sendMouseEvent({type: "click"}, btn, win);
 
   yield onUiUpdated;
-  yield onAnimationTimelineRendered;
+  yield onRendered;
   yield waitForAllAnimationTargets(panel);
 }
 
 /**
  * Click the rewind button in the timeline toolbar and wait for animations to
  * update.
  * @param {AnimationsPanel} panel
  */
 function* clickTimelineRewindButton(panel) {
   let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  const onAnimationTimelineRendered = waitForAnimationTimelineRendering(panel);
+  let onRendered = waitForAnimationTimelineRendering(panel);
 
   let btn = panel.rewindTimelineButtonEl;
   let win = btn.ownerDocument.defaultView;
   EventUtils.sendMouseEvent({type: "click"}, btn, win);
 
   yield onUiUpdated;
-  yield onAnimationTimelineRendered;
+  yield onRendered;
   yield waitForAllAnimationTargets(panel);
 }
 
 /**
  * Select a rate inside the playback rate selector in the timeline toolbar and
  * wait for animations to update.
  * @param {AnimationsPanel} panel
  * @param {Number} rate The new rate value to be selected
  */
 function* changeTimelinePlaybackRate(panel, rate) {
   let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  const onAnimationTimelineRendered = waitForAnimationTimelineRendering(panel);
+  let onRendered = waitForAnimationTimelineRendering(panel);
 
   let select = panel.rateSelectorEl.firstChild;
   let win = select.ownerDocument.defaultView;
 
   // Get the right option.
   let option = [...select.options].filter(o => o.value === rate + "")[0];
   if (!option) {
     ok(false,
@@ -350,17 +354,17 @@ function* changeTimelinePlaybackRate(pan
     return;
   }
 
   // Simulate the right events to select the option in the drop-down.
   EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"}, win);
   EventUtils.synthesizeMouseAtCenter(option, {type: "mouseup"}, win);
 
   yield onUiUpdated;
-  yield onAnimationTimelineRendered;
+  yield onRendered;
   yield waitForAllAnimationTargets(panel);
 
   // Simulate a mousemove outside of the rate selector area to avoid subsequent
   // tests from failing because of unwanted mouseover events.
   EventUtils.synthesizeMouseAtCenter(
     win.document.querySelector("#timeline-toolbar"), {type: "mousemove"}, win);
 }
 
@@ -372,21 +376,17 @@ function* waitForAnimationSelecting(pane
   yield panel.animationsTimelineComponent.once("animation-selected");
 }
 
 /**
  * Wait for rendering animation timeline.
  * @param {AnimationsPanel} panel
  */
 function* waitForAnimationTimelineRendering(panel) {
-  const ready =
-    panel.animationsTimelineComponent.animations.length === 0
-    ? Promise.resolve()
-    : panel.animationsTimelineComponent.once("animation-timeline-rendering-completed");
-  yield ready;
+  return panel.animationsTimelineComponent.once("animation-timeline-rendering-completed");
 }
 
 /**
    + * Click the timeline header to update the animation current time.
    + * @param {AnimationsPanel} panel
    + * @param {Number} x position rate on timeline header.
    + *                 This method calculates
    + *                 `position * offsetWidth + offsetLeft of timeline header`
@@ -480,28 +480,27 @@ function getKeyframeEl(panel, propertyNa
  * @param {String} value - property value.
  * @param {String} selector - selector for test document.
  */
 function* setStyle(animation, panel, name, value, selector) {
   info("Change the animation style via the content DOM. Setting " +
        name + " to " + value + " of " + selector);
 
   const onAnimationChanged = animation ? once(animation, "changed") : Promise.resolve();
+  const onRendered = waitForAnimationTimelineRendering(panel);
+
   yield executeInContent("devtools:test:setStyle", {
     selector: selector,
     propertyName: name,
     propertyValue: value
   });
+
   yield onAnimationChanged;
-
-  // Also wait for the target node previews to be loaded if the panel got
-  // refreshed as a result of this animation mutation.
+  yield onRendered;
   yield waitForAllAnimationTargets(panel);
-  // And wait for animation timeline rendering.
-  yield waitForAnimationTimelineRendering(panel);
 }
 
 /**
  * Graph shapes of summary and detail are constructed by <path> element.
  * This function checks the vertex of path segments.
  * Also, if needed, checks the color for <stop> element.
  * @param pathEl - <path> element.
  * @param duration - float as duration which pathEl represetns.
@@ -588,8 +587,32 @@ function isPassingThrough(pathSegList, x
  * @param offset - float which represents the "offset" attribute of <stop>.
  * @return <stop> element.
  */
 function findStopElement(svgEl, offset) {
   return [...svgEl.querySelectorAll("stop")].find(stopEl => {
     return stopEl.getAttribute("offset") == offset;
   });
 }
+
+/*
+ * Returns all AnimationTargetNode instances.
+ * This method should be called after emit "animation-timeline-rendering-completed".
+ * @param {AnimationsPanel} panel The panel instance.
+ * @return {Array} all AnimationTargetNode instances.
+ */
+function getAnimationTargetNodes(panel) {
+  return panel.animationsTimelineComponent.animations.map(animation => {
+    return panel.animationsTimelineComponent.componentsMap[animation.actorID].targetNode;
+  });
+}
+
+/*
+ * Returns all AnimationTargetBlock instances.
+ * This method should be called after emit "animation-timeline-rendering-completed".
+ * @param {AnimationsPanel} panel The panel instance.
+ * @return {Array} all AnimationTargetBlock instances.
+ */
+function getAnimationTimeBlocks(panel) {
+  return panel.animationsTimelineComponent.animations.map(animation => {
+    return panel.animationsTimelineComponent.componentsMap[animation.actorID].timeBlock;
+  });
+}