From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../browser/browser_ext_contextMenus_onclick.js | 297 +++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js (limited to 'browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js') diff --git a/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js b/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js new file mode 100644 index 0000000000..72c365f7d7 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js @@ -0,0 +1,297 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const PAGE = + "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html"; + +// Loaded both as a background script and a tab page. +function testScript() { + let page = location.pathname.includes("tab.html") ? "tab" : "background"; + let clickCounts = { + old: 0, + new: 0, + }; + browser.contextMenus.onClicked.addListener(() => { + // Async to give other onclick handlers a chance to fire. + setTimeout(() => { + browser.test.sendMessage("onClicked-fired", page); + }); + }); + browser.test.onMessage.addListener((toPage, msg) => { + if (toPage !== page) { + return; + } + browser.test.log(`Received ${msg} for ${toPage}`); + if (msg == "get-click-counts") { + browser.test.sendMessage("click-counts", clickCounts); + } else if (msg == "clear-click-counts") { + clickCounts.old = clickCounts.new = 0; + browser.test.sendMessage("next"); + } else if (msg == "create-with-onclick") { + browser.contextMenus.create( + { + id: "iden", + title: "tifier", + onclick() { + ++clickCounts.old; + browser.test.log( + `onclick fired for original onclick property in ${page}` + ); + }, + }, + () => browser.test.sendMessage("next") + ); + } else if (msg == "create-without-onclick") { + browser.contextMenus.create( + { + id: "iden", + title: "tifier", + }, + () => browser.test.sendMessage("next") + ); + } else if (msg == "update-without-onclick") { + browser.contextMenus.update( + "iden", + { + enabled: true, // Already enabled, so this does nothing. + }, + () => browser.test.sendMessage("next") + ); + } else if (msg == "update-with-onclick") { + browser.contextMenus.update( + "iden", + { + onclick() { + ++clickCounts.new; + browser.test.log( + `onclick fired for updated onclick property in ${page}` + ); + }, + }, + () => browser.test.sendMessage("next") + ); + } else if (msg == "remove") { + browser.contextMenus.remove("iden", () => + browser.test.sendMessage("next") + ); + } else if (msg == "removeAll") { + browser.contextMenus.removeAll(() => browser.test.sendMessage("next")); + } + }); + + if (page == "background") { + browser.test.log("Opening tab.html"); + browser.tabs.create({ + url: "tab.html", + active: false, // To not interfere with the context menu tests. + }); + } else { + // Sanity check - the pages must be in the same process. + let pages = browser.extension.getViews(); + browser.test.assertTrue( + pages.includes(window), + "Expected this tab to be an extension view" + ); + pages = pages.filter(w => w !== window); + browser.test.assertEq( + pages[0], + browser.extension.getBackgroundPage(), + "Expected the other page to be a background page" + ); + browser.test.sendMessage("tab.html ready"); + } +} + +add_task(async function () { + let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); + + gBrowser.selectedTab = tab1; + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["contextMenus"], + }, + background: testScript, + files: { + "tab.html": ``, + "tab.js": testScript, + }, + }); + await extension.startup(); + await extension.awaitMessage("tab.html ready"); + + async function clickContextMenu() { + // Using openContextMenu instead of openExtensionContextMenu because the + // test extension has only one context menu item. + let extensionMenuRoot = await openContextMenu(); + let items = extensionMenuRoot.getElementsByAttribute("label", "tifier"); + is(items.length, 1, "Expected one context menu item"); + await closeExtensionContextMenu(items[0]); + // One of them is "tab", the other is "background". + info(`onClicked from: ${await extension.awaitMessage("onClicked-fired")}`); + info(`onClicked from: ${await extension.awaitMessage("onClicked-fired")}`); + } + + function getCounts(page) { + extension.sendMessage(page, "get-click-counts"); + return extension.awaitMessage("click-counts"); + } + async function resetCounts() { + extension.sendMessage("tab", "clear-click-counts"); + extension.sendMessage("background", "clear-click-counts"); + await extension.awaitMessage("next"); + await extension.awaitMessage("next"); + } + + // During this test, at most one "onclick" attribute is expected at any time. + for (let pageOne of ["background", "tab"]) { + for (let pageTwo of ["background", "tab"]) { + info(`Testing with menu created by ${pageOne} and updated by ${pageTwo}`); + extension.sendMessage(pageOne, "create-with-onclick"); + await extension.awaitMessage("next"); + + // Test that update without onclick attribute does not clear the existing + // onclick handler. + extension.sendMessage(pageTwo, "update-without-onclick"); + await extension.awaitMessage("next"); + await clickContextMenu(); + let clickCounts = await getCounts(pageOne); + is( + clickCounts.old, + 1, + `Original onclick should still be present in ${pageOne}` + ); + is(clickCounts.new, 0, `Not expecting any new handlers in ${pageOne}`); + if (pageOne !== pageTwo) { + clickCounts = await getCounts(pageTwo); + is(clickCounts.old, 0, `Not expecting any handlers in ${pageTwo}`); + is(clickCounts.new, 0, `Not expecting any new handlers in ${pageTwo}`); + } + await resetCounts(); + + // Test that update with onclick handler in a different page clears the + // existing handler and activates the new onclick handler. + extension.sendMessage(pageTwo, "update-with-onclick"); + await extension.awaitMessage("next"); + await clickContextMenu(); + clickCounts = await getCounts(pageOne); + is(clickCounts.old, 0, `Original onclick should be gone from ${pageOne}`); + if (pageOne !== pageTwo) { + is( + clickCounts.new, + 0, + `Still not expecting new handlers in ${pageOne}` + ); + } + clickCounts = await getCounts(pageTwo); + if (pageOne !== pageTwo) { + is(clickCounts.old, 0, `Not expecting an old onclick in ${pageTwo}`); + } + is(clickCounts.new, 1, `New onclick should be triggered in ${pageTwo}`); + await resetCounts(); + + // Test that updating the handler (different again from the last `update` + // call, but the same as the `create` call) clears the existing handler + // and activates the new onclick handler. + extension.sendMessage(pageOne, "update-with-onclick"); + await extension.awaitMessage("next"); + await clickContextMenu(); + clickCounts = await getCounts(pageOne); + is(clickCounts.new, 1, `onclick should be triggered in ${pageOne}`); + if (pageOne !== pageTwo) { + clickCounts = await getCounts(pageTwo); + is(clickCounts.new, 0, `onclick should be gone from ${pageTwo}`); + } + await resetCounts(); + + // Test that removing the context menu and recreating it with the same ID + // (in a different context) does not leave behind any onclick handlers. + extension.sendMessage(pageTwo, "remove"); + await extension.awaitMessage("next"); + extension.sendMessage(pageTwo, "create-without-onclick"); + await extension.awaitMessage("next"); + await clickContextMenu(); + clickCounts = await getCounts(pageOne); + is(clickCounts.new, 0, `Did not expect any click handlers in ${pageOne}`); + if (pageOne !== pageTwo) { + clickCounts = await getCounts(pageTwo); + is( + clickCounts.new, + 0, + `Did not expect any click handlers in ${pageTwo}` + ); + } + await resetCounts(); + + // Remove context menu for the next iteration of the test. And just to get + // more coverage, let's use removeAll instead of remove. + extension.sendMessage(pageOne, "removeAll"); + await extension.awaitMessage("next"); + } + } + await extension.unload(); + BrowserTestUtils.removeTab(tab1); +}); + +add_task(async function test_onclick_modifiers() { + const manifest = { + permissions: ["contextMenus"], + }; + + function background() { + function onclick(info) { + browser.test.sendMessage("click", info); + } + browser.contextMenus.create( + { contexts: ["all"], title: "modify", onclick }, + () => { + browser.test.sendMessage("ready"); + } + ); + } + + const extension = ExtensionTestUtils.loadExtension({ manifest, background }); + const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); + + await extension.startup(); + await extension.awaitMessage("ready"); + + async function click(modifiers = {}) { + const menu = await openContextMenu(); + const items = menu.getElementsByAttribute("label", "modify"); + is(items.length, 1, "Got exactly one context menu item"); + await closeExtensionContextMenu(items[0], modifiers); + return extension.awaitMessage("click"); + } + + const plain = await click(); + is(plain.modifiers.length, 0, "modifiers array empty with a plain click"); + + const shift = await click({ shiftKey: true }); + is(shift.modifiers.join(), "Shift", "Correct modifier: Shift"); + + const ctrl = await click({ ctrlKey: true }); + if (AppConstants.platform !== "macosx") { + is(ctrl.modifiers.join(), "Ctrl", "Correct modifier: Ctrl"); + } else { + is( + ctrl.modifiers.sort().join(), + "Ctrl,MacCtrl", + "Correct modifier: Ctrl (and MacCtrl)" + ); + + const meta = await click({ metaKey: true }); + is(meta.modifiers.join(), "Command", "Correct modifier: Command"); + } + + const altShift = await click({ altKey: true, shiftKey: true }); + is( + altShift.modifiers.sort().join(), + "Alt,Shift", + "Correct modifiers: Shift+Alt" + ); + + BrowserTestUtils.removeTab(tab); + await extension.unload(); +}); -- cgit v1.2.3