browser_form_validation.js (12550B)
1 var gInvalidFormPopup = 2 gBrowser.selectedBrowser.browsingContext.currentWindowGlobal 3 .getActor("FormValidation") 4 ._getAndMaybeCreatePanel(document); 5 ok( 6 gInvalidFormPopup, 7 "The browser should have a popup to show when a form is invalid" 8 ); 9 10 function isWithinHalfPixel(a, b) { 11 return Math.abs(a - b) <= 0.5; 12 } 13 14 function checkPopupShow(anchorRect) { 15 ok( 16 gInvalidFormPopup.state == "showing" || gInvalidFormPopup.state == "open", 17 "[Test " + testId + "] The invalid form popup should be shown" 18 ); 19 // Just check the vertical position, as the horizontal position of an 20 // arrow panel will be offset. 21 is( 22 isWithinHalfPixel(gInvalidFormPopup.screenY), 23 isWithinHalfPixel(anchorRect.bottom), 24 "popup top" 25 ); 26 } 27 28 function checkPopupHide() { 29 ok( 30 gInvalidFormPopup.state != "showing" && gInvalidFormPopup.state != "open", 31 "[Test " + testId + "] The invalid form popup should not be shown" 32 ); 33 } 34 35 var testId = 0; 36 37 function incrementTest() { 38 testId++; 39 info("Starting next part of test"); 40 } 41 42 function getDocHeader() { 43 return "<html><head><meta charset='utf-8'></head><body>" + getEmptyFrame(); 44 } 45 46 function getDocFooter() { 47 return "</body></html>"; 48 } 49 50 function getEmptyFrame() { 51 return ( 52 "<iframe style='width:100px; height:30px; margin:3px; border:1px solid lightgray;' " + 53 "name='t' srcdoc=\"<html><head><meta charset='utf-8'></head><body>form target</body></html>\"></iframe>" 54 ); 55 } 56 57 async function openNewTab(uri, background) { 58 let tab = BrowserTestUtils.addTab(gBrowser); 59 let browser = gBrowser.getBrowserForTab(tab); 60 if (!background) { 61 gBrowser.selectedTab = tab; 62 } 63 await BrowserTestUtils.loadURIString({ 64 browser: tab.linkedBrowser, 65 uriString: "data:text/html," + escape(uri), 66 }); 67 return browser; 68 } 69 70 function clickChildElement(browser) { 71 return SpecialPowers.spawn(browser, [], async function () { 72 let element = content.document.getElementById("s"); 73 element.click(); 74 return { 75 bottom: content.mozInnerScreenY + element.getBoundingClientRect().bottom, 76 }; 77 }); 78 } 79 80 async function blurChildElement(browser) { 81 await SpecialPowers.spawn(browser, [], async function () { 82 content.document.getElementById("i").blur(); 83 }); 84 } 85 86 async function checkChildFocus(browser, message) { 87 await SpecialPowers.spawn( 88 browser, 89 [[message, testId]], 90 async function (args) { 91 let [msg, id] = args; 92 var focused = 93 content.document.activeElement == content.document.getElementById("i"); 94 95 var validMsg = true; 96 if (msg) { 97 validMsg = 98 msg == content.document.getElementById("i").validationMessage; 99 } 100 101 Assert.equal( 102 focused, 103 true, 104 "Test " + id + " First invalid element should be focused" 105 ); 106 Assert.equal( 107 validMsg, 108 true, 109 "Test " + 110 id + 111 " The panel should show the message from validationMessage" 112 ); 113 } 114 ); 115 } 116 117 /** 118 * In this test, we check that no popup appears if the form is valid. 119 */ 120 add_task(async function () { 121 incrementTest(); 122 let uri = 123 getDocHeader() + 124 "<form target='t' action='data:text/html,'><input><input id='s' type='submit'></form>" + 125 getDocFooter(); 126 let browser = await openNewTab(uri); 127 128 await clickChildElement(browser); 129 130 await new Promise(resolve => { 131 // XXXndeakin This isn't really going to work when the content is another process 132 executeSoon(function () { 133 checkPopupHide(); 134 resolve(); 135 }); 136 }); 137 138 gBrowser.removeCurrentTab(); 139 }); 140 141 /** 142 * In this test, we check that, when an invalid form is submitted, 143 * the invalid element is focused and a popup appears. 144 */ 145 add_task(async function () { 146 incrementTest(); 147 let uri = 148 getDocHeader() + 149 "<form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>" + 150 getDocFooter(); 151 let browser = await openNewTab(uri); 152 153 let popupShownPromise = BrowserTestUtils.waitForEvent( 154 gInvalidFormPopup, 155 "popupshown" 156 ); 157 let anchorRect = await clickChildElement(browser); 158 await popupShownPromise; 159 160 checkPopupShow(anchorRect); 161 162 await checkChildFocus( 163 browser, 164 gInvalidFormPopup.firstElementChild.textContent 165 ); 166 167 gBrowser.removeCurrentTab(); 168 }); 169 170 /** 171 * In this test, we check that, when an invalid form is submitted, 172 * the first invalid element is focused and a popup appears. 173 */ 174 add_task(async function () { 175 incrementTest(); 176 let uri = 177 getDocHeader() + 178 "<form target='t' action='data:text/html,'><input><input id='i' required><input required><input id='s' type='submit'></form>" + 179 getDocFooter(); 180 let browser = await openNewTab(uri); 181 182 let popupShownPromise = BrowserTestUtils.waitForEvent( 183 gInvalidFormPopup, 184 "popupshown" 185 ); 186 let anchorRect = await clickChildElement(browser); 187 await popupShownPromise; 188 189 checkPopupShow(anchorRect); 190 await checkChildFocus( 191 browser, 192 gInvalidFormPopup.firstElementChild.textContent 193 ); 194 195 gBrowser.removeCurrentTab(); 196 }); 197 198 /** 199 * In this test, we check that, we hide the popup by interacting with the 200 * invalid element if the element becomes valid. 201 */ 202 add_task(async function () { 203 incrementTest(); 204 let uri = 205 getDocHeader() + 206 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 207 getDocFooter(); 208 let browser = await openNewTab(uri); 209 210 let popupShownPromise = BrowserTestUtils.waitForEvent( 211 gInvalidFormPopup, 212 "popupshown" 213 ); 214 let anchorRect = await clickChildElement(browser); 215 await popupShownPromise; 216 217 checkPopupShow(anchorRect); 218 await checkChildFocus( 219 browser, 220 gInvalidFormPopup.firstElementChild.textContent 221 ); 222 223 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 224 gInvalidFormPopup, 225 "popuphidden" 226 ); 227 EventUtils.sendString("a"); 228 await popupHiddenPromise; 229 230 gBrowser.removeCurrentTab(); 231 }); 232 233 /** 234 * In this test, we check that, we don't hide the popup by interacting with the 235 * invalid element if the element is still invalid. 236 */ 237 add_task(async function () { 238 incrementTest(); 239 let uri = 240 getDocHeader() + 241 "<form target='t' action='data:text/html,'><input type='email' id='i' required><input id='s' type='submit'></form>" + 242 getDocFooter(); 243 let browser = await openNewTab(uri); 244 245 let popupShownPromise = BrowserTestUtils.waitForEvent( 246 gInvalidFormPopup, 247 "popupshown" 248 ); 249 let anchorRect = await clickChildElement(browser); 250 await popupShownPromise; 251 252 checkPopupShow(anchorRect); 253 await checkChildFocus( 254 browser, 255 gInvalidFormPopup.firstElementChild.textContent 256 ); 257 258 await new Promise(resolve => { 259 EventUtils.sendString("a"); 260 executeSoon(function () { 261 checkPopupShow(anchorRect); 262 resolve(); 263 }); 264 }); 265 266 gBrowser.removeCurrentTab(); 267 }); 268 269 /** 270 * In this test, we check that we can hide the popup by blurring the invalid 271 * element. 272 */ 273 add_task(async function () { 274 incrementTest(); 275 let uri = 276 getDocHeader() + 277 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 278 getDocFooter(); 279 let browser = await openNewTab(uri); 280 281 let popupShownPromise = BrowserTestUtils.waitForEvent( 282 gInvalidFormPopup, 283 "popupshown" 284 ); 285 let anchorRect = await clickChildElement(browser); 286 await popupShownPromise; 287 288 checkPopupShow(anchorRect); 289 await checkChildFocus( 290 browser, 291 gInvalidFormPopup.firstElementChild.textContent 292 ); 293 294 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 295 gInvalidFormPopup, 296 "popuphidden" 297 ); 298 await blurChildElement(browser); 299 await popupHiddenPromise; 300 301 gBrowser.removeCurrentTab(); 302 }); 303 304 /** 305 * In this test, we check that we can hide the popup by pressing TAB. 306 */ 307 add_task(async function () { 308 incrementTest(); 309 let uri = 310 getDocHeader() + 311 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 312 getDocFooter(); 313 let browser = await openNewTab(uri); 314 315 let popupShownPromise = BrowserTestUtils.waitForEvent( 316 gInvalidFormPopup, 317 "popupshown" 318 ); 319 let anchorRect = await clickChildElement(browser); 320 await popupShownPromise; 321 322 checkPopupShow(anchorRect); 323 await checkChildFocus( 324 browser, 325 gInvalidFormPopup.firstElementChild.textContent 326 ); 327 328 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 329 gInvalidFormPopup, 330 "popuphidden" 331 ); 332 EventUtils.synthesizeKey("KEY_Tab"); 333 await popupHiddenPromise; 334 335 gBrowser.removeCurrentTab(); 336 }); 337 338 /** 339 * In this test, we check that the popup will hide if we move to another tab. 340 */ 341 add_task(async function () { 342 incrementTest(); 343 let uri = 344 getDocHeader() + 345 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 346 getDocFooter(); 347 let browser1 = await openNewTab(uri); 348 349 let popupShownPromise = BrowserTestUtils.waitForEvent( 350 gInvalidFormPopup, 351 "popupshown" 352 ); 353 let anchorRect = await clickChildElement(browser1); 354 await popupShownPromise; 355 356 checkPopupShow(anchorRect); 357 await checkChildFocus( 358 browser1, 359 gInvalidFormPopup.firstElementChild.textContent 360 ); 361 362 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 363 gInvalidFormPopup, 364 "popuphidden" 365 ); 366 367 let browser2 = await openNewTab("data:text/html,<html></html>"); 368 await popupHiddenPromise; 369 370 gBrowser.removeTab(gBrowser.getTabForBrowser(browser1)); 371 gBrowser.removeTab(gBrowser.getTabForBrowser(browser2)); 372 }); 373 374 /** 375 * In this test, we check that the popup will hide if we navigate to another 376 * page. 377 */ 378 add_task(async function () { 379 incrementTest(); 380 let uri = 381 getDocHeader() + 382 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 383 getDocFooter(); 384 let browser = await openNewTab(uri); 385 386 let popupShownPromise = BrowserTestUtils.waitForEvent( 387 gInvalidFormPopup, 388 "popupshown" 389 ); 390 let anchorRect = await clickChildElement(browser); 391 await popupShownPromise; 392 393 checkPopupShow(anchorRect); 394 await checkChildFocus( 395 browser, 396 gInvalidFormPopup.firstElementChild.textContent 397 ); 398 399 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 400 gInvalidFormPopup, 401 "popuphidden" 402 ); 403 BrowserTestUtils.startLoadingURIString( 404 browser, 405 "data:text/html,<div>hello!</div>" 406 ); 407 await BrowserTestUtils.browserLoaded(browser); 408 409 await popupHiddenPromise; 410 411 gBrowser.removeCurrentTab(); 412 }); 413 414 /** 415 * In this test, we check that the message is correctly updated when it changes. 416 */ 417 add_task(async function () { 418 incrementTest(); 419 let uri = 420 getDocHeader() + 421 "<form target='t' action='data:text/html,'><input type='email' required id='i'><input id='s' type='submit'></form>" + 422 getDocFooter(); 423 let browser = await openNewTab(uri); 424 425 let popupShownPromise = BrowserTestUtils.waitForEvent( 426 gInvalidFormPopup, 427 "popupshown" 428 ); 429 let anchorRect = await clickChildElement(browser); 430 await popupShownPromise; 431 432 checkPopupShow(anchorRect); 433 await checkChildFocus( 434 browser, 435 gInvalidFormPopup.firstElementChild.textContent 436 ); 437 438 let inputPromise = BrowserTestUtils.waitForContentEvent(browser, "input"); 439 EventUtils.sendString("f"); 440 await inputPromise; 441 442 // Now, the element suffers from another error, the message should have 443 // been updated. 444 await new Promise(resolve => { 445 // XXXndeakin This isn't really going to work when the content is another process 446 executeSoon(function () { 447 checkChildFocus(browser, gInvalidFormPopup.firstElementChild.textContent); 448 resolve(); 449 }); 450 }); 451 452 gBrowser.removeCurrentTab(); 453 }); 454 455 /** 456 * In this test, we reload the page while the form validation popup is visible. The validation 457 * popup should hide. 458 */ 459 add_task(async function () { 460 incrementTest(); 461 let uri = 462 getDocHeader() + 463 "<form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>" + 464 getDocFooter(); 465 let browser = await openNewTab(uri); 466 467 let popupShownPromise = BrowserTestUtils.waitForEvent( 468 gInvalidFormPopup, 469 "popupshown" 470 ); 471 let anchorRect = await clickChildElement(browser); 472 await popupShownPromise; 473 474 checkPopupShow(anchorRect); 475 await checkChildFocus( 476 browser, 477 gInvalidFormPopup.firstElementChild.textContent 478 ); 479 480 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 481 gInvalidFormPopup, 482 "popuphidden" 483 ); 484 BrowserCommands.reloadSkipCache(); 485 await popupHiddenPromise; 486 487 gBrowser.removeCurrentTab(); 488 });