Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function () {
let tab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:blank?1"
);
let tab2 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:blank?2"
);
gBrowser.selectedTab = tab1;
async function background() {
function promiseUpdated(tabId, attr) {
return new Promise(resolve => {
let onUpdated = (tabId_, changeInfo, tab) => {
if (tabId == tabId_ && attr in changeInfo) {
browser.tabs.onUpdated.removeListener(onUpdated);
resolve({ changeInfo, tab });
}
};
browser.tabs.onUpdated.addListener(onUpdated);
});
}
let deferred = {};
browser.test.onMessage.addListener((message, tabId, result) => {
if (message == "change-tab-done" && deferred[tabId]) {
deferred[tabId].resolve(result);
}
});
function changeTab(tabId, attr, on) {
return new Promise((resolve, reject) => {
deferred[tabId] = { resolve, reject };
browser.test.sendMessage("change-tab", tabId, attr, on);
});
}
try {
let tabs = await browser.tabs.query({ lastFocusedWindow: true });
browser.test.assertEq(tabs.length, 3, "We have three tabs");
for (let tab of tabs) {
// Note: We want to check that these are actual boolean values, not
// just that they evaluate as false.
browser.test.assertEq(false, tab.mutedInfo.muted, "Tab is not muted");
browser.test.assertEq(
undefined,
tab.mutedInfo.reason,
"Tab has no muted info reason"
);
browser.test.assertEq(false, tab.audible, "Tab is not audible");
}
let windowId = tabs[0].windowId;
let tabIds = [tabs[1].id, tabs[2].id];
browser.test.log(
"Test initial queries for muted and audible return no tabs"
);
let silent = await browser.tabs.query({ windowId, audible: false });
let audible = await browser.tabs.query({ windowId, audible: true });
let muted = await browser.tabs.query({ windowId, muted: true });
let nonMuted = await browser.tabs.query({ windowId, muted: false });
browser.test.assertEq(3, silent.length, "Three silent tabs");
browser.test.assertEq(0, audible.length, "No audible tabs");
browser.test.assertEq(0, muted.length, "No muted tabs");
browser.test.assertEq(3, nonMuted.length, "Three non-muted tabs");
browser.test.log(
"Toggle muted and audible externally on one tab each, and check results"
);
[muted, audible] = await Promise.all([
promiseUpdated(tabIds[0], "mutedInfo"),
promiseUpdated(tabIds[1], "audible"),
changeTab(tabIds[0], "muted", true),
changeTab(tabIds[1], "audible", true),
]);
for (let obj of [muted.changeInfo, muted.tab]) {
browser.test.assertEq(true, obj.mutedInfo.muted, "Tab is muted");
browser.test.assertEq(
"user",
obj.mutedInfo.reason,
"Tab was muted by the user"
);
}
browser.test.assertEq(
true,
audible.changeInfo.audible,
"Tab audible state changed"
);
browser.test.assertEq(true, audible.tab.audible, "Tab is audible");
browser.test.log(
"Re-check queries. Expect one audible and one muted tab"
);
silent = await browser.tabs.query({ windowId, audible: false });
audible = await browser.tabs.query({ windowId, audible: true });
muted = await browser.tabs.query({ windowId, muted: true });
nonMuted = await browser.tabs.query({ windowId, muted: false });
browser.test.assertEq(2, silent.length, "Two silent tabs");
browser.test.assertEq(1, audible.length, "One audible tab");
browser.test.assertEq(1, muted.length, "One muted tab");
browser.test.assertEq(2, nonMuted.length, "Two non-muted tabs");
browser.test.assertEq(true, muted[0].mutedInfo.muted, "Tab is muted");
browser.test.assertEq(
"user",
muted[0].mutedInfo.reason,
"Tab was muted by the user"
);
browser.test.assertEq(true, audible[0].audible, "Tab is audible");
browser.test.log(
"Toggle muted internally on two tabs, and check results"
);
[nonMuted, muted] = await Promise.all([
promiseUpdated(tabIds[0], "mutedInfo"),
promiseUpdated(tabIds[1], "mutedInfo"),
browser.tabs.update(tabIds[0], { muted: false }),
browser.tabs.update(tabIds[1], { muted: true }),
]);
for (let obj of [nonMuted.changeInfo, nonMuted.tab]) {
browser.test.assertEq(false, obj.mutedInfo.muted, "Tab is not muted");
}
for (let obj of [muted.changeInfo, muted.tab]) {
browser.test.assertEq(true, obj.mutedInfo.muted, "Tab is muted");
}
for (let obj of [
nonMuted.changeInfo,
nonMuted.tab,
muted.changeInfo,
muted.tab,
]) {
browser.test.assertEq(
"extension",
obj.mutedInfo.reason,
"Mute state changed by extension"
);
browser.test.assertEq(
browser.runtime.id,
obj.mutedInfo.extensionId,
"Mute state changed by extension"
);
}
browser.test.log("Test that mutedInfo is preserved by sessionstore");
let tab = await changeTab(tabIds[1], "duplicate").then(browser.tabs.get);
browser.test.assertEq(true, tab.mutedInfo.muted, "Tab is muted");
browser.test.assertEq(
"extension",
tab.mutedInfo.reason,
"Mute state changed by extension"
);
browser.test.assertEq(
browser.runtime.id,
tab.mutedInfo.extensionId,
"Mute state changed by extension"
);
browser.test.log("Unmute externally, and check results");
[nonMuted] = await Promise.all([
promiseUpdated(tabIds[1], "mutedInfo"),
changeTab(tabIds[1], "muted", false),
browser.tabs.remove(tab.id),
]);
for (let obj of [nonMuted.changeInfo, nonMuted.tab]) {
browser.test.assertEq(false, obj.mutedInfo.muted, "Tab is not muted");
browser.test.assertEq(
"user",
obj.mutedInfo.reason,
"Mute state changed by user"
);
}
browser.test.notifyPass("tab-audio");
} catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);
browser.test.notifyFail("tab-audio");
}
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["tabs"],
},
background,
});
extension.onMessage("change-tab", (tabId, attr, on) => {
const {
Management: {
global: { tabTracker },
},
} = ChromeUtils.importESModule("resource://gre/modules/Extension.sys.mjs");
let tab = tabTracker.getTab(tabId);
if (attr == "muted") {
// Ideally we'd simulate a click on the tab audio icon for this, but the
// handler relies on CSS :hover states, which are complicated and fragile
// to simulate.
if (tab.muted != on) {
tab.toggleMuteAudio();
}
} else if (attr == "audible") {
let browser = tab.linkedBrowser;
if (on) {
browser.audioPlaybackStarted();
} else {
browser.audioPlaybackStopped();
}
} else if (attr == "duplicate") {
// This is a bit of a hack. It won't be necessary once we have
// `tabs.duplicate`.
let newTab = gBrowser.duplicateTab(tab);
BrowserTestUtils.waitForEvent(newTab, "SSTabRestored", () => true).then(
() => {
extension.sendMessage(
"change-tab-done",
tabId,
tabTracker.getId(newTab)
);
}
);
return;
}
extension.sendMessage("change-tab-done", tabId);
});
await extension.startup();
await extension.awaitFinish("tab-audio");
await extension.unload();
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab2);
});