summaryrefslogtreecommitdiffstats
path: root/browser/modules/test/browser/browser_PageActions.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules/test/browser/browser_PageActions.js')
-rw-r--r--browser/modules/test/browser/browser_PageActions.js1402
1 files changed, 1402 insertions, 0 deletions
diff --git a/browser/modules/test/browser/browser_PageActions.js b/browser/modules/test/browser/browser_PageActions.js
new file mode 100644
index 0000000000..a0b6e72211
--- /dev/null
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -0,0 +1,1402 @@
+"use strict";
+
+// This is a test for PageActions.jsm, specifically the generalized parts that
+// add and remove page actions and toggle them in the urlbar. This does not
+// test the built-in page actions; browser_page_action_menu.js does that.
+
+// Initialization. Must run first.
+add_setup(async function () {
+ // The page action urlbar button, and therefore the panel, is only shown when
+ // the current tab is actionable -- i.e., a normal web page. about:blank is
+ // not, so open a new tab first thing, and close it when this test is done.
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: "http://example.com/",
+ });
+ registerCleanupFunction(async () => {
+ BrowserTestUtils.removeTab(tab);
+ });
+
+ await initPageActionsTest();
+});
+
+// Tests a simple non-built-in action without an iframe or subview. Also
+// thoroughly checks most of the action's properties, methods, and DOM nodes, so
+// it's not necessary to do that in general in other test tasks.
+add_task(async function simple() {
+ let iconURL = "chrome://browser/skin/mail.svg";
+ let id = "test-simple";
+ let title = "Test simple";
+ let tooltip = "Test simple tooltip";
+
+ let onCommandCallCount = 0;
+ let onPlacedInPanelCallCount = 0;
+ let onPlacedInUrlbarCallCount = 0;
+ let onShowingInPanelCallCount = 0;
+ let onCommandExpectedButtonID;
+
+ let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+ let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
+
+ // Open the panel so that actions are added to it, and then close it.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ let initialActions = PageActions.actions;
+ let initialActionsInPanel = PageActions.actionsInPanel(window);
+ let initialActionsInUrlbar = PageActions.actionsInUrlbar(window);
+
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ iconURL,
+ id,
+ title,
+ tooltip,
+ onCommand(event, buttonNode) {
+ onCommandCallCount++;
+ Assert.ok(event, "event should be non-null: " + event);
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, onCommandExpectedButtonID, "buttonNode.id");
+ },
+ onPlacedInPanel(buttonNode) {
+ onPlacedInPanelCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, panelButtonID, "buttonNode.id");
+ },
+ onPlacedInUrlbar(buttonNode) {
+ onPlacedInUrlbarCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, urlbarButtonID, "buttonNode.id");
+ },
+ onShowingInPanel(buttonNode) {
+ onShowingInPanelCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, panelButtonID, "buttonNode.id");
+ },
+ })
+ );
+
+ Assert.equal(action.getIconURL(), iconURL, "iconURL");
+ Assert.equal(action.id, id, "id");
+ Assert.equal(action.pinnedToUrlbar, true, "pinnedToUrlbar");
+ Assert.equal(action.getDisabled(), false, "disabled");
+ Assert.equal(action.getDisabled(window), false, "disabled in window");
+ Assert.equal(action.getTitle(), title, "title");
+ Assert.equal(action.getTitle(window), title, "title in window");
+ Assert.equal(action.getTooltip(), tooltip, "tooltip");
+ Assert.equal(action.getTooltip(window), tooltip, "tooltip in window");
+ Assert.equal(action.getWantsSubview(), false, "subview");
+ Assert.equal(action.getWantsSubview(window), false, "subview in window");
+ Assert.equal(action.urlbarIDOverride, null, "urlbarIDOverride");
+ Assert.equal(action.wantsIframe, false, "wantsIframe");
+
+ Assert.ok(!("__insertBeforeActionID" in action), "__insertBeforeActionID");
+ Assert.ok(!("__isSeparator" in action), "__isSeparator");
+ Assert.ok(!("__urlbarNodeInMarkup" in action), "__urlbarNodeInMarkup");
+ Assert.ok(!("__transient" in action), "__transient");
+
+ // The action shouldn't be placed in the panel until it opens for the first
+ // time.
+ Assert.equal(
+ onPlacedInPanelCallCount,
+ 0,
+ "onPlacedInPanelCallCount should remain 0"
+ );
+ Assert.equal(
+ onPlacedInUrlbarCallCount,
+ 1,
+ "onPlacedInUrlbarCallCount after adding the action"
+ );
+ Assert.equal(
+ onShowingInPanelCallCount,
+ 0,
+ "onShowingInPanelCallCount should remain 0"
+ );
+
+ // Open the panel so that actions are added to it, and then close it.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ Assert.equal(
+ onPlacedInPanelCallCount,
+ 1,
+ "onPlacedInPanelCallCount should be inc'ed"
+ );
+ Assert.equal(
+ onShowingInPanelCallCount,
+ 1,
+ "onShowingInPanelCallCount should be inc'ed"
+ );
+
+ // Build an array of the expected actions in the panel and compare it to the
+ // actual actions. Don't assume that there are or aren't already other non-
+ // built-in actions.
+ let sepIndex = initialActionsInPanel.findIndex(
+ a => a.id == PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ );
+ let initialSepIndex = sepIndex;
+ let indexInPanel;
+ if (sepIndex < 0) {
+ // No prior non-built-in actions.
+ indexInPanel = initialActionsInPanel.length;
+ } else {
+ // Prior non-built-in actions. Find the index where the action goes.
+ for (
+ indexInPanel = sepIndex + 1;
+ indexInPanel < initialActionsInPanel.length;
+ indexInPanel++
+ ) {
+ let a = initialActionsInPanel[indexInPanel];
+ if (a.getTitle().localeCompare(action.getTitle()) < 1) {
+ break;
+ }
+ }
+ }
+ let expectedActionsInPanel = initialActionsInPanel.slice();
+ expectedActionsInPanel.splice(indexInPanel, 0, action);
+ // The separator between the built-ins and non-built-ins should be present
+ // if it's not already.
+ if (sepIndex < 0) {
+ expectedActionsInPanel.splice(
+ indexInPanel,
+ 0,
+ new PageActions.Action({
+ id: PageActions.ACTION_ID_BUILT_IN_SEPARATOR,
+ _isSeparator: true,
+ })
+ );
+ sepIndex = indexInPanel;
+ indexInPanel++;
+ }
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window),
+ expectedActionsInPanel,
+ "Actions in panel after adding the action"
+ );
+
+ Assert.deepEqual(
+ PageActions.actionsInUrlbar(window),
+ [action].concat(initialActionsInUrlbar),
+ "Actions in urlbar after adding the action"
+ );
+
+ // Check the set of all actions.
+ Assert.deepEqual(
+ new Set(PageActions.actions),
+ new Set(initialActions.concat([action])),
+ "All actions after adding the action"
+ );
+
+ Assert.deepEqual(
+ PageActions.actionForID(action.id),
+ action,
+ "actionForID should be action"
+ );
+
+ Assert.ok(
+ PageActions._persistedActions.ids.includes(action.id),
+ "PageActions should record action in its list of seen actions"
+ );
+
+ // The action's panel button should have been created.
+ let panelButtonNode =
+ BrowserPageActions.mainViewBodyNode.children[indexInPanel];
+ Assert.notEqual(panelButtonNode, null, "panelButtonNode");
+ Assert.equal(panelButtonNode.id, panelButtonID, "panelButtonID");
+ Assert.equal(
+ panelButtonNode.getAttribute("label"),
+ action.getTitle(),
+ "label"
+ );
+
+ // The separator between the built-ins and non-built-ins should exist.
+ let sepNode = BrowserPageActions.mainViewBodyNode.children[sepIndex];
+ Assert.notEqual(sepNode, null, "sepNode");
+ Assert.equal(
+ sepNode.id,
+ BrowserPageActions.panelButtonNodeIDForActionID(
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ ),
+ "sepNode.id"
+ );
+
+ let urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(!!urlbarButtonNode, true, "urlbarButtonNode");
+
+ // Open the panel, click the action's button.
+ await promiseOpenPageActionPanel();
+ Assert.equal(
+ onShowingInPanelCallCount,
+ 2,
+ "onShowingInPanelCallCount should be inc'ed"
+ );
+ onCommandExpectedButtonID = panelButtonID;
+ EventUtils.synthesizeMouseAtCenter(panelButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.equal(onCommandCallCount, 1, "onCommandCallCount should be inc'ed");
+
+ // Show the action's button in the urlbar.
+ action.pinnedToUrlbar = true;
+ Assert.equal(
+ onPlacedInUrlbarCallCount,
+ 1,
+ "onPlacedInUrlbarCallCount should be inc'ed"
+ );
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.notEqual(urlbarButtonNode, null, "urlbarButtonNode");
+
+ // The button should have been inserted before the bookmark star.
+ Assert.notEqual(
+ urlbarButtonNode.nextElementSibling,
+ null,
+ "Should be a next node"
+ );
+ Assert.equal(
+ urlbarButtonNode.nextElementSibling.id,
+ PageActions.actionForID(PageActions.ACTION_ID_BOOKMARK).urlbarIDOverride,
+ "Next node should be the bookmark star"
+ );
+
+ // Disable the action. The button in the urlbar should be removed, and the
+ // button in the panel should be disabled.
+ action.setDisabled(true);
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(urlbarButtonNode, null, "urlbar button should be removed");
+ Assert.equal(
+ panelButtonNode.disabled,
+ true,
+ "panel button should be disabled"
+ );
+
+ // Enable the action. The button in the urlbar should be added back, and the
+ // button in the panel should be enabled.
+ action.setDisabled(false);
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.notEqual(urlbarButtonNode, null, "urlbar button should be added back");
+ Assert.equal(
+ panelButtonNode.disabled,
+ false,
+ "panel button should not be disabled"
+ );
+
+ // Click the urlbar button.
+ onCommandExpectedButtonID = urlbarButtonID;
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ Assert.equal(onCommandCallCount, 2, "onCommandCallCount should be inc'ed");
+
+ // Set a new title.
+ let newTitle = title + " new title";
+ action.setTitle(newTitle);
+ Assert.equal(action.getTitle(), newTitle, "New title");
+ Assert.equal(
+ panelButtonNode.getAttribute("label"),
+ action.getTitle(),
+ "New label"
+ );
+
+ // Now that pinnedToUrlbar has been toggled, make sure that it sticks across
+ // app restarts. Simulate that by "unregistering" the action (not by removing
+ // it, which is more permanent) and then registering it again.
+
+ // unregister
+ PageActions._actionsByID.delete(action.id);
+ let index = PageActions._nonBuiltInActions.findIndex(a => a.id == action.id);
+ Assert.ok(index >= 0, "Action should be in _nonBuiltInActions to begin with");
+ PageActions._nonBuiltInActions.splice(index, 1);
+
+ // register again
+ PageActions._registerAction(action);
+
+ // check relevant properties
+ Assert.ok(
+ PageActions._persistedActions.ids.includes(action.id),
+ "PageActions should have 'seen' the action"
+ );
+ Assert.ok(
+ PageActions._persistedActions.idsInUrlbar.includes(action.id),
+ "idsInUrlbar should still include the action"
+ );
+ Assert.ok(action.pinnedToUrlbar, "pinnedToUrlbar should still be true");
+ Assert.ok(
+ action._pinnedToUrlbar,
+ "_pinnedToUrlbar should still be true, for good measure"
+ );
+
+ // Remove the action.
+ action.remove();
+ panelButtonNode = document.getElementById(panelButtonID);
+ Assert.equal(panelButtonNode, null, "panelButtonNode");
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
+
+ let separatorNode = document.getElementById(
+ BrowserPageActions.panelButtonNodeIDForActionID(
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ )
+ );
+ if (initialSepIndex < 0) {
+ // The separator between the built-in actions and non-built-in actions
+ // should be gone now, too.
+ Assert.equal(separatorNode, null, "No separator");
+ Assert.ok(
+ !BrowserPageActions.mainViewBodyNode.lastElementChild.localName.includes(
+ "separator"
+ ),
+ "Last child should not be separator"
+ );
+ } else {
+ // The separator should still be present.
+ Assert.notEqual(separatorNode, null, "Separator should still exist");
+ }
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window),
+ initialActionsInPanel,
+ "Actions in panel should go back to initial"
+ );
+ Assert.deepEqual(
+ PageActions.actionsInUrlbar(window),
+ initialActionsInUrlbar,
+ "Actions in urlbar should go back to initial"
+ );
+ Assert.deepEqual(
+ PageActions.actions,
+ initialActions,
+ "Actions should go back to initial"
+ );
+ Assert.equal(
+ PageActions.actionForID(action.id),
+ null,
+ "actionForID should be null"
+ );
+
+ Assert.ok(
+ PageActions._persistedActions.ids.includes(action.id),
+ "Action ID should remain in cache until purged"
+ );
+ PageActions._purgeUnregisteredPersistedActions();
+ Assert.ok(
+ !PageActions._persistedActions.ids.includes(action.id),
+ "Action ID should be removed from cache after being purged"
+ );
+});
+
+// Tests a non-built-in action with a subview.
+add_task(async function withSubview() {
+ let id = "test-subview";
+
+ let onActionPlacedInPanelCallCount = 0;
+ let onActionPlacedInUrlbarCallCount = 0;
+ let onSubviewPlacedCount = 0;
+ let onSubviewShowingCount = 0;
+
+ let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+ let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
+
+ let panelViewIDPanel = BrowserPageActions._panelViewNodeIDForActionID(
+ id,
+ false
+ );
+ let panelViewIDUrlbar = BrowserPageActions._panelViewNodeIDForActionID(
+ id,
+ true
+ );
+
+ let onSubviewPlacedExpectedPanelViewID = panelViewIDPanel;
+ let onSubviewShowingExpectedPanelViewID;
+
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ iconURL: "chrome://browser/skin/mail.svg",
+ id,
+ pinnedToUrlbar: true,
+ title: "Test subview",
+ wantsSubview: true,
+ onPlacedInPanel(buttonNode) {
+ onActionPlacedInPanelCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, panelButtonID, "buttonNode.id");
+ },
+ onPlacedInUrlbar(buttonNode) {
+ onActionPlacedInUrlbarCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, urlbarButtonID, "buttonNode.id");
+ },
+ onSubviewPlaced(panelViewNode) {
+ onSubviewPlacedCount++;
+ Assert.ok(
+ panelViewNode,
+ "panelViewNode should be non-null: " + panelViewNode
+ );
+ Assert.equal(
+ panelViewNode.id,
+ onSubviewPlacedExpectedPanelViewID,
+ "panelViewNode.id"
+ );
+ },
+ onSubviewShowing(panelViewNode) {
+ onSubviewShowingCount++;
+ Assert.ok(
+ panelViewNode,
+ "panelViewNode should be non-null: " + panelViewNode
+ );
+ Assert.equal(
+ panelViewNode.id,
+ onSubviewShowingExpectedPanelViewID,
+ "panelViewNode.id"
+ );
+ },
+ })
+ );
+
+ Assert.equal(action.id, id, "id");
+ Assert.equal(action.getWantsSubview(), true, "subview");
+ Assert.equal(action.getWantsSubview(window), true, "subview in window");
+
+ // The action shouldn't be placed in the panel until it opens for the first
+ // time.
+ Assert.equal(
+ onActionPlacedInPanelCallCount,
+ 0,
+ "onActionPlacedInPanelCallCount should be 0"
+ );
+ Assert.equal(onSubviewPlacedCount, 0, "onSubviewPlacedCount should be 0");
+
+ // But it should be placed in the urlbar.
+ Assert.equal(
+ onActionPlacedInUrlbarCallCount,
+ 1,
+ "onActionPlacedInUrlbarCallCount should be 0"
+ );
+
+ // Open the panel, which should place the action in it.
+ await promiseOpenPageActionPanel();
+
+ Assert.equal(
+ onActionPlacedInPanelCallCount,
+ 1,
+ "onActionPlacedInPanelCallCount should be inc'ed"
+ );
+ Assert.equal(
+ onSubviewPlacedCount,
+ 1,
+ "onSubviewPlacedCount should be inc'ed"
+ );
+ Assert.equal(
+ onSubviewShowingCount,
+ 0,
+ "onSubviewShowingCount should remain 0"
+ );
+
+ // The action's panel button and view (in the main page action panel) should
+ // have been created.
+ let panelButtonNode = document.getElementById(panelButtonID);
+ Assert.notEqual(panelButtonNode, null, "panelButtonNode");
+
+ // The action's urlbar button should have been created.
+ let urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.notEqual(urlbarButtonNode, null, "urlbarButtonNode");
+
+ // The button should have been inserted before the bookmark star.
+ Assert.notEqual(
+ urlbarButtonNode.nextElementSibling,
+ null,
+ "Should be a next node"
+ );
+ Assert.equal(
+ urlbarButtonNode.nextElementSibling.id,
+ PageActions.actionForID(PageActions.ACTION_ID_BOOKMARK).urlbarIDOverride,
+ "Next node should be the bookmark star"
+ );
+
+ // Click the action's button in the panel. The subview should be shown.
+ Assert.equal(
+ onSubviewShowingCount,
+ 0,
+ "onSubviewShowingCount should remain 0"
+ );
+ let subviewShownPromise = promisePageActionViewShown();
+ onSubviewShowingExpectedPanelViewID = panelViewIDPanel;
+ panelButtonNode.click();
+ await subviewShownPromise;
+
+ // Click the main button to hide the main panel.
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ // Click the action's urlbar button, which should open the activated-action
+ // panel showing the subview.
+ onSubviewPlacedExpectedPanelViewID = panelViewIDUrlbar;
+ onSubviewShowingExpectedPanelViewID = panelViewIDUrlbar;
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ await promisePanelShown(BrowserPageActions._activatedActionPanelID);
+ Assert.equal(
+ onSubviewPlacedCount,
+ 2,
+ "onSubviewPlacedCount should be inc'ed"
+ );
+ Assert.equal(
+ onSubviewShowingCount,
+ 2,
+ "onSubviewShowingCount should be inc'ed"
+ );
+
+ // Click the urlbar button again. The activated-action panel should close.
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ assertActivatedPageActionPanelHidden();
+
+ // Remove the action.
+ action.remove();
+ panelButtonNode = document.getElementById(panelButtonID);
+ Assert.equal(panelButtonNode, null, "panelButtonNode");
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
+ let panelViewNodePanel = document.getElementById(panelViewIDPanel);
+ Assert.equal(panelViewNodePanel, null, "panelViewNodePanel");
+ let panelViewNodeUrlbar = document.getElementById(panelViewIDUrlbar);
+ Assert.equal(panelViewNodeUrlbar, null, "panelViewNodeUrlbar");
+});
+
+// Tests a non-built-in action with an iframe.
+add_task(async function withIframe() {
+ let id = "test-iframe";
+
+ let onCommandCallCount = 0;
+ let onPlacedInPanelCallCount = 0;
+ let onPlacedInUrlbarCallCount = 0;
+ let onIframeShowingCount = 0;
+
+ let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+ let urlbarButtonID = BrowserPageActions.urlbarButtonNodeIDForActionID(id);
+
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ iconURL: "chrome://browser/skin/mail.svg",
+ id,
+ pinnedToUrlbar: true,
+ title: "Test iframe",
+ wantsIframe: true,
+ onCommand(event, buttonNode) {
+ onCommandCallCount++;
+ },
+ onIframeShowing(iframeNode, panelNode) {
+ onIframeShowingCount++;
+ Assert.ok(iframeNode, "iframeNode should be non-null: " + iframeNode);
+ Assert.equal(iframeNode.localName, "iframe", "iframe localName");
+ Assert.ok(panelNode, "panelNode should be non-null: " + panelNode);
+ Assert.equal(
+ panelNode.id,
+ BrowserPageActions._activatedActionPanelID,
+ "panelNode.id"
+ );
+ },
+ onPlacedInPanel(buttonNode) {
+ onPlacedInPanelCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, panelButtonID, "buttonNode.id");
+ },
+ onPlacedInUrlbar(buttonNode) {
+ onPlacedInUrlbarCallCount++;
+ Assert.ok(buttonNode, "buttonNode should be non-null: " + buttonNode);
+ Assert.equal(buttonNode.id, urlbarButtonID, "buttonNode.id");
+ },
+ })
+ );
+
+ Assert.equal(action.id, id, "id");
+ Assert.equal(action.wantsIframe, true, "wantsIframe");
+
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ Assert.equal(
+ onPlacedInPanelCallCount,
+ 1,
+ "onPlacedInPanelCallCount should be inc'ed"
+ );
+ Assert.equal(
+ onPlacedInUrlbarCallCount,
+ 1,
+ "onPlacedInUrlbarCallCount should be inc'ed"
+ );
+ Assert.equal(onIframeShowingCount, 0, "onIframeShowingCount should remain 0");
+ Assert.equal(onCommandCallCount, 0, "onCommandCallCount should remain 0");
+
+ // The action's panel button should have been created.
+ let panelButtonNode = document.getElementById(panelButtonID);
+ Assert.notEqual(panelButtonNode, null, "panelButtonNode");
+
+ // The action's urlbar button should have been created.
+ let urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.notEqual(urlbarButtonNode, null, "urlbarButtonNode");
+
+ // The button should have been inserted before the bookmark star.
+ Assert.notEqual(
+ urlbarButtonNode.nextElementSibling,
+ null,
+ "Should be a next node"
+ );
+ Assert.equal(
+ urlbarButtonNode.nextElementSibling.id,
+ PageActions.actionForID(PageActions.ACTION_ID_BOOKMARK).urlbarIDOverride,
+ "Next node should be the bookmark star"
+ );
+
+ // Open the panel, click the action's button.
+ await promiseOpenPageActionPanel();
+ Assert.equal(onIframeShowingCount, 0, "onIframeShowingCount should remain 0");
+ EventUtils.synthesizeMouseAtCenter(panelButtonNode, {});
+ await promisePanelShown(BrowserPageActions._activatedActionPanelID);
+ Assert.equal(onCommandCallCount, 1, "onCommandCallCount should be inc'ed");
+ Assert.equal(
+ onIframeShowingCount,
+ 1,
+ "onIframeShowingCount should be inc'ed"
+ );
+
+ // The activated-action panel should have opened, anchored to the action's
+ // urlbar button.
+ let aaPanel = document.getElementById(
+ BrowserPageActions._activatedActionPanelID
+ );
+ Assert.notEqual(aaPanel, null, "activated-action panel");
+ Assert.equal(aaPanel.anchorNode.id, urlbarButtonID, "aaPanel.anchorNode.id");
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ assertActivatedPageActionPanelHidden();
+
+ // Click the action's urlbar button.
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ await promisePanelShown(BrowserPageActions._activatedActionPanelID);
+ Assert.equal(onCommandCallCount, 2, "onCommandCallCount should be inc'ed");
+ Assert.equal(
+ onIframeShowingCount,
+ 2,
+ "onIframeShowingCount should be inc'ed"
+ );
+
+ // The activated-action panel should have opened, again anchored to the
+ // action's urlbar button.
+ aaPanel = document.getElementById(BrowserPageActions._activatedActionPanelID);
+ Assert.notEqual(aaPanel, null, "aaPanel");
+ Assert.equal(aaPanel.anchorNode.id, urlbarButtonID, "aaPanel.anchorNode.id");
+ EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
+ assertActivatedPageActionPanelHidden();
+
+ // Hide the action's button in the urlbar.
+ action.pinnedToUrlbar = false;
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
+
+ // Open the panel, click the action's button.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(panelButtonNode, {});
+ await promisePanelShown(BrowserPageActions._activatedActionPanelID);
+ Assert.equal(onCommandCallCount, 3, "onCommandCallCount should be inc'ed");
+ Assert.equal(
+ onIframeShowingCount,
+ 3,
+ "onIframeShowingCount should be inc'ed"
+ );
+
+ // The activated-action panel should have opened, this time anchored to the
+ // main page action button in the urlbar.
+ aaPanel = document.getElementById(BrowserPageActions._activatedActionPanelID);
+ Assert.notEqual(aaPanel, null, "aaPanel");
+ Assert.equal(
+ aaPanel.anchorNode.id,
+ BrowserPageActions.mainButtonNode.id,
+ "aaPanel.anchorNode.id"
+ );
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ assertActivatedPageActionPanelHidden();
+
+ // Remove the action.
+ action.remove();
+ panelButtonNode = document.getElementById(panelButtonID);
+ Assert.equal(panelButtonNode, null, "panelButtonNode");
+ urlbarButtonNode = document.getElementById(urlbarButtonID);
+ Assert.equal(urlbarButtonNode, null, "urlbarButtonNode");
+});
+
+// Tests an action with the _insertBeforeActionID option set.
+add_task(async function insertBeforeActionID() {
+ let id = "test-insertBeforeActionID";
+ let panelButtonID = BrowserPageActions.panelButtonNodeIDForActionID(id);
+
+ let initialActions = PageActions.actionsInPanel(window);
+ let initialBuiltInActions = PageActions._builtInActions.slice();
+ let initialNonBuiltInActions = PageActions._nonBuiltInActions.slice();
+
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ id,
+ title: "Test insertBeforeActionID",
+ _insertBeforeActionID: PageActions.ACTION_ID_BOOKMARK_SEPARATOR,
+ })
+ );
+
+ Assert.equal(action.id, id, "id");
+ Assert.ok("__insertBeforeActionID" in action, "__insertBeforeActionID");
+ Assert.equal(
+ action.__insertBeforeActionID,
+ PageActions.ACTION_ID_BOOKMARK_SEPARATOR,
+ "action.__insertBeforeActionID"
+ );
+
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ let newActions = PageActions.actionsInPanel(window);
+ Assert.equal(
+ newActions.length,
+ initialActions.length + 1,
+ "PageActions.actions.length should be updated"
+ );
+ Assert.equal(
+ PageActions._builtInActions.length,
+ initialBuiltInActions.length + 1,
+ "PageActions._builtInActions.length should be updated"
+ );
+ Assert.equal(
+ PageActions._nonBuiltInActions.length,
+ initialNonBuiltInActions.length,
+ "PageActions._nonBuiltInActions.length should remain the same"
+ );
+
+ // The action's panel button should have been created.
+ let panelButtonNode = document.getElementById(panelButtonID);
+ Assert.notEqual(panelButtonNode, null, "panelButtonNode");
+
+ // The separator between the built-in and non-built-in actions should not have
+ // been created.
+ Assert.equal(
+ document.getElementById(
+ BrowserPageActions.panelButtonNodeIDForActionID(
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ )
+ ),
+ null,
+ "Separator should be gone"
+ );
+
+ action.remove();
+});
+
+// Tests that the ordering in the panel of multiple non-built-in actions is
+// alphabetical.
+add_task(async function multipleNonBuiltInOrdering() {
+ let idPrefix = "test-multipleNonBuiltInOrdering-";
+ let titlePrefix = "Test multipleNonBuiltInOrdering ";
+
+ let initialActions = PageActions.actionsInPanel(window);
+ let initialBuiltInActions = PageActions._builtInActions.slice();
+ let initialNonBuiltInActions = PageActions._nonBuiltInActions.slice();
+
+ // Create some actions in an out-of-order order.
+ let actions = [2, 1, 4, 3].map(index => {
+ return PageActions.addAction(
+ new PageActions.Action({
+ id: idPrefix + index,
+ title: titlePrefix + index,
+ })
+ );
+ });
+
+ // + 1 for the separator between built-in and non-built-in actions.
+ Assert.equal(
+ PageActions.actionsInPanel(window).length,
+ initialActions.length + actions.length + 1,
+ "PageActions.actionsInPanel().length should be updated"
+ );
+
+ Assert.equal(
+ PageActions._builtInActions.length,
+ initialBuiltInActions.length,
+ "PageActions._builtInActions.length should be same"
+ );
+ Assert.equal(
+ PageActions._nonBuiltInActions.length,
+ initialNonBuiltInActions.length + actions.length,
+ "PageActions._nonBuiltInActions.length should be updated"
+ );
+
+ // Look at the final actions.length actions in PageActions.actions, from first
+ // to last.
+ for (let i = 0; i < actions.length; i++) {
+ let expectedIndex = i + 1;
+ let actualAction = PageActions._nonBuiltInActions[i];
+ Assert.equal(
+ actualAction.id,
+ idPrefix + expectedIndex,
+ "actualAction.id for index: " + i
+ );
+ }
+
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+
+ // Check the button nodes in the panel.
+ let expectedIndex = 1;
+ let buttonNode = document.getElementById(
+ BrowserPageActions.panelButtonNodeIDForActionID(idPrefix + expectedIndex)
+ );
+ Assert.notEqual(buttonNode, null, "buttonNode");
+ Assert.notEqual(
+ buttonNode.previousElementSibling,
+ null,
+ "buttonNode.previousElementSibling"
+ );
+ Assert.equal(
+ buttonNode.previousElementSibling.id,
+ BrowserPageActions.panelButtonNodeIDForActionID(
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ ),
+ "buttonNode.previousElementSibling.id"
+ );
+ for (let i = 0; i < actions.length; i++) {
+ Assert.notEqual(buttonNode, null, "buttonNode at index: " + i);
+ Assert.equal(
+ buttonNode.id,
+ BrowserPageActions.panelButtonNodeIDForActionID(idPrefix + expectedIndex),
+ "buttonNode.id at index: " + i
+ );
+ buttonNode = buttonNode.nextElementSibling;
+ expectedIndex++;
+ }
+ Assert.equal(buttonNode, null, "Nothing should come after the last button");
+
+ for (let action of actions) {
+ action.remove();
+ }
+
+ // The separator between the built-in and non-built-in actions should be gone.
+ Assert.equal(
+ document.getElementById(
+ BrowserPageActions.panelButtonNodeIDForActionID(
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR
+ )
+ ),
+ null,
+ "Separator should be gone"
+ );
+});
+
+// Makes sure the panel is correctly updated when a non-built-in action is
+// added before the built-in actions; and when all built-in actions are removed
+// and added back.
+add_task(async function nonBuiltFirst() {
+ let initialActions = PageActions.actions;
+ let initialActionsInPanel = PageActions.actionsInPanel(window);
+
+ // Remove all actions.
+ for (let action of initialActions) {
+ action.remove();
+ }
+
+ // Check the actions.
+ Assert.deepEqual(
+ PageActions.actions.map(a => a.id),
+ [],
+ "PageActions.actions should be empty"
+ );
+ Assert.deepEqual(
+ PageActions._builtInActions.map(a => a.id),
+ [],
+ "PageActions._builtInActions should be empty"
+ );
+ Assert.deepEqual(
+ PageActions._nonBuiltInActions.map(a => a.id),
+ [],
+ "PageActions._nonBuiltInActions should be empty"
+ );
+
+ // Check the panel.
+ Assert.equal(
+ BrowserPageActions.mainViewBodyNode.children.length,
+ 0,
+ "All nodes should be gone"
+ );
+
+ // Add a non-built-in action.
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ id: "test-nonBuiltFirst",
+ title: "Test nonBuiltFirst",
+ })
+ );
+
+ // Check the actions.
+ Assert.deepEqual(
+ PageActions.actions.map(a => a.id),
+ [action.id],
+ "Action should be in PageActions.actions"
+ );
+ Assert.deepEqual(
+ PageActions._builtInActions.map(a => a.id),
+ [],
+ "PageActions._builtInActions should be empty"
+ );
+ Assert.deepEqual(
+ PageActions._nonBuiltInActions.map(a => a.id),
+ [action.id],
+ "Action should be in PageActions._nonBuiltInActions"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ [BrowserPageActions.panelButtonNodeIDForActionID(action.id)],
+ "Action should be in panel"
+ );
+
+ // Now add back all the actions.
+ for (let a of initialActions) {
+ PageActions.addAction(a);
+ }
+
+ // Check the actions.
+ Assert.deepEqual(
+ new Set(PageActions.actions.map(a => a.id)),
+ new Set(initialActions.map(a => a.id).concat([action.id])),
+ "All actions should be in PageActions.actions"
+ );
+ Assert.deepEqual(
+ PageActions._builtInActions.map(a => a.id),
+ initialActions.filter(a => !a.__transient).map(a => a.id),
+ "PageActions._builtInActions should be initial actions"
+ );
+ Assert.deepEqual(
+ PageActions._nonBuiltInActions.map(a => a.id),
+ [action.id],
+ "PageActions._nonBuiltInActions should contain action"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_BUILT_IN_SEPARATOR], [action.id]),
+ "All actions should be in PageActions.actionsInPanel()"
+ );
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_BUILT_IN_SEPARATOR], [action.id])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Panel should contain all actions"
+ );
+
+ // Remove the test action.
+ action.remove();
+
+ // Check the actions.
+ Assert.deepEqual(
+ PageActions.actions.map(a => a.id),
+ initialActions.map(a => a.id),
+ "Action should no longer be in PageActions.actions"
+ );
+ Assert.deepEqual(
+ PageActions._builtInActions.map(a => a.id),
+ initialActions.filter(a => !a.__transient).map(a => a.id),
+ "PageActions._builtInActions should be initial actions"
+ );
+ Assert.deepEqual(
+ PageActions._nonBuiltInActions.map(a => a.id),
+ [],
+ "Action should no longer be in PageActions._nonBuiltInActions"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel.map(a => a.id),
+ "Action should no longer be in PageActions.actionsInPanel()"
+ );
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel.map(a =>
+ BrowserPageActions.panelButtonNodeIDForActionID(a.id)
+ ),
+ "Action should no longer be in panel"
+ );
+});
+
+// Adds an action, changes its placement in the urlbar to something non-default,
+// removes the action, and then adds it back. Since the action was removed and
+// re-added without restarting the app (or more accurately without calling
+// PageActions._purgeUnregisteredPersistedActions), the action should remain in
+// persisted state and retain its last placement in the urlbar.
+add_task(async function removeRetainState() {
+ // Get the list of actions initially in the urlbar.
+ let initialActionsInUrlbar = PageActions.actionsInUrlbar(window);
+ Assert.ok(
+ !!initialActionsInUrlbar.length,
+ "This test expects there to be at least one action in the urlbar initially (like the bookmark star)"
+ );
+
+ // Add a test action.
+ let id = "test-removeRetainState";
+ let testAction = PageActions.addAction(
+ new PageActions.Action({
+ id,
+ title: "Test removeRetainState",
+ })
+ );
+
+ // Show its button in the urlbar.
+ testAction.pinnedToUrlbar = true;
+
+ // "Move" the test action to the front of the urlbar by toggling
+ // pinnedToUrlbar for all the other actions in the urlbar.
+ for (let action of initialActionsInUrlbar) {
+ action.pinnedToUrlbar = false;
+ action.pinnedToUrlbar = true;
+ }
+
+ // Check the actions in PageActions.actionsInUrlbar.
+ Assert.deepEqual(
+ PageActions.actionsInUrlbar(window).map(a => a.id),
+ [testAction].concat(initialActionsInUrlbar).map(a => a.id),
+ "PageActions.actionsInUrlbar should be in expected order: testAction followed by all initial actions"
+ );
+
+ // Check the nodes in the urlbar.
+ let actualUrlbarNodeIDs = [];
+ for (
+ let node = BrowserPageActions.mainButtonNode.nextElementSibling;
+ node;
+ node = node.nextElementSibling
+ ) {
+ actualUrlbarNodeIDs.push(node.id);
+ }
+ Assert.deepEqual(
+ actualUrlbarNodeIDs,
+ [testAction]
+ .concat(initialActionsInUrlbar)
+ .map(a => BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)),
+ "urlbar nodes should be in expected order: testAction followed by all initial actions"
+ );
+
+ // Remove the test action.
+ testAction.remove();
+
+ // Check the actions in PageActions.actionsInUrlbar.
+ Assert.deepEqual(
+ PageActions.actionsInUrlbar(window).map(a => a.id),
+ initialActionsInUrlbar.map(a => a.id),
+ "PageActions.actionsInUrlbar should be in expected order after removing test action: all initial actions"
+ );
+
+ // Check the nodes in the urlbar.
+ actualUrlbarNodeIDs = [];
+ for (
+ let node = BrowserPageActions.mainButtonNode.nextElementSibling;
+ node;
+ node = node.nextElementSibling
+ ) {
+ actualUrlbarNodeIDs.push(node.id);
+ }
+ Assert.deepEqual(
+ actualUrlbarNodeIDs,
+ initialActionsInUrlbar.map(a =>
+ BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)
+ ),
+ "urlbar nodes should be in expected order after removing test action: all initial actions"
+ );
+
+ // Add the test action again.
+ testAction = PageActions.addAction(
+ new PageActions.Action({
+ id,
+ title: "Test removeRetainState",
+ })
+ );
+
+ // Show its button in the urlbar again.
+ testAction.pinnedToUrlbar = true;
+
+ // Check the actions in PageActions.actionsInUrlbar.
+ Assert.deepEqual(
+ PageActions.actionsInUrlbar(window).map(a => a.id),
+ [testAction].concat(initialActionsInUrlbar).map(a => a.id),
+ "PageActions.actionsInUrlbar should be in expected order after re-adding test action: testAction followed by all initial actions"
+ );
+
+ // Check the nodes in the urlbar.
+ actualUrlbarNodeIDs = [];
+ for (
+ let node = BrowserPageActions.mainButtonNode.nextElementSibling;
+ node;
+ node = node.nextElementSibling
+ ) {
+ actualUrlbarNodeIDs.push(node.id);
+ }
+ Assert.deepEqual(
+ actualUrlbarNodeIDs,
+ [testAction]
+ .concat(initialActionsInUrlbar)
+ .map(a => BrowserPageActions.urlbarButtonNodeIDForActionID(a.id)),
+ "urlbar nodes should be in expected order after re-adding test action: testAction followed by all initial actions"
+ );
+
+ // Done, clean up.
+ testAction.remove();
+});
+
+// Tests transient actions.
+add_task(async function transient() {
+ let initialActionsInPanel = PageActions.actionsInPanel(window);
+
+ let onPlacedInPanelCount = 0;
+ let onBeforePlacedInWindowCount = 0;
+
+ let action = PageActions.addAction(
+ new PageActions.Action({
+ id: "test-transient",
+ title: "Test transient",
+ _transient: true,
+ onPlacedInPanel(buttonNode) {
+ onPlacedInPanelCount++;
+ },
+ onBeforePlacedInWindow(win) {
+ onBeforePlacedInWindowCount++;
+ },
+ })
+ );
+
+ Assert.equal(action.__transient, true, "__transient");
+
+ Assert.equal(onPlacedInPanelCount, 0, "onPlacedInPanelCount should remain 0");
+ Assert.equal(
+ onBeforePlacedInWindowCount,
+ 1,
+ "onBeforePlacedInWindowCount after adding transient action"
+ );
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_TRANSIENT_SEPARATOR, action.id]),
+ "PageActions.actionsInPanel() should be updated"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_TRANSIENT_SEPARATOR, action.id])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Actions in panel should be correct"
+ );
+
+ Assert.equal(
+ onPlacedInPanelCount,
+ 1,
+ "onPlacedInPanelCount should be inc'ed"
+ );
+ Assert.equal(
+ onBeforePlacedInWindowCount,
+ 1,
+ "onBeforePlacedInWindowCount should be inc'ed"
+ );
+
+ // Disable the action. It should be removed from the panel.
+ action.setDisabled(true, window);
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel.map(a => a.id),
+ "PageActions.actionsInPanel() should revert to initial"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel.map(a =>
+ BrowserPageActions.panelButtonNodeIDForActionID(a.id)
+ ),
+ "Actions in panel should be correct"
+ );
+
+ // Enable the action. It should be added back to the panel.
+ action.setDisabled(false, window);
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_TRANSIENT_SEPARATOR, action.id]),
+ "PageActions.actionsInPanel() should be updated"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_TRANSIENT_SEPARATOR, action.id])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Actions in panel should be correct"
+ );
+
+ Assert.equal(
+ onPlacedInPanelCount,
+ 2,
+ "onPlacedInPanelCount should be inc'ed"
+ );
+ Assert.equal(
+ onBeforePlacedInWindowCount,
+ 2,
+ "onBeforePlacedInWindowCount should be inc'ed"
+ );
+
+ // Add another non-built in but non-transient action.
+ let otherAction = PageActions.addAction(
+ new PageActions.Action({
+ id: "test-transient2",
+ title: "Test transient 2",
+ })
+ );
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR,
+ otherAction.id,
+ PageActions.ACTION_ID_TRANSIENT_SEPARATOR,
+ action.id,
+ ]),
+ "PageActions.actionsInPanel() should be updated"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR,
+ otherAction.id,
+ PageActions.ACTION_ID_TRANSIENT_SEPARATOR,
+ action.id,
+ ])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Actions in panel should be correct"
+ );
+
+ Assert.equal(
+ onPlacedInPanelCount,
+ 2,
+ "onPlacedInPanelCount should remain the same"
+ );
+ Assert.equal(
+ onBeforePlacedInWindowCount,
+ 2,
+ "onBeforePlacedInWindowCount should remain the same"
+ );
+
+ // Disable the action again. It should be removed from the panel.
+ action.setDisabled(true, window);
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_BUILT_IN_SEPARATOR, otherAction.id]),
+ "PageActions.actionsInPanel() should be updated"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([PageActions.ACTION_ID_BUILT_IN_SEPARATOR, otherAction.id])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Actions in panel should be correct"
+ );
+
+ // Enable the action again. It should be added back to the panel.
+ action.setDisabled(false, window);
+
+ Assert.deepEqual(
+ PageActions.actionsInPanel(window).map(a => a.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR,
+ otherAction.id,
+ PageActions.ACTION_ID_TRANSIENT_SEPARATOR,
+ action.id,
+ ]),
+ "PageActions.actionsInPanel() should be updated"
+ );
+
+ // Check the panel.
+ await promiseOpenPageActionPanel();
+ EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
+ await promisePageActionPanelHidden();
+ Assert.deepEqual(
+ Array.from(BrowserPageActions.mainViewBodyNode.children, n => n.id),
+ initialActionsInPanel
+ .map(a => a.id)
+ .concat([
+ PageActions.ACTION_ID_BUILT_IN_SEPARATOR,
+ otherAction.id,
+ PageActions.ACTION_ID_TRANSIENT_SEPARATOR,
+ action.id,
+ ])
+ .map(id => BrowserPageActions.panelButtonNodeIDForActionID(id)),
+ "Actions in panel should be correct"
+ );
+
+ Assert.equal(
+ onPlacedInPanelCount,
+ 3,
+ "onPlacedInPanelCount should be inc'ed"
+ );
+ Assert.equal(
+ onBeforePlacedInWindowCount,
+ 3,
+ "onBeforePlacedInWindowCount should be inc'ed"
+ );
+
+ // Done, clean up.
+ action.remove();
+ otherAction.remove();
+});