Bug 1383070 - Intermittent: Uncaught exception Should load onboarding overlay, r=mossop draft
authorFischer.json <fischer.json@gmail.com>
Sat, 22 Jul 2017 23:40:01 +0800
changeset 617260 77de15e49f686bfa7d9a5529e563331cf93e51a8
parent 614808 dcfb58fcb6dd8f6474eed6520ba6272dedded393
child 639769 1949bbfb98e4360d26689121bbe1233a46ec11c1
push id71002
push userbmo:fliu@mozilla.com
push dateFri, 28 Jul 2017 08:18:31 +0000
reviewersmossop
bugs1383070
milestone56.0a1
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)
       });
@@ -877,14 +876,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")) {