summaryrefslogtreecommitdiffstats
path: root/browser/modules/test/browser/formValidation/browser_form_validation.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules/test/browser/formValidation/browser_form_validation.js')
-rw-r--r--browser/modules/test/browser/formValidation/browser_form_validation.js519
1 files changed, 519 insertions, 0 deletions
diff --git a/browser/modules/test/browser/formValidation/browser_form_validation.js b/browser/modules/test/browser/formValidation/browser_form_validation.js
new file mode 100644
index 0000000000..a1cbc4d88d
--- /dev/null
+++ b/browser/modules/test/browser/formValidation/browser_form_validation.js
@@ -0,0 +1,519 @@
+/**
+ * COPIED FROM browser/base/content/test/general/head.js.
+ * This function should be removed and replaced with BTU withNewTab calls
+ *
+ * Waits for a load (or custom) event to finish in a given tab. If provided
+ * load an uri into the tab.
+ *
+ * @param tab
+ * The tab to load into.
+ * @param [optional] url
+ * The url to load, or the current url.
+ * @return {Promise} resolved when the event is handled.
+ * @resolves to the received event
+ * @rejects if a valid load event is not received within a meaningful interval
+ */
+function promiseTabLoadEvent(tab, url) {
+ info("Wait tab event: load");
+
+ function handle(loadedUrl) {
+ if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
+ info(`Skipping spurious load event for ${loadedUrl}`);
+ return false;
+ }
+
+ info("Tab event received: load");
+ return true;
+ }
+
+ let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
+
+ if (url) {
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, url);
+ }
+
+ return loaded;
+}
+
+var gInvalidFormPopup =
+ gBrowser.selectedBrowser.browsingContext.currentWindowGlobal
+ .getActor("FormValidation")
+ ._getAndMaybeCreatePanel(document);
+ok(
+ gInvalidFormPopup,
+ "The browser should have a popup to show when a form is invalid"
+);
+
+function isWithinHalfPixel(a, b) {
+ return Math.abs(a - b) <= 0.5;
+}
+
+function checkPopupShow(anchorRect) {
+ ok(
+ gInvalidFormPopup.state == "showing" || gInvalidFormPopup.state == "open",
+ "[Test " + testId + "] The invalid form popup should be shown"
+ );
+ // Just check the vertical position, as the horizontal position of an
+ // arrow panel will be offset.
+ is(
+ isWithinHalfPixel(gInvalidFormPopup.screenY),
+ isWithinHalfPixel(anchorRect.bottom),
+ "popup top"
+ );
+}
+
+function checkPopupHide() {
+ ok(
+ gInvalidFormPopup.state != "showing" && gInvalidFormPopup.state != "open",
+ "[Test " + testId + "] The invalid form popup should not be shown"
+ );
+}
+
+var testId = 0;
+
+function incrementTest() {
+ testId++;
+ info("Starting next part of test");
+}
+
+function getDocHeader() {
+ return "<html><head><meta charset='utf-8'></head><body>" + getEmptyFrame();
+}
+
+function getDocFooter() {
+ return "</body></html>";
+}
+
+function getEmptyFrame() {
+ return (
+ "<iframe style='width:100px; height:30px; margin:3px; border:1px solid lightgray;' " +
+ "name='t' srcdoc=\"<html><head><meta charset='utf-8'></head><body>form target</body></html>\"></iframe>"
+ );
+}
+
+async function openNewTab(uri, background) {
+ let tab = BrowserTestUtils.addTab(gBrowser);
+ let browser = gBrowser.getBrowserForTab(tab);
+ if (!background) {
+ gBrowser.selectedTab = tab;
+ }
+ await promiseTabLoadEvent(tab, "data:text/html," + escape(uri));
+ return browser;
+}
+
+function clickChildElement(browser) {
+ return SpecialPowers.spawn(browser, [], async function () {
+ let element = content.document.getElementById("s");
+ element.click();
+ return {
+ bottom: content.mozInnerScreenY + element.getBoundingClientRect().bottom,
+ };
+ });
+}
+
+async function blurChildElement(browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ content.document.getElementById("i").blur();
+ });
+}
+
+async function checkChildFocus(browser, message) {
+ await SpecialPowers.spawn(
+ browser,
+ [[message, testId]],
+ async function (args) {
+ let [msg, id] = args;
+ var focused =
+ content.document.activeElement == content.document.getElementById("i");
+
+ var validMsg = true;
+ if (msg) {
+ validMsg =
+ msg == content.document.getElementById("i").validationMessage;
+ }
+
+ Assert.equal(
+ focused,
+ true,
+ "Test " + id + " First invalid element should be focused"
+ );
+ Assert.equal(
+ validMsg,
+ true,
+ "Test " +
+ id +
+ " The panel should show the message from validationMessage"
+ );
+ }
+ );
+}
+
+/**
+ * In this test, we check that no popup appears if the form is valid.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ await clickChildElement(browser);
+
+ await new Promise((resolve, reject) => {
+ // XXXndeakin This isn't really going to work when the content is another process
+ executeSoon(function () {
+ checkPopupHide();
+ resolve();
+ });
+ });
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that, when an invalid form is submitted,
+ * the invalid element is focused and a popup appears.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that, when an invalid form is submitted,
+ * the first invalid element is focused and a popup appears.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input><input id='i' required><input required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that, we hide the popup by interacting with the
+ * invalid element if the element becomes valid.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+ EventUtils.sendString("a");
+ await popupHiddenPromise;
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that, we don't hide the popup by interacting with the
+ * invalid element if the element is still invalid.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input type='email' id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ await new Promise((resolve, reject) => {
+ EventUtils.sendString("a");
+ executeSoon(function () {
+ checkPopupShow(anchorRect);
+ resolve();
+ });
+ });
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that we can hide the popup by blurring the invalid
+ * element.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+ await blurChildElement(browser);
+ await popupHiddenPromise;
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that we can hide the popup by pressing TAB.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Tab");
+ await popupHiddenPromise;
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that the popup will hide if we move to another tab.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser1 = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser1);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser1,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+
+ let browser2 = await openNewTab("data:text/html,<html></html>");
+ await popupHiddenPromise;
+
+ gBrowser.removeTab(gBrowser.getTabForBrowser(browser1));
+ gBrowser.removeTab(gBrowser.getTabForBrowser(browser2));
+});
+
+/**
+ * In this test, we check that the popup will hide if we navigate to another
+ * page.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+ BrowserTestUtils.loadURIString(browser, "data:text/html,<div>hello!</div>");
+ await BrowserTestUtils.browserLoaded(browser);
+
+ await popupHiddenPromise;
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we check that the message is correctly updated when it changes.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input type='email' required id='i'><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let inputPromise = BrowserTestUtils.waitForContentEvent(browser, "input");
+ EventUtils.sendString("f");
+ await inputPromise;
+
+ // Now, the element suffers from another error, the message should have
+ // been updated.
+ await new Promise((resolve, reject) => {
+ // XXXndeakin This isn't really going to work when the content is another process
+ executeSoon(function () {
+ checkChildFocus(browser, gInvalidFormPopup.firstElementChild.textContent);
+ resolve();
+ });
+ });
+
+ gBrowser.removeCurrentTab();
+});
+
+/**
+ * In this test, we reload the page while the form validation popup is visible. The validation
+ * popup should hide.
+ */
+add_task(async function () {
+ incrementTest();
+ let uri =
+ getDocHeader() +
+ "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" +
+ getDocFooter();
+ let browser = await openNewTab(uri);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popupshown"
+ );
+ let anchorRect = await clickChildElement(browser);
+ await popupShownPromise;
+
+ checkPopupShow(anchorRect);
+ await checkChildFocus(
+ browser,
+ gInvalidFormPopup.firstElementChild.textContent
+ );
+
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(
+ gInvalidFormPopup,
+ "popuphidden"
+ );
+ BrowserReloadSkipCache();
+ await popupHiddenPromise;
+
+ gBrowser.removeCurrentTab();
+});