Bug 1383070 - Intermittent: Uncaught exception Should load onboarding overlay, r=mossop
authorFischer.json <fischer.json@gmail.com>
Sat, 22 Jul 2017 23:40:01 +0800
changeset 422766 2948f11c75c809caff4491384d68698608c4f59a
parent 422765 e2c06426fc2e1340ca316a03653408452a16f960
child 422767 3b9509ef04d0c8e87a59aa1b03e4a0beca12f1dc
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop
bugs1383070
milestone56.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 1383070 - Intermittent: Uncaught exception Should load onboarding overlay, r=mossop MozReview-Commit-ID: 6avWDMV3PAg
browser/extensions/onboarding/content/onboarding.js
browser/extensions/onboarding/test/browser/browser_onboarding_notification.js
browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js
browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js
browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js
browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
browser/extensions/onboarding/test/browser/head.js
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -678,27 +678,26 @@ class Onboarding {
       return;
     }
     let targetTourId = queue[0];
     let targetTour = this._tours.find(tour => tour.id == targetTourId);
 
     // Show the target tour notification
     this._notificationBar = this._renderNotificationBar();
     this._notificationBar.addEventListener("click", this);
-    this._window.document.body.appendChild(this._notificationBar);
-
     this._notificationBar.dataset.targetTourId = targetTour.id;
     let notificationStrings = targetTour.getNotificationStrings(this._bundle);
     let actionBtn = this._notificationBar.querySelector("#onboarding-notification-action-btn");
     actionBtn.textContent = notificationStrings.button;
     let tourTitle = this._notificationBar.querySelector("#onboarding-notification-tour-title");
     tourTitle.textContent = notificationStrings.title;
     let tourMessage = this._notificationBar.querySelector("#onboarding-notification-tour-message");
     tourMessage.textContent = notificationStrings.message;
     this._notificationBar.classList.add("onboarding-opened");
+    this._window.document.body.appendChild(this._notificationBar);
 
     let params = [];
     if (startQueueLength != queue.length) {
       // We just change tour so update the time, the count and the queue
       params.push({
         name: "browser.onboarding.notification.last-time-of-changing-tour-sec",
         value: Math.floor(Date.now() / 1000)
       });
@@ -884,14 +883,20 @@ if (Services.prefs.getBoolPref("browser.
     if (!content || evt.target != content.document) {
       return;
     }
     removeEventListener("load", onLoad);
 
     let window = evt.target.defaultView;
     let location = window.location.href;
     if (location == ABOUT_NEWTAB_URL || location == ABOUT_HOME_URL) {
+      // We just want to run tests as quick as possible
+      // so in the automation test, we don't do `requestIdleCallback`.
+      if (Cu.isInAutomation) {
+        new Onboarding(window);
+        return;
+      }
       window.requestIdleCallback(() => {
         new Onboarding(window);
       });
     }
   }, true);
 }
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_notification.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification.js
@@ -1,64 +1,58 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+requestLongerTimeout(3);
+
 add_task(async function test_show_tour_notifications_in_order() {
   resetOnboardingDefaultState();
   Preferences.set("browser.onboarding.notification.max-prompt-count-per-tour", 1);
   skipMuteNotificationOnFirstSession();
 
   let tourIds = TOUR_IDs;
   let tab = null;
   let targetTourId = null;
-  let reloadPromise = null;
   let expectedPrefUpdate = null;
   await loopTourNotificationQueueOnceInOrder();
   await loopTourNotificationQueueOnceInOrder();
 
   expectedPrefUpdate = promisePrefUpdated("browser.onboarding.notification.finished", true);
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await expectedPrefUpdate;
   let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   ok(!tourId, "Should not prompt each tour for more than 2 chances.");
   await BrowserTestUtils.removeTab(tab);
 
   async function loopTourNotificationQueueOnceInOrder() {
     for (let i = 0; i < tourIds.length; ++i) {
       if (tab) {
-        reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-        tab.linkedBrowser.reload();
-        await reloadPromise;
+        await reloadTab(tab);
       } else {
-        tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-        await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+        tab = await openTab(ABOUT_NEWTAB_URL);
       }
       await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
       await promiseTourNotificationOpened(tab.linkedBrowser);
       targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
       is(targetTourId, tourIds[i], "Should show tour notifications in order");
     }
   }
 });
 
 add_task(async function test_open_target_tour_from_notification() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
   let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
 
   is(targetTourId, activeNavItemId, "Should navigate to the target tour item.");
   is(`${targetTourId}-page`, activePageId, "Should display the target tour page.");
   await BrowserTestUtils.removeTab(tab);
 });
-
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js
@@ -1,28 +1,29 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+requestLongerTimeout(3);
+
 add_task(async function test_not_show_notification_for_completed_tour() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
   let tourIds = TOUR_IDs;
   // Make only the last tour uncompleted
   let lastTourId = tourIds[tourIds.length - 1];
   for (let id of tourIds) {
     if (id != lastTourId) {
       setTourCompletedState(id, true);
     }
   }
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   is(targetTourId, lastTourId, "Should not show notification for completed tour");
   await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_skip_notification_for_completed_tour() {
@@ -30,58 +31,50 @@ add_task(async function test_skip_notifi
   Preferences.set("browser.onboarding.notification.max-prompt-count-per-tour", 1);
   skipMuteNotificationOnFirstSession();
 
   let tourIds = TOUR_IDs;
   // Make only 2nd tour completed
   await setTourCompletedState(tourIds[1], true);
 
   // Test show notification for the 1st tour
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   is(targetTourId, tourIds[0], "Should show notification for incompleted tour");
 
   // Test skip the 2nd tour and show notification for the 3rd tour
-  let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   is(targetTourId, tourIds[2], "Should skip notification for the completed 2nd tour");
   await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_mute_notification_on_1st_session() {
   resetOnboardingDefaultState();
 
   // Test no notifications during the mute duration on the 1st session
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   // The tour notification would be prompted on idle, so we wait idle twice here before proceeding
   await waitUntilWindowIdle(tab.linkedBrowser);
   await waitUntilWindowIdle(tab.linkedBrowser);
-  let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await waitUntilWindowIdle(tab.linkedBrowser);
   await waitUntilWindowIdle(tab.linkedBrowser);
   let promptCount = Preferences.get("browser.onboarding.notification.prompt-count", 0);
   is(0, promptCount, "Should not prompt tour notification during the mute duration on the 1st session");
 
   // Test notification prompted after the mute duration on the 1st session
   let muteTime = Preferences.get("browser.onboarding.notification.mute-duration-on-first-session-ms");
   let lastTime = Math.floor((Date.now() - muteTime - 1) / 1000);
   Preferences.set("browser.onboarding.notification.last-time-of-changing-tour-sec", lastTime);
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   promptCount = Preferences.get("browser.onboarding.notification.prompt-count", 0);
   is(1, promptCount, "Should prompt tour notification after the mute duration on the 1st session");
   await BrowserTestUtils.removeTab(tab);
 });
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js
@@ -1,94 +1,82 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+requestLongerTimeout(3);
+
 add_task(async function test_move_on_to_next_notification_when_reaching_max_prompt_count() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
   let maxCount = Preferences.get("browser.onboarding.notification.max-prompt-count-per-tour");
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
 
   let currentTourId = null;
-  let reloadPromise = null;
   for (let i = maxCount - 1; i > 0; --i) {
-    reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-    tab.linkedBrowser.reload();
-    await reloadPromise;
+    await reloadTab(tab);
     await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
     await promiseTourNotificationOpened(tab.linkedBrowser);
     currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
     is(previousTourId, currentTourId, "Should not move on to next tour notification until reaching the max prompt count per tour");
   }
 
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   isnot(previousTourId, currentTourId, "Should move on to next tour notification when reaching the max prompt count per tour");
 
   await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_move_on_to_next_notification_when_reaching_max_life_time() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
 
   let maxTime = Preferences.get("browser.onboarding.notification.max-life-time-per-tour-ms");
   let lastTime = Math.floor((Date.now() - maxTime - 1) / 1000);
   Preferences.set("browser.onboarding.notification.last-time-of-changing-tour-sec", lastTime);
-  let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   isnot(previousTourId, currentTourId, "Should move on to next tour notification when reaching the max life time per tour");
 
   await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_move_on_to_next_notification_after_interacting_with_notification() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-  await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+  let tab = await openTab(ABOUT_NEWTAB_URL);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-close-btn", {}, tab.linkedBrowser);
 
-  let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   let currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   isnot(previousTourId, currentTourId, "Should move on to next tour notification after clicking #onboarding-notification-close-btn");
   await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
   previousTourId = currentTourId;
 
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await promiseTourNotificationOpened(tab.linkedBrowser);
   currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   isnot(previousTourId, currentTourId, "Should move on to next tour notification after clicking #onboarding-notification-action-btn");
 
   await BrowserTestUtils.removeTab(tab);
 });
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js
@@ -1,42 +1,38 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+requestLongerTimeout(3);
+
 add_task(async function test_remove_all_tour_notifications_through_close_button() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
   let tourIds = TOUR_IDs;
   let tab = null;
   let targetTourId = null;
-  let reloadPromise = null;
   await closeTourNotificationsOneByOne();
 
   let expectedPrefUpdate = promisePrefUpdated("browser.onboarding.notification.finished", true);
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await expectedPrefUpdate;
   let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   ok(!tourId, "Should not prompt tour notifications any more after closing all notifcations.");
   await BrowserTestUtils.removeTab(tab);
 
   async function closeTourNotificationsOneByOne() {
     for (let i = 0; i < tourIds.length; ++i) {
       if (tab) {
-        reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-        tab.linkedBrowser.reload();
-        await reloadPromise;
+        await reloadTab(tab);
       } else {
-        tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-        await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+        tab = await openTab(ABOUT_NEWTAB_URL);
       }
       await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
       await promiseTourNotificationOpened(tab.linkedBrowser);
       targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
       is(targetTourId, tourIds[i], `Should show tour notifications of ${targetTourId}`);
       await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-close-btn", {}, tab.linkedBrowser);
       await promiseTourNotificationClosed(tab.linkedBrowser);
     }
@@ -45,38 +41,32 @@ add_task(async function test_remove_all_
 
 add_task(async function test_remove_all_tour_notifications_through_action_button() {
   resetOnboardingDefaultState();
   skipMuteNotificationOnFirstSession();
 
   let tourIds = TOUR_IDs;
   let tab = null;
   let targetTourId = null;
-  let reloadPromise = null;
   await clickTourNotificationActionButtonsOneByOne();
 
   let expectedPrefUpdate = promisePrefUpdated("browser.onboarding.notification.finished", true);
-  reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-  tab.linkedBrowser.reload();
-  await reloadPromise;
+  await reloadTab(tab);
   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
   await expectedPrefUpdate;
   let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
   ok(!tourId, "Should not prompt tour notifcations any more after taking actions on all notifcations.");
   await BrowserTestUtils.removeTab(tab);
 
   async function clickTourNotificationActionButtonsOneByOne() {
     for (let i = 0; i < tourIds.length; ++i) {
       if (tab) {
-        reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
-        tab.linkedBrowser.reload();
-        await reloadPromise;
+        await reloadTab(tab);
       } else {
-        tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-        await BrowserTestUtils.loadURI(tab.linkedBrowser, ABOUT_NEWTAB_URL);
+        tab = await openTab(ABOUT_NEWTAB_URL);
       }
       await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
       await promiseTourNotificationOpened(tab.linkedBrowser);
       targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
       is(targetTourId, tourIds[i], `Should show tour notifications of ${targetTourId}`);
       await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
       await promiseTourNotificationClosed(tab.linkedBrowser);
     }
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
  "use strict";
 
+requestLongerTimeout(2);
+
 function assertOnboardingDestroyed(browser) {
   return ContentTask.spawn(browser, {}, function() {
     let expectedRemovals = [
       "#onboarding-overlay",
       "#onboarding-overlay-button"
     ];
     for (let selector of expectedRemovals) {
       let removal = content.document.querySelector(selector);
@@ -28,18 +30,17 @@ function assertTourCompletedStyle(tourId
 }
 
 add_task(async function test_hide_onboarding_tours() {
   resetOnboardingDefaultState();
 
   let tourIds = TOUR_IDs;
   let tabs = [];
   for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+    let tab = await openTab(url);
     await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
     await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
     await promiseOnboardingOverlayOpened(tab.linkedBrowser);
     tabs.push(tab);
   }
 
   let expectedPrefUpdates = [
     promisePrefUpdated("browser.onboarding.hidden", true),
@@ -59,18 +60,17 @@ add_task(async function test_hide_onboar
 });
 
 add_task(async function test_click_action_button_to_set_tour_completed() {
   resetOnboardingDefaultState();
 
   let tourIds = TOUR_IDs;
   let tabs = [];
   for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+    let tab = await openTab(url);
     await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
     await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
     await promiseOnboardingOverlayOpened(tab.linkedBrowser);
     tabs.push(tab);
   }
 
   let completedTourId = tourIds[0];
   let expectedPrefUpdate = promisePrefUpdated(`browser.onboarding.tour.${completedTourId}.completed`, true);
@@ -81,30 +81,28 @@ add_task(async function test_click_actio
     let tab = tabs[i];
     for (let id of tourIds) {
       await assertTourCompletedStyle(id, id == completedTourId, tab.linkedBrowser);
     }
     await BrowserTestUtils.removeTab(tab);
   }
 });
 
-
 add_task(async function test_set_right_tour_completed_style_on_overlay() {
   resetOnboardingDefaultState();
 
   let tourIds = TOUR_IDs;
   // Make the tours of even number as completed
   for (let i = 0; i < tourIds.length; ++i) {
     setTourCompletedState(tourIds[i], i % 2 == 0);
   }
 
   let tabs = [];
   for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+    let tab = await openTab(url);
     await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
     await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
     await promiseOnboardingOverlayOpened(tab.linkedBrowser);
     tabs.push(tab);
   }
 
   for (let i = tabs.length - 1; i >= 0; --i) {
     let tab = tabs[i];
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
@@ -1,36 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+requestLongerTimeout(2);
+
 add_task(async function test_onboarding_default_new_tourset() {
   resetOnboardingDefaultState();
-  let tabs = [];
-  for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
-    await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
-    await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
-    await promiseOnboardingOverlayOpened(tab.linkedBrowser);
-    tabs.push(tab);
-  }
+
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, TOUR_IDs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(TOUR_IDs[idx], dom.id, "contain defined onboarding id");
   });
 
-  for (let i = tabs.length - 1; i >= 0; --i) {
-    let tab = tabs[i];
-    await BrowserTestUtils.removeTab(tab);
-  }
+  await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_onboarding_custom_new_tourset() {
   const CUSTOM_NEW_TOURs = [
     "onboarding-tour-private-browsing",
     "onboarding-tour-addons",
     "onboarding-tour-customize",
   ];
@@ -38,67 +33,51 @@ add_task(async function test_onboarding_
   resetOnboardingDefaultState();
   await SpecialPowers.pushPrefEnv({set: [
     ["browser.onboarding.tour-type", "new"],
     ["browser.onboarding.tourset-version", 1],
     ["browser.onboarding.seen-tourset-version", 1],
     ["browser.onboarding.newtour", "private,addons,customize"],
   ]});
 
-  let tabs = [];
-  for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
-    await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
-    await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
-    await promiseOnboardingOverlayOpened(tab.linkedBrowser);
-    tabs.push(tab);
-  }
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, CUSTOM_NEW_TOURs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(CUSTOM_NEW_TOURs[idx], dom.id, "contain defined onboarding id");
   });
 
-  for (let i = tabs.length - 1; i >= 0; --i) {
-    let tab = tabs[i];
-    await BrowserTestUtils.removeTab(tab);
-  }
+  await BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_onboarding_custom_update_tourset() {
   const CUSTOM_UPDATE_TOURs = [
     "onboarding-tour-customize",
     "onboarding-tour-private-browsing",
     "onboarding-tour-addons",
   ];
   resetOnboardingDefaultState();
   await SpecialPowers.pushPrefEnv({set: [
     ["browser.onboarding.tour-type", "update"],
     ["browser.onboarding.tourset-version", 1],
     ["browser.onboarding.seen-tourset-version", 1],
     ["browser.onboarding.updatetour", "customize,private,addons"],
   ]});
 
-  let tabs = [];
-  for (let url of URLs) {
-    let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
-    await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
-    await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
-    await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
-    await promiseOnboardingOverlayOpened(tab.linkedBrowser);
-    tabs.push(tab);
-  }
+  let tab = await openTab(ABOUT_NEWTAB_URL);
+  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+  await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
 
   let doc = content && content.document;
   let doms = doc.querySelectorAll(".onboarding-tour-item");
   is(doms.length, CUSTOM_UPDATE_TOURs.length, "has exact tour numbers");
   doms.forEach((dom, idx) => {
     is(CUSTOM_UPDATE_TOURs[idx], dom.id, "contain defined onboarding id");
   });
 
-  for (let i = tabs.length - 1; i >= 0; --i) {
-    let tab = tabs[i];
-    await BrowserTestUtils.removeTab(tab);
-  }
+  await BrowserTestUtils.removeTab(tab);
 });
--- a/browser/extensions/onboarding/test/browser/head.js
+++ b/browser/extensions/onboarding/test/browser/head.js
@@ -32,37 +32,53 @@ function resetOnboardingDefaultState() {
   Preferences.reset("browser.onboarding.notification.tour-ids-queue");
   TOUR_IDs.forEach(id => Preferences.reset(`browser.onboarding.tour.${id}.completed`));
 }
 
 function setTourCompletedState(tourId, state) {
   Preferences.set(`browser.onboarding.tour.${tourId}.completed`, state);
 }
 
+async function openTab(url) {
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+  let loadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+  await loadedPromise;
+  return tab;
+}
+
+function reloadTab(tab) {
+  let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  tab.linkedBrowser.reload();
+  return reloadPromise;
+}
+
 function promiseOnboardingOverlayLoaded(browser) {
-  // The onboarding overlay is init inside window.requestIdleCallback, not immediately,
-  // so we use check conditions here.
-  let condition = () => {
-    return ContentTask.spawn(browser, {}, function() {
-      return new Promise(resolve => {
-        let doc = content && content.document;
-        if (doc && doc.querySelector("#onboarding-overlay")) {
-          resolve(true);
-          return;
-        }
-        resolve(false);
+  function isLoaded() {
+    let doc = content && content.document;
+    if (doc.querySelector("#onboarding-overlay")) {
+      ok(true, "Should load onboarding overlay");
+      return Promise.resolve();
+    }
+    return new Promise(resolve => {
+      let observer = new content.MutationObserver(mutations => {
+        mutations.forEach(mutation => {
+          let overlay = Array.from(mutation.addedNodes)
+                             .find(node => node.id == "onboarding-overlay");
+          if (overlay) {
+            observer.disconnect();
+            ok(true, "Should load onboarding overlay");
+            resolve();
+          }
+        });
       });
-    })
-  };
-  return BrowserTestUtils.waitForCondition(
-    condition,
-    "Should load onboarding overlay",
-    100,
-    50 // Bug 1381335 increased retries, so debug builds can trigger idle in time
-  );
+      observer.observe(doc.body, { childList: true });
+    });
+  }
+  return ContentTask.spawn(browser, {}, isLoaded);
 }
 
 function promiseOnboardingOverlayOpened(browser) {
   let condition = () => {
     return ContentTask.spawn(browser, {}, function() {
       return new Promise(resolve => {
         let overlay = content.document.querySelector("#onboarding-overlay");
         if (overlay.classList.contains("onboarding-opened")) {
@@ -88,34 +104,39 @@ function promisePrefUpdated(name, expect
       is(expectedValue, actualValue, `Should update the pref of ${name}`);
       resolve();
     };
     Preferences.observe(name, onUpdate);
   });
 }
 
 function promiseTourNotificationOpened(browser) {
-  let condition = () => {
-    return ContentTask.spawn(browser, {}, function() {
-      return new Promise(resolve => {
-        let bar = content.document.querySelector("#onboarding-notification-bar");
-        if (bar && bar.classList.contains("onboarding-opened")) {
-          resolve(true);
-          return;
-        }
-        resolve(false);
+  function isOpened() {
+    let doc = content && content.document;
+    let notification = doc.querySelector("#onboarding-notification-bar");
+    if (notification && notification.classList.contains("onboarding-opened")) {
+      ok(true, "Should open tour notification");
+      return Promise.resolve();
+    }
+    return new Promise(resolve => {
+      let observer = new content.MutationObserver(mutations => {
+        mutations.forEach(mutation => {
+          let bar = Array.from(mutation.addedNodes)
+                         .find(node => node.id == "onboarding-notification-bar");
+          if (bar && bar.classList.contains("onboarding-opened")) {
+            observer.disconnect();
+            ok(true, "Should open tour notification");
+            resolve();
+          }
+        });
       });
-    })
-  };
-  return BrowserTestUtils.waitForCondition(
-    condition,
-    "Should open tour notification",
-    100,
-    30
-  );
+      observer.observe(doc.body, { childList: true });
+    });
+  }
+  return ContentTask.spawn(browser, {}, isOpened);
 }
 
 function promiseTourNotificationClosed(browser) {
   let condition = () => {
     return ContentTask.spawn(browser, {}, function() {
       return new Promise(resolve => {
         let bar = content.document.querySelector("#onboarding-notification-bar");
         if (bar && !bar.classList.contains("onboarding-opened")) {