Bug 1394730 - Should clean up UITour highlight while navigating to another tour, r?rexboy draft
authorFischer.json <fischer.json@gmail.com>
Sun, 10 Sep 2017 19:25:48 +0800
changeset 662232 20a000f2a919c5cff55069e8e38d4945e12205b6
parent 662021 00baeed193d4f276694912f0298336880280837d
child 730793 a8a20d0e3e628973326a6d65bfc5abd8ed41482e
push id79003
push userbmo:fliu@mozilla.com
push dateMon, 11 Sep 2017 08:55:58 +0000
reviewersrexboy
bugs1394730, 1377298
milestone57.0a1
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);
+});