Bug 1394730 - Should clean up UITour highlight while navigating to another tour, r=rexboy
authorFischer.json <fischer.json@gmail.com>
Sun, 10 Sep 2017 19:25:48 +0800
changeset 429543 67fb712adac175fab2744eef90946db65854c520
parent 429542 f09b2b387751bb86a34b5cfb2bd1eacd31ab1fad
child 429544 3be0f512422bcf03178c3c1160328d2e6e7ca678
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrexboy
bugs1394730, 1377298
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1394730 - Should clean up UITour highlight while navigating to another tour, r=rexboy This patch: - fixes UITour highlight not being cleaned up while navigating to another tour by mouse (the regression caused by the bug 1377298) - adds the ability to clean up UITour while navigating to another tour by keyboard MozReview-Commit-ID: CH8w5CloGCv
browser/extensions/onboarding/content/onboarding-tour-agent.js
browser/extensions/onboarding/test/browser/browser.ini
browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js
--- a/browser/extensions/onboarding/content/onboarding-tour-agent.js
+++ b/browser/extensions/onboarding/content/onboarding-tour-agent.js
@@ -1,27 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
- /* globals Mozilla */
+/* globals Mozilla */
 
+(function() {
 "use strict";
 
-document.addEventListener("Agent:CanSetDefaultBrowserInBackground", () => {
+let onCanSetDefaultBrowserInBackground = () => {
   Mozilla.UITour.getConfiguration("appinfo", config => {
     let canSetInBackGround = config.canSetDefaultBrowserInBackground;
     let btn = document.getElementById("onboarding-tour-default-browser-button");
     btn.setAttribute("data-cansetbg", canSetInBackGround);
     btn.textContent = canSetInBackGround ? btn.getAttribute("data-bg") : btn.getAttribute("data-panel");
   });
-});
+};
 
-document.getElementById("onboarding-overlay")
-  .addEventListener("click", evt => {
+let onClick = evt => {
   switch (evt.target.id) {
     case "onboarding-tour-addons-button":
       Mozilla.UITour.showHighlight("addons");
       break;
     case "onboarding-tour-customize-button":
       Mozilla.UITour.showHighlight("customize");
       break;
     case "onboarding-tour-default-browser-button":
@@ -58,18 +58,32 @@ document.getElementById("onboarding-over
       }
       break;
     case "onboarding-overlay":
     case "onboarding-overlay-close-btn":
       // Dismiss any highlights if a user tries to close the dialog.
       Mozilla.UITour.hideHighlight();
       break;
   }
-  // Dismiss any highlights if a user tries to change to other tours.
-  if (evt.target.classList.contains("onboarding-tour-item")) {
-    Mozilla.UITour.hideHighlight();
+  let classList = evt.target.classList;
+  // On keyboard navigation the target would be .onboarding-tour-item.
+  // On mouse clicking the target would be .onboarding-tour-item-container.
+  if (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container")) {
+    Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
+  }
+};
+
+let overlay = document.getElementById("onboarding-overlay");
+overlay.addEventListener("click", onClick);
+overlay.addEventListener("keypress", e => {
+  let { target, key } = e;
+  let classList = target.classList;
+  if ((key == " " || key == "Enter") &&
+      // On keyboard navigation the target would be .onboarding-tour-item.
+      // On mouse clicking the target would be .onboarding-tour-item-container.
+      (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container"))) {
+    Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
   }
 });
+document.getElementById("onboarding-overlay-button").addEventListener("Agent:Destroy", () => Mozilla.UITour.hideHighlight());
+document.addEventListener("Agent:CanSetDefaultBrowserInBackground", onCanSetDefaultBrowserInBackground);
 
-document.getElementById("onboarding-overlay-button").addEventListener("Agent:Destroy", () => {
-  Mozilla.UITour.hideHighlight();
-  Mozilla.UITour.hideMenu("urlbar");
-});
+})();
--- a/browser/extensions/onboarding/test/browser/browser.ini
+++ b/browser/extensions/onboarding/test/browser/browser.ini
@@ -10,8 +10,9 @@ skip-if = debug || os == "mac" # Full ke
 [browser_onboarding_notification_3.js]
 [browser_onboarding_notification_4.js]
 [browser_onboarding_notification_5.js]
 [browser_onboarding_notification_click_auto_complete_tour.js]
 [browser_onboarding_select_default_tour.js]
 [browser_onboarding_skip_tour.js]
 [browser_onboarding_tours.js]
 [browser_onboarding_tourset.js]
+[browser_onboarding_uitour.js]
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
@@ -20,23 +20,16 @@ function assertTourCompleted(tourId, exp
     } else {
       ok(!item.classList.contains("onboarding-complete"), `Should not set the incomplete #${args.tourId} tour with the complete style`);
       ok(!completedText, "Text label should not be present for an incomplete item");
       ok(!item.hasAttribute("aria-describedby"), "Incomplete item should not have aria-describedby attribute set");
     }
   });
 }
 
-function promisePopupChange(popup, expectedState) {
-  return new Promise(resolve => {
-    let event = expectedState == "open" ? "popupshown" : "popuphidden";
-    popup.addEventListener(event, resolve, { once: true });
-  });
-}
-
 add_task(async function test_set_right_tour_completed_style_on_overlay() {
   resetOnboardingDefaultState();
 
   let tourIds = TOUR_IDs;
   // Mark the tours of even number as completed
   for (let i = 0; i < tourIds.length; ++i) {
     setTourCompletedState(tourIds[i], i % 2 == 0);
   }
@@ -90,84 +83,8 @@ add_task(async function test_click_actio
     let tab = tabs[i];
     await assertOverlaySemantics(tab.linkedBrowser);
     for (let id of tourIds) {
       await assertTourCompleted(id, id == completedTourId, tab.linkedBrowser);
     }
     await BrowserTestUtils.removeTab(tab);
   }
 });
-
-add_task(async function test_clean_up_uitour_on_page_unload() {
-  resetOnboardingDefaultState();
-  await SpecialPowers.pushPrefEnv({set: [
-    ["browser.onboarding.newtour", "singlesearch,customize"],
-  ]});
-
-  let tab = await openTab(ABOUT_NEWTAB_URL);
-  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
-  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
-  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
-
-  // Trigger UITour showHighlight and showMenu
-  let highlight = document.getElementById("UITourHighlightContainer");
-  let urlbarOpenPromise = promisePopupChange(gURLBar.popup, "open");
-  let highlightOpenPromise = promisePopupChange(highlight, "open");
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch-button", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize-button", {}, tab.linkedBrowser);
-  await urlbarOpenPromise;
-  await highlightOpenPromise;
-  is(gURLBar.popup.state, "open", "Should show urlbar popup");
-  is(highlight.state, "open", "Should show UITour highlight");
-  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
-
-  // Load another page to unload the current page
-  let urlbarClosePromise = promisePopupChange(gURLBar.popup, "closed");
-  let highlightClosePromise = promisePopupChange(highlight, "closed");
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com");
-  await urlbarClosePromise;
-  await highlightClosePromise;
-  is(gURLBar.popup.state, "closed", "Should close urlbar popup after page unloaded");
-  is(highlight.state, "closed", "Should close UITour highlight after page unloaded");
-
-  await BrowserTestUtils.removeTab(tab);
-});
-
-add_task(async function test_clean_up_uitour_on_window_resize() {
-  resetOnboardingDefaultState();
-  await SpecialPowers.pushPrefEnv({set: [
-    ["browser.onboarding.newtour", "singlesearch,customize"],
-  ]});
-
-  let tab = await openTab(ABOUT_NEWTAB_URL);
-  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
-  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
-  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
-
-  // Trigger UITour showHighlight and showMenu
-  let highlight = document.getElementById("UITourHighlightContainer");
-  let urlbarOpenPromise = promisePopupChange(gURLBar.popup, "open");
-  let highlightOpenPromise = promisePopupChange(highlight, "open");
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch-button", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize", {}, tab.linkedBrowser);
-  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize-button", {}, tab.linkedBrowser);
-  await urlbarOpenPromise;
-  await highlightOpenPromise;
-  is(gURLBar.popup.state, "open", "Should show urlbar popup");
-  is(highlight.state, "open", "Should show UITour highlight");
-  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
-
-  // Resize window to destroy the onboarding tour
-  const originalWidth = window.innerWidth;
-  let urlbarClosePromise = promisePopupChange(gURLBar.popup, "closed");
-  let highlightClosePromise = promisePopupChange(highlight, "closed");
-  window.innerWidth = 300;
-  await urlbarClosePromise;
-  await highlightClosePromise;
-  is(gURLBar.popup.state, "closed", "Should close urlbar popup after window resized");
-  is(highlight.state, "closed", "Should close UITour highlight after window resized");
-
-  window.innerWidth = originalWidth;
-  await BrowserTestUtils.removeTab(tab);
-});
new file mode 100644
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js
@@ -0,0 +1,129 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+function promisePopupChange(popup, expectedState) {
+  return new Promise(resolve => {
+    let event = expectedState == "open" ? "popupshown" : "popuphidden";
+    popup.addEventListener(event, resolve, { once: true });
+  });
+}
+
+async function promiseOpenOnboardingOverlay(tab) {
+  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+  return promiseOnboardingOverlayOpened(tab.linkedBrowser);
+}
+
+async function triggerCustomizeUITourHighlight(tab) {
+  await promiseOpenOnboardingOverlay(tab);
+  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize", {}, tab.linkedBrowser);
+  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize-button", {}, tab.linkedBrowser);
+}
+
+add_task(async function test_clean_up_uitour_after_navigating_to_other_tour_by_keyboard() {
+  resetOnboardingDefaultState();
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.onboarding.newtour", "singlesearch,customize"],
+  ]});
+
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await promiseOpenOnboardingOverlay(tab);
+
+  // Navigate to the Customize tour to trigger UITour showHighlight
+  let highlight = document.getElementById("UITourHighlightContainer");
+  let highlightOpenPromise = promisePopupChange(highlight, "open");
+  tab.linkedBrowser.focus(); // Make sure the key event will be fired on the focused page
+  await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+  await highlightOpenPromise;
+  is(highlight.state, "open", "Should show UITour highlight");
+  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+  // Navigate to the Single-Search tour
+  let highlightClosePromise = promisePopupChange(highlight, "closed");
+  tab.linkedBrowser.focus(); // Make sure the key event will be fired on the focused page
+  await BrowserTestUtils.synthesizeKey("VK_TAB", { shiftKey: true }, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_TAB", { shiftKey: true }, tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+  await highlightClosePromise;
+  is(highlight.state, "closed", "Should close UITour highlight after navigating to another tour by keyboard");
+  await BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_after_navigating_to_other_tour_by_mouse() {
+  resetOnboardingDefaultState();
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.onboarding.newtour", "singlesearch,customize"],
+  ]});
+
+  // Navigate to the Customize tour to trigger UITour showHighlight
+  let highlight = document.getElementById("UITourHighlightContainer");
+  let highlightOpenPromise = promisePopupChange(highlight, "open");
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await triggerCustomizeUITourHighlight(tab);
+  await highlightOpenPromise;
+  is(highlight.state, "open", "Should show UITour highlight");
+  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+  // Navigate to the Single-Search tour
+  let highlightClosePromise = promisePopupChange(highlight, "closed");
+  BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch", {}, tab.linkedBrowser);
+  await highlightClosePromise;
+  is(highlight.state, "closed", "Should close UITour highlight after navigating to another tour by mouse");
+  await BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_on_page_unload() {
+  resetOnboardingDefaultState();
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.onboarding.newtour", "singlesearch,customize"],
+  ]});
+
+  // Trigger UITour showHighlight
+  let highlight = document.getElementById("UITourHighlightContainer");
+  let highlightOpenPromise = promisePopupChange(highlight, "open");
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await triggerCustomizeUITourHighlight(tab);
+  await highlightOpenPromise;
+  is(highlight.state, "open", "Should show UITour highlight");
+  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+  // Load another page to unload the current page
+  let highlightClosePromise = promisePopupChange(highlight, "closed");
+  await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com");
+  await highlightClosePromise;
+  is(highlight.state, "closed", "Should close UITour highlight after page unloaded");
+  await BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_on_window_resize() {
+  resetOnboardingDefaultState();
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.onboarding.newtour", "singlesearch,customize"],
+  ]});
+
+  // Trigger UITour showHighlight
+  let highlight = document.getElementById("UITourHighlightContainer");
+  let highlightOpenPromise = promisePopupChange(highlight, "open");
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await triggerCustomizeUITourHighlight(tab);
+  await highlightOpenPromise;
+  is(highlight.state, "open", "Should show UITour highlight");
+  is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+  // Resize window to destroy the onboarding tour
+  const originalWidth = window.innerWidth;
+  let highlightClosePromise = promisePopupChange(highlight, "closed");
+  window.innerWidth = 300;
+  await highlightClosePromise;
+  is(highlight.state, "closed", "Should close UITour highlight after window resized");
+  window.innerWidth = originalWidth;
+  await BrowserTestUtils.removeTab(tab);
+});