var gInvalidFormPopup = document.getElementById("invalid-form-popup"); ok(gInvalidFormPopup, "The browser should have a popup to show when a form is invalid"); function checkPopupShow() { ok(gInvalidFormPopup.state == "showing" || gInvalidFormPopup.state == "open", "[Test " + testId + "] The invalid form popup should be shown"); } function checkPopupHide() { ok(gInvalidFormPopup.state != "showing" && gInvalidFormPopup.state != "open", "[Test " + testId + "] The invalid form popup should not be shown"); } var gObserver = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]), notifyInvalidSubmit(aFormElement, aInvalidElements) { } }; var testId = 0; function incrementTest() { testId++; info("Starting next part of test"); } function getDocHeader() { return "" + getEmptyFrame(); } function getDocFooter() { return ""; } function getEmptyFrame() { return ""; } 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; } async function clickChildElement(browser) { await ContentTask.spawn(browser, {}, async function() { content.document.getElementById("s").click(); }); } async function blurChildElement(browser) { await ContentTask.spawn(browser, {}, async function() { content.document.getElementById("i").blur(); }); } async function checkChildFocus(browser, message) { await ContentTask.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() + "
" + 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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden"); EventUtils.synthesizeKey("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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); await new Promise((resolve, reject) => { EventUtils.synthesizeKey("a", {}); executeSoon(function() { checkPopupShow(); 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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); let popupHiddenPromise = promiseWaitForEvent(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() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden"); EventUtils.synthesizeKey("VK_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() + "
" + getDocFooter(); let browser1 = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser1); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser1, gInvalidFormPopup.firstChild.textContent); let popupHiddenPromise = promiseWaitForEvent(gInvalidFormPopup, "popuphidden"); let browser2 = await openNewTab("data:text/html,"); await popupHiddenPromise; gBrowser.removeTab(gBrowser.getTabForBrowser(browser1)); gBrowser.removeTab(gBrowser.getTabForBrowser(browser2)); }); /** * In this test, we check that nothing happen if the invalid form is * submitted in a background tab. */ add_task(async function() { // Observers don't propagate currently across processes. We may add support for this in the // future via the addon compat layer. if (gMultiProcessBrowser) { return; } incrementTest(); let uri = getDocHeader() + "
" + getDocFooter(); let browser = await openNewTab(uri, true); isnot(gBrowser.selectedBrowser, browser, "This tab should have been loaded in background"); let notifierPromise = new Promise((resolve, reject) => { gObserver.notifyInvalidSubmit = function() { executeSoon(function() { checkPopupHide(); // Clean-up Services.obs.removeObserver(gObserver, "invalidformsubmit"); gObserver.notifyInvalidSubmit = function() {}; resolve(); }); }; Services.obs.addObserver(gObserver, "invalidformsubmit"); executeSoon(function() { browser.contentDocument.getElementById("s").click(); }); }); await notifierPromise; gBrowser.removeTab(gBrowser.getTabForBrowser(browser)); }); /** * In this test, we check that the author defined error message is shown. */ add_task(async function() { incrementTest(); let uri = getDocHeader() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); is(gInvalidFormPopup.firstChild.textContent, "foo", "The panel should show the author defined error message"); gBrowser.removeCurrentTab(); }); /** * In this test, we check that the message is correctly updated when it changes. */ add_task(async function() { incrementTest(); let uri = getDocHeader() + "
" + getDocFooter(); let browser = await openNewTab(uri); let popupShownPromise = promiseWaitForEvent(gInvalidFormPopup, "popupshown"); await clickChildElement(browser); await popupShownPromise; checkPopupShow(); await checkChildFocus(browser, gInvalidFormPopup.firstChild.textContent); let inputPromise = promiseWaitForEvent(gBrowser.contentDocument.getElementById("i"), "input"); EventUtils.synthesizeKey("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.firstChild.textContent); resolve(); }); }); gBrowser.removeCurrentTab(); });