Bug 1755763 - Update browserAction.openPopup API r=geckoview-reviewers,robwu,owlish

To align with other browsers, the user gesture requirement has
been removed and there is now an optional first argument which
can be used to provide a windowId.

Differential Revision: https://phabricator.services.mozilla.com/D139796
This commit is contained in:
Oliver Dunk 2022-10-31 15:22:41 +00:00
Родитель 3cfcd785c8
Коммит b7782d615a
13 изменённых файлов: 690 добавлений и 77 удалений

Просмотреть файл

@ -36,7 +36,7 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/ExtensionPermissions.jsm"
);
var { DefaultWeakMap } = ExtensionUtils;
var { DefaultWeakMap, ExtensionError } = ExtensionUtils;
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
@ -256,6 +256,9 @@ this.browserAction = class extends ExtensionAPIPersistent {
button: event.button || 0,
modifiers: clickModifiersFromEvent(event),
};
// The openPopupWithoutUserInteraction flag may be set by openPopup.
this.openPopupWithoutUserInteraction =
event.detail?.openPopupWithoutUserInteraction === true;
},
onViewShowing: async event => {
@ -269,7 +272,10 @@ this.browserAction = class extends ExtensionAPIPersistent {
let tabbrowser = document.defaultView.gBrowser;
let tab = tabbrowser.selectedTab;
let popupURL = this.action.triggerClickOrPopup(tab, this.lastClickInfo);
let popupURL = !this.openPopupWithoutUserInteraction
? this.action.triggerClickOrPopup(tab, this.lastClickInfo)
: this.action.getPopupUrl(tab);
if (popupURL) {
try {
@ -326,6 +332,51 @@ this.browserAction = class extends ExtensionAPIPersistent {
this.widget = widget;
}
/**
* Shows the popup. The caller is expected to check if a popup is set before
* this is called.
*
* @param {Window} window Window to show the popup for
* @param {boolean} openPopupWithoutUserInteraction
* If the popup was opened without user interaction
*/
async openPopup(window, openPopupWithoutUserInteraction = false) {
const widgetForWindow = this.widget.forWindow(window);
if (!widgetForWindow.node) {
return;
}
// We want to focus hidden or minimized windows (both for the API, and to
// avoid an issue where showing the popup in a non-focused window
// immediately triggers a popuphidden event)
window.focus();
if (widgetForWindow.node.open) {
return;
}
if (this.widget.areaType == CustomizableUI.TYPE_MENU_PANEL) {
await window.document.getElementById("nav-bar").overflowable.show();
}
// This should already have been checked by callers, but acts as an
// an additional safeguard. It also makes sure we don't dispatch a click
// if the URL is removed while waiting for the overflow to show above.
if (!this.action.getPopupUrl(window.gBrowser.selectedTab)) {
return;
}
const event = new window.CustomEvent("command", {
bubbles: true,
cancelable: true,
detail: {
openPopupWithoutUserInteraction,
},
});
widgetForWindow.node.dispatchEvent(event);
}
/**
* Triggers this browser action for the given window, with the same effects as
* if it were clicked by a user.
@ -335,34 +386,21 @@ this.browserAction = class extends ExtensionAPIPersistent {
*
* @param {Window} window
*/
async triggerAction(window) {
triggerAction(window) {
let popup = ViewPopup.for(this.extension, window);
if (!this.pendingPopup && popup) {
popup.closePopup();
return;
}
let widget = this.widget.forWindow(window);
let tab = window.gBrowser.selectedTab;
if (!widget.node) {
return;
}
let popupUrl = this.action.triggerClickOrPopup(tab, {
button: 0,
modifiers: [],
});
if (popupUrl) {
if (this.widget.areaType == CustomizableUI.TYPE_MENU_PANEL) {
await window.document.getElementById("nav-bar").overflowable.show();
}
let event = new window.CustomEvent("command", {
bubbles: true,
cancelable: true,
});
widget.node.dispatchEvent(event);
this.openPopup(window);
}
}
@ -696,9 +734,27 @@ this.browserAction = class extends ExtensionAPIPersistent {
extensionApi: this,
}).api(),
openPopup: () => {
let window = windowTracker.topWindow;
this.triggerAction(window);
openPopup: async options => {
const isHandlingUserInput =
context.callContextData?.isHandlingUserInput;
if (
!Services.prefs.getBoolPref(
"extensions.openPopupWithoutUserGesture.enabled"
) &&
!isHandlingUserInput
) {
throw new ExtensionError("openPopup requires a user gesture");
}
const window =
typeof options?.windowId === "number"
? windowTracker.getWindow(options.windowId, context)
: windowTracker.getTopNormalWindow(context);
if (this.action.getPopupUrl(window.gBrowser.selectedTab, true)) {
await this.openPopup(window, !isHandlingUserInput);
}
},
},
};

Просмотреть файл

@ -119,11 +119,21 @@ async function test_clickData({ manifest_version, persistent }) {
async function test_clickData_reset({ manifest_version }) {
const action = manifest_version < 3 ? "browser_action" : "action";
const browser_action_command =
manifest_version < 3 ? "_execute_browser_action" : "_execute_action";
const browser_action_key = "j";
let extension = ExtensionTestUtils.loadExtension({
manifest: {
manifest_version,
[action]: {},
page_action: {},
commands: {
[browser_action_command]: {
suggested_key: {
default: "Alt+Shift+J",
},
},
},
},
async background() {
@ -132,10 +142,7 @@ async function test_clickData_reset({ manifest_version }) {
}
function onPageActionClicked(tab, info) {
// openPopup requires user interaction, such as a page action click.
// NOTE: this triggers the browserAction onClicked event as a side-effect
// of triggering the browserAction popup through browserAction.openPopup.
browser.browserAction.openPopup();
browser.test.sendMessage("open-popup");
}
const { manifest_version } = browser.runtime.getManifest();
@ -195,10 +202,17 @@ async function test_clickData_reset({ manifest_version }) {
// spawned again to handle the action onClicked event.
await extension.awaitMessage("ready");
} else {
extension.onMessage("open-popup", () => {
EventUtils.synthesizeKey(browser_action_key, {
altKey: true,
shiftKey: true,
});
});
// pageAction should only be available in MV2 extensions.
await clickPageAction(extension);
// NOTE: the pageAction event listener then triggers browserAction.onClicked
// as a side effect of calling browserAction.openPopup.
assertInfoReset(await extension.awaitMessage("onClick"));
}

Просмотреть файл

@ -15,11 +15,6 @@ add_task(async function test_openPopup_requires_user_interaction() {
"pageAction.openPopup may only be called from a user input handler",
"The error is informative."
);
await browser.test.assertRejects(
browser.browserAction.openPopup(),
"browserAction.openPopup may only be called from a user input handler",
"The error is informative."
);
await browser.test.assertRejects(
browser.sidebarAction.open(),
"sidebarAction.open may only be called from a user input handler",
@ -64,7 +59,6 @@ add_task(async function test_openPopup_requires_user_interaction() {
"tab.html": `
<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<button id="openBrowserAction">openBrowserAction</button>
<button id="openPageAction">openPageAction</button>
<button id="openSidebarAction">openSidebarAction</button>
<button id="closeSidebarAction">closeSidebarAction</button>
@ -79,13 +73,6 @@ add_task(async function test_openPopup_requires_user_interaction() {
</body></html>
`,
"tab.js": function() {
document.getElementById("openBrowserAction").addEventListener(
"click",
() => {
browser.browserAction.openPopup();
},
{ once: true }
);
document.getElementById("openPageAction").addEventListener(
"click",
() => {
@ -133,23 +120,9 @@ add_task(async function test_openPopup_requires_user_interaction() {
return open;
}
function testActiveTab(extension, expected) {
let ext = WebExtensionPolicy.getByID(extension.id).extension;
is(
ext.tabManager.hasActiveTabPermission(gBrowser.selectedTab),
expected,
"activeTab permission is correct"
);
}
await extension.startup();
await extension.awaitMessage("ready");
await click("#openBrowserAction");
testActiveTab(extension, false);
closeBrowserAction(extension);
await new Promise(resolve => setTimeout(resolve, 0));
await click("#openPageAction");
closePageAction(extension);
await new Promise(resolve => setTimeout(resolve, 0));
@ -174,17 +147,4 @@ add_task(async function test_openPopup_requires_user_interaction() {
BrowserTestUtils.removeTab(gBrowser.selectedTab);
await extension.unload();
extensionData.manifest.permissions = ["activeTab"];
extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("ready");
await click("#openBrowserAction");
testActiveTab(extension, true);
closeBrowserAction(extension);
await new Promise(resolve => setTimeout(resolve, 0));
BrowserTestUtils.removeTab(gBrowser.selectedTab);
await extension.unload();
});

Просмотреть файл

@ -50,9 +50,10 @@ class BrowserAction extends BrowserActionBase {
});
}
openPopup() {
const tab = tabTracker.activeTab;
const popupUri = this.triggerClickOrPopup(tab);
openPopup(tab, openPopupWithoutUserInteraction = false) {
const popupUri = openPopupWithoutUserInteraction
? this.getPopupUrl(tab)
: this.triggerClickOrPopup(tab);
const actionObject = this.getContextData(tab);
const action = this.helper.extractProperties(actionObject);
this.helper.sendRequest(tab.id, {
@ -151,8 +152,35 @@ this.browserAction = class extends ExtensionAPIPersistent {
extensionApi: this,
}).api(),
openPopup: function() {
action.openPopup();
openPopup: options => {
const isHandlingUserInput =
context.callContextData?.isHandlingUserInput;
if (
!Services.prefs.getBoolPref(
"extensions.openPopupWithoutUserGesture.enabled"
) &&
!isHandlingUserInput
) {
throw new ExtensionError("openPopup requires a user gesture");
}
const currentWindow = windowTracker.getCurrentWindow(context);
const window =
typeof options?.windowId === "number"
? windowTracker.getWindow(options.windowId, context)
: currentWindow;
if (window !== currentWindow) {
throw new ExtensionError(
"Only the current window is supported on Android."
);
}
if (this.action.getPopupUrl(window.tab, true)) {
action.openPopup(window.tab, !isHandlingUserInput);
}
},
},
};

Просмотреть файл

@ -1974,6 +1974,12 @@ pref("extensions.manifestV2.actionsPopupURLRestricted", false);
#else
pref("extensions.unifiedExtensions.enabled", false);
#endif
// Whether to enable the updated openPopup API.
#ifdef NIGHTLY_BUILD
pref("extensions.openPopupWithoutUserGesture.enabled", true);
#else
pref("extensions.openPopupWithoutUserGesture.enabled", false);
#endif
// Modifier key prefs: default to Windows settings,
// menu access key = alt, accelerator key = control.

Просмотреть файл

@ -185,14 +185,25 @@ class PanelActionBase {
*
* @param {XULElement} tab
* The tab the popup refers to.
* @param {boolean} strict
* If errors should be thrown if a URL is not available.
* @returns {string}
* The popup URL if a popup is present, undefined otherwise.
*/
getPopupUrl(tab) {
getPopupUrl(tab, strict = false) {
if (!this.isShownForTab(tab)) {
if (strict) {
throw new ExtensionError("Popup is disabled");
}
return undefined;
}
let popupUrl = this.getProperty(tab, "popup");
if (strict && !popupUrl) {
throw new ExtensionError("No popup URL is set");
}
return popupUrl;
}

Просмотреть файл

@ -469,10 +469,24 @@
{
"name": "openPopup",
"type": "function",
"requireUserInput": true,
"description": "Opens the extension popup window in the active window.",
"description": "Opens the extension popup window in the specified window.",
"async": true,
"parameters": []
"parameters": [
{
"name": "options",
"optional": true,
"type": "object",
"description": "An object with information about the popup to open.",
"properties": {
"windowId": {
"type": "integer",
"minimum": -2,
"optional": true,
"description": "Defaults to the $(topic:current-window)[current window]."
}
}
}
]
}
],
"events": [

Просмотреть файл

@ -87,6 +87,12 @@ skip-if = toolkit == 'android' || tsan # near-permafail after landing bug 127005
[test_ext_background_canvas.html]
[test_ext_background_page.html]
skip-if = (toolkit == 'android') # android doesn't have devtools
[test_ext_browserAction_openPopup.html]
[test_ext_browserAction_openPopup_incognito_window.html]
skip-if = os == "android" # cannot open private windows - bug 1372178
[test_ext_browserAction_openPopup_windowId.html]
skip-if = os == "android" # only the current window is supported - bug 1795956
[test_ext_browserAction_openPopup_without_pref.html]
[test_ext_browsingData_indexedDB.html]
[test_ext_browsingData_localStorage.html]
[test_ext_browsingData_pluginData.html]

Просмотреть файл

@ -0,0 +1,183 @@
<!DOCTYPE HTML>
<html>
<head>
<title>action.openPopup Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
let extensionData = {
manifest: {
applications: {
gecko: {
id: "open-popup@tests.mozilla.org",
}
},
browser_action: {
default_popup: "popup.html",
},
permissions: ["activeTab"]
},
useAddonManager: "android-only",
};
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
"set": [
["extensions.openPopupWithoutUserGesture.enabled", true],
],
});
});
async function testActiveTabPermissions(withHandlingUserInput) {
const background = async function(withHandlingUserInput) {
let tabPromise;
let tabLoadedPromise = new Promise(resolve => {
// Wait for the tab to actually finish loading (bug 1589734)
browser.tabs.onUpdated.addListener(async (id, { status }) => {
if (id === (await tabPromise).id && status === "complete") {
resolve();
}
});
});
tabPromise = browser.tabs.create({ url: "https://www.example.com" });
tabLoadedPromise.then(() => {
// Once the popup opens, check if we have activeTab permission
browser.runtime.onMessage.addListener(async msg => {
if (msg === "popup-open") {
let tabs = await browser.tabs.query({});
browser.test.assertEq(
withHandlingUserInput ? 1 : 0,
tabs.filter((t) => typeof t.url !== "undefined").length,
"active tab permission only granted with user input"
);
await browser.tabs.remove((await tabPromise).id);
browser.test.sendMessage("activeTabsChecked");
}
});
if (withHandlingUserInput) {
browser.test.withHandlingUserInput(() => {
browser.browserAction.openPopup();
});
} else {
browser.browserAction.openPopup();
}
})
};
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: `(${background})(${withHandlingUserInput})`,
files: {
"popup.html": `<!DOCTYPE html><meta charset="utf-8"><script src="popup.js"><\/script>`,
async "popup.js"() {
browser.runtime.sendMessage("popup-open");
},
},
});
await extension.startup();
await extension.awaitMessage("activeTabsChecked");
await extension.unload();
}
add_task(async function test_browserAction_openPopup_activeTab() {
await testActiveTabPermissions(true);
});
add_task(async function test_browserAction_openPopup_non_activeTab() {
await testActiveTabPermissions(false);
});
add_task(async function test_browserAction_openPopup_invalid_states() {
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: async function() {
await browser.browserAction.setPopup({ popup: "" })
await browser.test.assertRejects(
browser.browserAction.openPopup(),
"No popup URL is set",
"Should throw when no URL is set"
);
await browser.browserAction.disable()
await browser.test.assertRejects(
browser.browserAction.openPopup(),
"Popup is disabled",
"Should throw when disabled"
);
browser.test.notifyPass("invalidStates");
},
});
await extension.startup();
await extension.awaitFinish("invalidStates");
await extension.unload();
});
add_task(async function test_browserAction_openPopup_no_click_event() {
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: async function() {
let clicks = 0;
browser.browserAction.onClicked.addListener(() => {
clicks++;
});
// Test with popup set
await browser.browserAction.openPopup();
browser.test.sendMessage("close-popup");
browser.test.onMessage.addListener(async (msg) => {
if (msg === "popup-closed") {
// Test without popup
await browser.browserAction.setPopup({ popup: "" });
await browser.test.assertRejects(
browser.browserAction.openPopup(),
"No popup URL is set",
"Should throw when no URL is set"
);
// We expect the last call to be a no-op, so there isn't really anything
// to wait on. Instead, check that no clicks are registered after waiting
// for a sufficient amount of time.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
browser.test.assertEq(0, clicks, "onClicked should not be called");
browser.test.notifyPass("noClick");
}, 1000);
}
});
},
});
extension.onMessage("close-popup", async () => {
await AppTestDelegate.closeBrowserAction(window, extension);
extension.sendMessage("popup-closed");
});
await extension.startup();
await extension.awaitFinish("noClick");
await extension.unload();
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,129 @@
<!DOCTYPE HTML>
<html>
<head>
<title>action.openPopup Incognito Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
let extensionData = {
manifest: {
applications: {
gecko: {
id: "open-popup@tests.mozilla.org",
}
},
browser_action: {
default_popup: "popup.html",
},
permissions: ["activeTab"]
},
useAddonManager: "android-only",
};
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
"set": [
["extensions.openPopupWithoutUserGesture.enabled", true],
],
});
});
async function getIncognitoWindow() {
// Since events will be limited based on incognito, we need a
// spanning extension to get the tab id so we can test access failure.
let windowWatcher = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["tabs"],
},
background: function() {
browser.windows.create({ incognito: true }).then(({ id: windowId }) => {
browser.test.onMessage.addListener(async data => {
if (data === "close") {
await browser.windows.remove(windowId);
browser.test.sendMessage("window-closed");
}
});
browser.test.sendMessage("window-id", windowId);
});
},
incognitoOverride: "spanning",
});
await windowWatcher.startup();
let windowId = await windowWatcher.awaitMessage("window-id");
return {
windowId,
close: async () => {
windowWatcher.sendMessage("close");
await windowWatcher.awaitMessage("window-closed");
await windowWatcher.unload();
},
};
}
add_task(async function test_browserAction_openPopup_incognito_window() {
if (AppConstants.platform == "android") {
// TODO bug 1372178: Cannot open private windows from an extension.
todo(false, "Cannot open private windows on Android");
return;
}
async function testWithIncognitoOverride(incognitoOverride) {
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
incognitoOverride,
background: async function() {
browser.test.onMessage.addListener(async ({ windowId, incognitoOverride }) => {
const openPromise = browser.browserAction.openPopup({ windowId });
if (incognitoOverride === "not_allowed") {
await browser.test.assertRejects(
openPromise,
/Invalid window ID/,
"Should prevent open popup call for incognito window"
);
} else {
try {
browser.test.assertEq(await openPromise, undefined, "openPopup resolved");
} catch (e) {
browser.test.fail(`Unexpected error: ${e}`);
}
}
browser.test.sendMessage("incognitoWindow");
});
},
});
await extension.startup();
let incognitoWindow = await getIncognitoWindow();
await extension.sendMessage({ windowId: incognitoWindow.windowId, incognitoOverride });
await extension.awaitMessage("incognitoWindow");
await extension.unload();
await incognitoWindow.close();
}
for (const override of ["spanning", "not_allowed"]) {
await testWithIncognitoOverride(override);
}
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,150 @@
<!DOCTYPE HTML>
<html>
<head>
<title>action.openPopup Window ID Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
let extensionData = {
manifest: {
applications: {
gecko: {
id: "open-popup@tests.mozilla.org",
}
},
browser_action: {
default_popup: "popup.html",
},
permissions: ["activeTab"]
},
useAddonManager: "android-only",
};
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
"set": [
["extensions.openPopupWithoutUserGesture.enabled", true],
],
});
});
async function testWithWindowState(state) {
const background = async function(state) {
const originalWindow = await browser.windows.getCurrent();
let newWindowPromise;
const tabLoadedPromise = new Promise(resolve => {
browser.tabs.onUpdated.addListener(async (id, { status }, tab) => {
if (tab.windowId === (await newWindowPromise).id && status === "complete") {
resolve();
}
});
});
newWindowPromise = browser.windows.create({ url: "tab.html" });
tabLoadedPromise.then(async () => {
const windowId = (await newWindowPromise).id;
switch (state) {
case "inactive":
const focusChangePromise = new Promise(resolve => {
browser.windows.onFocusChanged.addListener((focusedWindowId) => {
if (focusedWindowId === originalWindow.id) {
resolve();
}
})
});
await browser.windows.update(originalWindow.id, { focused: true });
await focusChangePromise;
break;
case "minimized":
await browser.windows.update(windowId, { state: "minimized" });
break;
default:
throw new Error(`Invalid state: ${state}`);
}
await browser.browserAction.openPopup({ windowId });
});
};
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: `(${background})(${JSON.stringify(state)})`,
files: {
"tab.html": "<!DOCTYPE html>",
"popup.html": `<!DOCTYPE html><meta charset="utf-8"><script src="popup.js"><\/script>`,
"popup.js"() {
// Small timeout to ensure the popup doesn't immediately close, which can
// happen when focus moves between windows
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(async () => {
let windows = await browser.windows.getAll();
let highestWindowIdIsFocused = Math.max(...windows.map((w) => w.id))
=== windows.find((w) => w.focused).id;
browser.test.assertEq(true, highestWindowIdIsFocused, "new window is focused");
browser.windows.remove(windows[windows.length - 1].id);
browser.test.sendMessage("window");
}, 1000);
},
},
});
await extension.startup();
await extension.awaitMessage("window");
await extension.unload();
}
add_task(async function test_browserAction_openPopup_window_inactive() {
if (AppConstants.platform == "linux") {
// TODO bug 1798334: Currently unreliable on linux
todo(false, "Unreliable on linux");
return;
}
await testWithWindowState("inactive");
});
add_task(async function test_browserAction_openPopup_window_minimized() {
if (AppConstants.platform == "linux") {
// TODO bug 1798334: Currently unreliable on linux
todo(false, "Unreliable on linux");
return;
}
await testWithWindowState("minimized");
});
add_task(async function test_browserAction_openPopup_invalid_window() {
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: async function() {
await browser.test.assertRejects(
browser.browserAction.openPopup({ windowId: Number.MAX_SAFE_INTEGER }),
/Invalid window ID/,
"Should throw for invalid window ID"
);
browser.test.notifyPass("invalidWindow");
},
});
await extension.startup();
await extension.awaitFinish("invalidWindow");
await extension.unload();
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<title>action.openPopup Preference Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
let extensionData = {
manifest: {
applications: {
gecko: {
id: "open-popup@tests.mozilla.org",
}
},
browser_action: {
default_popup: "popup.html",
}
},
useAddonManager: "android-only",
};
add_task(async function test_browserAction_openPopup_without_pref() {
await SpecialPowers.pushPrefEnv({
"set": [
["extensions.openPopupWithoutUserGesture.enabled", false],
],
});
let extension = ExtensionTestUtils.loadExtension({
...extensionData,
background: async function() {
await browser.test.assertRejects(
browser.browserAction.openPopup(),
"openPopup requires a user gesture",
"Should throw when preference is unset"
);
browser.test.notifyPass("withoutPref");
},
});
await extension.startup();
await extension.awaitFinish("withoutPref");
await extension.unload();
});
</script>
</body>
</html>

Просмотреть файл

@ -40,9 +40,7 @@ async function test_query(query) {
browser.runtime.sendMessage({ tab, query });
}
});
browser.test.withHandlingUserInput(() =>
browser.browserAction.openPopup()
);
browser.browserAction.openPopup();
},
files: {