Bug 1470677 - Undo duplication in browser_multiselect_tabs_mute_unmute.js test file by moving browser_audioTabIcon.js to /browser/base/content/test/tabs directory. r=jaws
authorAbdoulaye O. Ly <ablayelyfondou@gmail.com>
Wed, 27 Jun 2018 05:21:59 +0000
changeset 423965 cd9f6f1e04d21173b5e94b5fbc7f7c39309e2e5f
parent 423964 fd3d6fae1c8fd8660b1c7f55d2a42f36bc1292cb
child 423966 2cc73c7d2c75fa46261ab18d8992181eb60d8fa1
push id34197
push usercsabou@mozilla.com
push dateThu, 28 Jun 2018 09:44:02 +0000
treeherdermozilla-central@db455160668d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1470677
milestone63.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 1470677 - Undo duplication in browser_multiselect_tabs_mute_unmute.js test file by moving browser_audioTabIcon.js to /browser/base/content/test/tabs directory. r=jaws MozReview-Commit-ID: 6psjZW3bdNG
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_audioTabIcon.js
browser/base/content/test/general/file_mediaPlayback.html
browser/base/content/test/tabs/browser.ini
browser/base/content/test/tabs/browser_audioTabIcon.js
browser/base/content/test/tabs/browser_multiselect_tabs_mute_unmute.js
browser/base/content/test/tabs/file_mediaPlayback.html
browser/base/content/test/tabs/head.js
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -32,17 +32,16 @@ support-files =
   discovery.html
   download_page.html
   download_page_1.txt
   download_page_2.txt
   dummy_page.html
   feed_tab.html
   file_generic_favicon.ico
   file_with_favicon.html
-  file_mediaPlayback.html
   file_bug970276_popup1.html
   file_bug970276_popup2.html
   file_bug970276_favicon1.ico
   file_bug970276_favicon2.ico
   file_documentnavigation_frameset.html
   file_double_close_tab.html
   file_favicon_change.html
   file_favicon_change_not_in_document.html
@@ -77,19 +76,16 @@ support-files =
   !/toolkit/content/tests/browser/common/mockTransfer.js
   !/toolkit/modules/tests/browser/metadata_*.html
 
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_addKeywordSearch.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_alltabslistener.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_audioTabIcon.js]
-tags = audiochannel
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_backButtonFitts.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_beforeunload_duplicate_dialogs.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_blob-channelname.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bookmark_popup.js]
 skip-if = (os == "linux" && debug) || (verify && (os == 'win')) # mouseover not reliable on linux debug builds
deleted file mode 100644
--- a/browser/base/content/test/general/file_mediaPlayback.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<audio src="audio.ogg" controls loop>
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,32 +1,33 @@
 [DEFAULT]
 support-files =
   head.js
   dummy_page.html
+  ../general/audio.ogg
+  file_mediaPlayback.html
 
 [browser_abandonment_telemetry.js]
 [browser_accessibility_indicator.js]
 skip-if = (verify && debug && (os == 'linux'))
 [browser_allow_process_switches_despite_related_browser.js]
+[browser_audioTabIcon.js]
+tags = audiochannel
 [browser_bug_1387976_restore_lazy_tab_browser_muted_state.js]
 [browser_bug580956.js]
 [browser_close_tab_by_dblclick.js]
 [browser_contextmenu_openlink_after_tabnavigated.js]
 skip-if = (verify && debug && (os == 'linux'))
 support-files =
   test_bug1358314.html
 [browser_isLocalAboutURI.js]
 [browser_multiselect_tabs_active_tab_selected_by_default.js]
 [browser_multiselect_tabs_close_using_shortcuts.js]
 [browser_multiselect_tabs_close.js]
 [browser_multiselect_tabs_mute_unmute.js]
-support-files =
-  ../general/audio.ogg
-  ../general/file_mediaPlayback.html
 [browser_multiselect_tabs_positional_attrs.js]
 [browser_multiselect_tabs_using_Ctrl.js]
 [browser_multiselect_tabs_using_Shift.js]
 [browser_navigatePinnedTab.js]
 [browser_new_file_whitelisted_http_tab.js]
 skip-if = !e10s # Test only relevant for e10s.
 [browser_new_tab_insert_position.js]
 skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
rename from browser/base/content/test/general/browser_audioTabIcon.js
rename to browser/base/content/test/tabs/browser_audioTabIcon.js
--- a/browser/base/content/test/general/browser_audioTabIcon.js
+++ b/browser/base/content/test/tabs/browser_audioTabIcon.js
@@ -1,53 +1,13 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
-const PAGE = "https://example.com/browser/browser/base/content/test/general/file_mediaPlayback.html";
+const PAGE = "https://example.com/browser/browser/base/content/test/tabs/file_mediaPlayback.html";
 const TABATTR_REMOVAL_PREFNAME = "browser.tabs.delayHidingAudioPlayingIconMS";
 const INITIAL_TABATTR_REMOVAL_DELAY_MS = Services.prefs.getIntPref(TABATTR_REMOVAL_PREFNAME);
 
-async function wait_for_tab_playing_event(tab, expectPlaying) {
-  if (tab.soundPlaying == expectPlaying) {
-    ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-    return true;
-  }
-  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
-    if (event.detail.changed.includes("soundplaying")) {
-      is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-      is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-      return true;
-    }
-    return false;
-  });
-}
-
-async function is_audio_playing(tab) {
-  let browser = tab.linkedBrowser;
-  let isPlaying = await ContentTask.spawn(browser, {}, async function() {
-    let audio = content.document.querySelector("audio");
-    return !audio.paused;
-  });
-  return isPlaying;
-}
-
-async function play(tab) {
-  let browser = tab.linkedBrowser;
-  await ContentTask.spawn(browser, {}, async function() {
-    let audio = content.document.querySelector("audio");
-    audio.play();
-  });
-
-  // If the tab has already be muted, it means the tab won't get soundplaying,
-  // so we don't need to check this attribute.
-  if (browser.audioMuted) {
-      return;
-  }
-
-  await wait_for_tab_playing_event(tab, true);
-}
-
 async function pause(tab, options) {
   let extendedDelay = options && options.extendedDelay;
   if (extendedDelay) {
     // Use 10s to remove possibility of race condition with attr removal.
     Services.prefs.setIntPref(TABATTR_REMOVAL_PREFNAME, 10000);
   }
 
   try {
@@ -90,103 +50,32 @@ async function hide_tab(tab) {
 }
 
 async function show_tab(tab) {
   let tabShown = BrowserTestUtils.waitForEvent(tab, "TabShow");
   gBrowser.showTab(tab);
   return tabShown;
 }
 
-function disable_non_test_mouse(disable) {
-  let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-  utils.disableNonTestMouseEvents(disable);
-}
-
-function hover_icon(icon, tooltip) {
-  disable_non_test_mouse(true);
-
-  let popupShownPromise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
-  EventUtils.synthesizeMouse(icon, 1, 1, {type: "mouseover"});
-  EventUtils.synthesizeMouse(icon, 2, 2, {type: "mousemove"});
-  EventUtils.synthesizeMouse(icon, 3, 3, {type: "mousemove"});
-  EventUtils.synthesizeMouse(icon, 4, 4, {type: "mousemove"});
-  return popupShownPromise;
-}
-
-function leave_icon(icon) {
-  EventUtils.synthesizeMouse(icon, 0, 0, {type: "mouseout"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-
-  disable_non_test_mouse(false);
-}
-
 async function test_tooltip(icon, expectedTooltip, isActiveTab) {
   let tooltip = document.getElementById("tabbrowser-tab-tooltip");
 
   await hover_icon(icon, tooltip);
   if (isActiveTab) {
     // The active tab should have the keybinding shortcut in the tooltip.
     // We check this by ensuring that the strings are not equal but the expected
     // message appears in the beginning.
     isnot(tooltip.getAttribute("label"), expectedTooltip, "Tooltips should not be equal");
     is(tooltip.getAttribute("label").indexOf(expectedTooltip), 0, "Correct tooltip expected");
   } else {
     is(tooltip.getAttribute("label"), expectedTooltip, "Tooltips should not be equal");
   }
   leave_icon(icon);
 }
 
-// The set of tabs which have ever had their mute state changed.
-// Used to determine whether the tab should have a muteReason value.
-let everMutedTabs = new WeakSet();
-
-function get_wait_for_mute_promise(tab, expectMuted) {
-  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, event => {
-    if (event.detail.changed.includes("muted")) {
-      is(tab.hasAttribute("muted"), expectMuted, "The tab should " + (expectMuted ? "" : "not ") + "be muted");
-      is(tab.muted, expectMuted, "The tab muted property " + (expectMuted ? "" : "not ") + "be true");
-
-      if (expectMuted || everMutedTabs.has(tab)) {
-        everMutedTabs.add(tab);
-        is(tab.muteReason, null, "The tab should have a null muteReason value");
-      } else {
-        is(tab.muteReason, undefined, "The tab should have an undefined muteReason value");
-      }
-      return true;
-    }
-    return false;
-  });
-}
-
-async function test_mute_tab(tab, icon, expectMuted) {
-  let mutedPromise = get_wait_for_mute_promise(tab, expectMuted);
-
-  let activeTab = gBrowser.selectedTab;
-
-  let tooltip = document.getElementById("tabbrowser-tab-tooltip");
-
-  await hover_icon(icon, tooltip);
-  EventUtils.synthesizeMouseAtCenter(icon, {button: 0});
-  leave_icon(icon);
-
-  is(gBrowser.selectedTab, activeTab, "Clicking on mute should not change the currently selected tab");
-
-  // If the audio is playing, we should check whether clicking on icon affects
-  // the media element's playing state.
-  let isAudioPlaying = await is_audio_playing(tab);
-  if (isAudioPlaying) {
-    await wait_for_tab_playing_event(tab, !expectMuted);
-  }
-
-  return mutedPromise;
-}
-
 function get_tab_state(tab) {
   return JSON.parse(SessionStore.getTabState(tab));
 }
 
 async function test_muting_using_menu(tab, expectMuted) {
   // Show the popup menu
   let contextMenu = document.getElementById("tabContextMenu");
   let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
--- a/browser/base/content/test/tabs/browser_multiselect_tabs_mute_unmute.js
+++ b/browser/base/content/test/tabs/browser_multiselect_tabs_mute_unmute.js
@@ -1,132 +1,10 @@
 const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
-const PAGE = "https://example.com/browser/browser/base/content/test/general/file_mediaPlayback.html";
-
-async function wait_for_tab_playing_event(tab, expectPlaying) {
-  if (tab.soundPlaying == expectPlaying) {
-    ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-    return true;
-  }
-  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
-    if (event.detail.changed.includes("soundplaying")) {
-      is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-      is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
-      return true;
-    }
-    return false;
-  });
-}
-
-async function waitForTabMuteStateChangeEvent(tab) {
-  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
-    for (let attr of ["activemedia-blocked", "muted", "soundplaying"]) {
-      if (event.detail.changed.includes(attr)) {
-        return true;
-      }
-    }
-    return false;
-  });
-}
-
-async function is_audio_playing(tab) {
-  let browser = tab.linkedBrowser;
-  let isPlaying = await ContentTask.spawn(browser, {}, async function() {
-    let audio = content.document.querySelector("audio");
-    return !audio.paused;
-  });
-  return isPlaying;
-}
-
-async function play(tab) {
-  let browser = tab.linkedBrowser;
-  await ContentTask.spawn(browser, {}, async function() {
-    let audio = content.document.querySelector("audio");
-    audio.play();
-  });
-
-  // If the tab has already been muted, it means the tab won't get soundplaying,
-  // so we don't need to check this attribute.
-  if (browser.audioMuted) {
-    return;
-  }
-
-  await waitForTabMuteStateChangeEvent(tab);
-}
-
-function disable_non_test_mouse(disable) {
-  let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-  utils.disableNonTestMouseEvents(disable);
-}
-
-function hover_icon(icon, tooltip) {
-  disable_non_test_mouse(true);
-
-  let popupShownPromise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
-  EventUtils.synthesizeMouse(icon, 1, 1, {type: "mouseover"});
-  EventUtils.synthesizeMouse(icon, 2, 2, {type: "mousemove"});
-  EventUtils.synthesizeMouse(icon, 3, 3, {type: "mousemove"});
-  EventUtils.synthesizeMouse(icon, 4, 4, {type: "mousemove"});
-  return popupShownPromise;
-}
-
-function leave_icon(icon) {
-  EventUtils.synthesizeMouse(icon, 0, 0, {type: "mouseout"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-
-  disable_non_test_mouse(false);
-}
-
-// The set of tabs which have ever had their mute state changed.
-// Used to determine whether the tab should have a muteReason value.
-let everMutedTabs = new WeakSet();
-
-function get_wait_for_mute_promise(tab, expectMuted) {
-  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, event => {
-    if (event.detail.changed.includes("muted") || event.detail.changed.includes("activemedia-blocked")) {
-      is(tab.hasAttribute("muted"), expectMuted, "The tab should " + (expectMuted ? "" : "not ") + "be muted");
-      is(tab.muted, expectMuted, "The tab muted property " + (expectMuted ? "" : "not ") + "be true");
-
-      if (expectMuted || everMutedTabs.has(tab)) {
-        everMutedTabs.add(tab);
-        is(tab.muteReason, null, "The tab should have a null muteReason value");
-      } else {
-        is(tab.muteReason, undefined, "The tab should have an undefined muteReason value");
-      }
-      return true;
-    }
-    return false;
-  });
-}
-
-async function test_mute_tab(tab, icon, expectMuted) {
-  let mutedPromise = waitForTabMuteStateChangeEvent(tab);
-
-  let activeTab = gBrowser.selectedTab;
-
-  let tooltip = document.getElementById("tabbrowser-tab-tooltip");
-
-  await hover_icon(icon, tooltip);
-  EventUtils.synthesizeMouseAtCenter(icon, {button: 0});
-  leave_icon(icon);
-
-  is(gBrowser.selectedTab, activeTab, "Clicking on mute should not change the currently selected tab");
-
-  // If the audio is playing, we should check whether clicking on icon affects
-  // the media element's playing state.
-  let isAudioPlaying = await is_audio_playing(tab);
-  if (isAudioPlaying) {
-    await wait_for_tab_playing_event(tab, !expectMuted);
-  }
-
-  return mutedPromise;
-}
+const PAGE = "https://example.com/browser/browser/base/content/test/tabs/file_mediaPlayback.html";
 
 function muted(tab) {
   return tab.linkedBrowser.audioMuted;
 }
 
 function activeMediaBlocked(tab) {
   return tab.activeMediaBlocked;
 }
@@ -150,18 +28,18 @@ add_task(async function muteTabs_usingBu
   let tab2 = await addMediaTab();
   let tab3 = await addMediaTab();
   let tab4 = await addMediaTab();
 
   let tabs = [tab0, tab1, tab2, tab3, tab4];
 
   await BrowserTestUtils.switchTab(gBrowser, tab0);
   await play(tab0);
-  await play(tab1);
-  await play(tab2);
+  await play(tab1, false);
+  await play(tab2, false);
 
   // Multiselecting tab1, tab2 and tab3
   await BrowserTestUtils.switchTab(gBrowser, tab1);
   await triggerClickOn(tab3, { shiftKey: true });
 
   is(gBrowser.multiSelectedTabsCount, 3, "Three multiselected tabs");
   ok(!tab0.multiselected, "Tab0 is not multiselected");
   ok(!tab4.multiselected, "Tab4 is not multiselected");
@@ -229,18 +107,18 @@ add_task(async function unmuteTabs_using
   let tab2 = await addMediaTab();
   let tab3 = await addMediaTab();
   let tab4 = await addMediaTab();
 
   let tabs = [tab0, tab1, tab2, tab3, tab4];
 
   await BrowserTestUtils.switchTab(gBrowser, tab0);
   await play(tab0);
-  await play(tab1);
-  await play(tab2);
+  await play(tab1, false);
+  await play(tab2, false);
 
   // Mute tab3 and tab4
   tab3.toggleMuteAudio();
   tab4.toggleMuteAudio();
 
   // Multiselecting tab0, tab1, tab2 and tab3
   await triggerClickOn(tab3, { shiftKey: true });
 
@@ -285,18 +163,18 @@ add_task(async function playTabs_usingBu
   let tab2 = await addMediaTab();
   let tab3 = await addMediaTab();
   let tab4 = await addMediaTab();
 
   let tabs = [tab0, tab1, tab2, tab3, tab4];
 
   await BrowserTestUtils.switchTab(gBrowser, tab0);
   await play(tab0);
-  await play(tab1);
-  await play(tab2);
+  await play(tab1, false);
+  await play(tab2, false);
 
   // Multiselecting tab0, tab1, tab2 and tab3.
   await triggerClickOn(tab3, { shiftKey: true });
 
   // Mute tab0 and tab4
   tab0.toggleMuteAudio();
   tab4.toggleMuteAudio();
 
@@ -341,19 +219,19 @@ add_task(async function checkTabContextM
   let tab1 = await addMediaTab();
   let tab2 = await addMediaTab();
   let tab3 = await addMediaTab();
   let tabs = [tab0, tab1, tab2, tab3];
 
   let menuItemToggleMuteTab = document.getElementById("context_toggleMuteTab");
   let menuItemToggleMuteSelectedTabs = document.getElementById("context_toggleMuteSelectedTabs");
 
-  await play(tab0);
+  await play(tab0, false);
   tab0.toggleMuteAudio();
-  await play(tab1);
+  await play(tab1, false);
   tab2.toggleMuteAudio();
 
   // Mutliselect tab0, tab1, tab2.
   await triggerClickOn(tab0, { ctrlKey: true });
   await triggerClickOn(tab1, { ctrlKey: true });
   await triggerClickOn(tab2, { ctrlKey: true });
 
   // Check mutliselected tabs
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/file_mediaPlayback.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<audio src="audio.ogg" controls loop>
--- a/browser/base/content/test/tabs/head.js
+++ b/browser/base/content/test/tabs/head.js
@@ -23,8 +23,138 @@ function triggerClickOn(target, options)
 
 async function addTab() {
   const tab = BrowserTestUtils.addTab(gBrowser,
       "http://mochi.test:8888/", { skipAnimation: true });
   const browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
   return tab;
 }
+
+async function wait_for_tab_playing_event(tab, expectPlaying) {
+  if (tab.soundPlaying == expectPlaying) {
+    ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+    return true;
+  }
+  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
+    if (event.detail.changed.includes("soundplaying")) {
+      is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+      is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+      return true;
+    }
+    return false;
+  });
+}
+
+async function wait_for_tab_media_blocked_event(tab, expectMediaBlocked) {
+  if (tab.activeMediaBlocked == expectMediaBlocked) {
+    ok(true, "The tab should " + (expectMediaBlocked ? "" : "not ") + "be activemedia-blocked");
+    return true;
+  }
+  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
+    if (event.detail.changed.includes("activemedia-blocked")) {
+      is(tab.hasAttribute("activemedia-blocked"), expectMediaBlocked, "The tab should " + (expectMediaBlocked ? "" : "not ") + "be activemedia-blocked");
+      is(tab.activeMediaBlocked, expectMediaBlocked, "The tab should " + (expectMediaBlocked ? "" : "not ") + "be activemedia-blocked");
+      return true;
+    }
+    return false;
+  });
+}
+
+async function is_audio_playing(tab) {
+  let browser = tab.linkedBrowser;
+  let isPlaying = await ContentTask.spawn(browser, {}, async function() {
+    let audio = content.document.querySelector("audio");
+    return !audio.paused;
+  });
+  return isPlaying;
+}
+
+async function play(tab, expectPlaying = true) {
+  let browser = tab.linkedBrowser;
+  await ContentTask.spawn(browser, {}, async function() {
+    let audio = content.document.querySelector("audio");
+    audio.play();
+  });
+
+  // If the tab has already been muted, it means the tab won't get soundplaying,
+  // so we don't need to check this attribute.
+  if (browser.audioMuted) {
+    return;
+  }
+
+  if (expectPlaying) {
+    await wait_for_tab_playing_event(tab, true);
+  } else {
+    await wait_for_tab_media_blocked_event(tab, true);
+  }
+}
+
+function disable_non_test_mouse(disable) {
+  let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIDOMWindowUtils);
+  utils.disableNonTestMouseEvents(disable);
+}
+
+function hover_icon(icon, tooltip) {
+  disable_non_test_mouse(true);
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
+  EventUtils.synthesizeMouse(icon, 1, 1, {type: "mouseover"});
+  EventUtils.synthesizeMouse(icon, 2, 2, {type: "mousemove"});
+  EventUtils.synthesizeMouse(icon, 3, 3, {type: "mousemove"});
+  EventUtils.synthesizeMouse(icon, 4, 4, {type: "mousemove"});
+  return popupShownPromise;
+}
+
+function leave_icon(icon) {
+  EventUtils.synthesizeMouse(icon, 0, 0, {type: "mouseout"});
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
+
+  disable_non_test_mouse(false);
+}
+
+// The set of tabs which have ever had their mute state changed.
+// Used to determine whether the tab should have a muteReason value.
+let everMutedTabs = new WeakSet();
+
+function get_wait_for_mute_promise(tab, expectMuted) {
+  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, event => {
+    if (event.detail.changed.includes("muted") || event.detail.changed.includes("activemedia-blocked")) {
+      is(tab.hasAttribute("muted"), expectMuted, "The tab should " + (expectMuted ? "" : "not ") + "be muted");
+      is(tab.muted, expectMuted, "The tab muted property " + (expectMuted ? "" : "not ") + "be true");
+
+      if (expectMuted || everMutedTabs.has(tab)) {
+        everMutedTabs.add(tab);
+        is(tab.muteReason, null, "The tab should have a null muteReason value");
+      } else {
+        is(tab.muteReason, undefined, "The tab should have an undefined muteReason value");
+      }
+      return true;
+    }
+    return false;
+  });
+}
+
+async function test_mute_tab(tab, icon, expectMuted) {
+  let mutedPromise = get_wait_for_mute_promise(tab, expectMuted);
+
+  let activeTab = gBrowser.selectedTab;
+
+  let tooltip = document.getElementById("tabbrowser-tab-tooltip");
+
+  await hover_icon(icon, tooltip);
+  EventUtils.synthesizeMouseAtCenter(icon, {button: 0});
+  leave_icon(icon);
+
+  is(gBrowser.selectedTab, activeTab, "Clicking on mute should not change the currently selected tab");
+
+  // If the audio is playing, we should check whether clicking on icon affects
+  // the media element's playing state.
+  let isAudioPlaying = await is_audio_playing(tab);
+  if (isAudioPlaying) {
+    await wait_for_tab_playing_event(tab, !expectMuted);
+  }
+
+  return mutedPromise;
+}