<!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: {
    browser_specific_settings: {
      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>
