/**
 * In this test, we check that the content can't open more than one popup at a
 * time (depending on "dom.allow_mulitple_popups" preference value).
 */

const TEST_DOMAIN = "http://example.net";
const TEST_PATH = "/browser/dom/base/test/";
const CHROME_DOMAIN = "chrome://mochitests/content";

requestLongerTimeout(2);

function WindowObserver(count) {
  return new Promise(resolve => {
    let windowObserver = function(aSubject, aTopic, aData) {
      if (aTopic != "domwindowopened") {
        return;
      }

      if (--count == 0) {
        Services.ww.unregisterNotification(windowObserver);
        resolve();
      }
    };
    Services.ww.registerNotification(windowObserver);
  });
}

add_task(async _ => {
  info("All opened if the pref is off");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", false],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openPopups",
    {},
    tab.linkedBrowser
  );

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s in a click event allowed because whitelisted domain.");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createContentPrincipal(
    uri,
    {}
  );

  Services.perms.addFromPrincipal(
    principal,
    "popup",
    Services.perms.ALLOW_ACTION
  );

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openPopups",
    {},
    tab.linkedBrowser
  );

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(
      Ci.nsIClearDataService.CLEAR_PERMISSIONS,
      value => {
        Assert.equal(value, 0);
        aResolve();
      }
    );
  });
});

add_task(async _ => {
  info(
    "2 window.open()s in a mouseup event allowed because whitelisted domain."
  );

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createContentPrincipal(
    uri,
    {}
  );

  Services.perms.addFromPrincipal(
    principal,
    "popup",
    Services.perms.ALLOW_ACTION
  );

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#input",
    { type: "mouseup" },
    tab.linkedBrowser
  );

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(
      Ci.nsIClearDataService.CLEAR_PERMISSIONS,
      value => {
        Assert.equal(value, 0);
        aResolve();
      }
    );
  });
});

add_task(async _ => {
  info(
    "2 window.open()s in a single click event: only the first one is allowed."
  );

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = SpecialPowers.spawn(browser, [], () => {
    return new content.Promise(resolve => {
      content.addEventListener(
        "DOMPopupBlocked",
        () => {
          ok(true, "The popup has been blocked");
          resolve();
        },
        { once: true }
      );
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openPopups",
    {},
    tab.linkedBrowser
  );

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info(
    "2 window.open()s in a single mouseup event: only the first one is allowed."
  );

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = SpecialPowers.spawn(browser, [], () => {
    return new content.Promise(resolve => {
      content.addEventListener(
        "DOMPopupBlocked",
        () => {
          ok(true, "The popup has been blocked");
          resolve();
        },
        { once: true }
      );
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#input",
    { type: "mouseup" },
    tab.linkedBrowser
  );

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s by non-event code: no windows allowed.");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  await SpecialPowers.spawn(browser, [], () => {
    return new content.Promise(resolve => {
      let count = 0;
      content.addEventListener("DOMPopupBlocked", function cb() {
        if (++count == 2) {
          content.removeEventListener("DOMPopupBlocked", cb);
          ok(true, "The popup has been blocked");
          resolve();
        }
      });

      let p = content.document.createElement("p");
      p.setAttribute("id", "start");
      content.document.body.appendChild(p);
    });
  });

  ok(true, "We had 0 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("2 window.open()s by non-event code allowed by permission");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  const uri = Services.io.newURI(TEST_DOMAIN);
  const principal = Services.scriptSecurityManager.createContentPrincipal(
    uri,
    {}
  );

  Services.perms.addFromPrincipal(
    principal,
    "popup",
    Services.perms.ALLOW_ACTION
  );

  let obs = new WindowObserver(2);

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html?openPopups"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);

  await new Promise(aResolve => {
    Services.clearData.deleteData(
      Ci.nsIClearDataService.CLEAR_PERMISSIONS,
      value => {
        Assert.equal(value, 0);
        aResolve();
      }
    );
  });
});

add_task(async _ => {
  info(
    "1 window.open() executing another window.open(): only the first one is allowed."
  );

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  // We don't receive DOMPopupBlocked for nested windows. Let's use just the observer.
  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openNestedPopups",
    {},
    tab.linkedBrowser
  );

  await obs;
  ok(true, "We had 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("window.open() and .click() on the element opening the window.");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    TEST_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let p = SpecialPowers.spawn(browser, [], () => {
    return new content.Promise(resolve => {
      content.addEventListener(
        "DOMPopupBlocked",
        () => {
          ok(true, "The popup has been blocked");
          resolve();
        },
        { once: true }
      );
    });
  });

  let obs = new WindowObserver(1);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openPopupAndClick",
    {},
    tab.linkedBrowser
  );

  await p;
  await obs;
  ok(true, "We had only 1 window.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});

add_task(async _ => {
  info("All opened from chrome.");

  await SpecialPowers.pushPrefEnv({
    set: [
      ["dom.block_multiple_popups", true],
      ["dom.disable_open_during_load", true],
    ],
  });

  let tab = BrowserTestUtils.addTab(
    gBrowser,
    CHROME_DOMAIN + TEST_PATH + "browser_multiple_popups.html"
  );
  gBrowser.selectedTab = tab;

  let browser = gBrowser.getBrowserForTab(tab);
  await BrowserTestUtils.browserLoaded(browser);

  let obs = new WindowObserver(2);

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#openPopups",
    {},
    tab.linkedBrowser
  );

  await obs;
  ok(true, "We had 2 windows.");

  await BrowserTestUtils.synthesizeMouseAtCenter(
    "#closeAllWindows",
    {},
    tab.linkedBrowser
  );

  BrowserTestUtils.removeTab(tab);
});
