test_autofillFormFields.js (33454B)
1 /* 2 * Test for form auto fill content helper fill all inputs function. 3 */ 4 /* eslint-disable mozilla/no-arbitrary-setTimeout */ 5 6 "use strict"; 7 8 const { setTimeout, clearTimeout } = ChromeUtils.importESModule( 9 "resource://gre/modules/Timer.sys.mjs" 10 ); 11 12 const TESTCASES = [ 13 { 14 description: "Form without autocomplete property", 15 document: `<form><input id="given-name"><input id="family-name"> 16 <input id="street-addr"><input id="city"><select id="country"></select> 17 <input id='email'><input id="tel"></form>`, 18 focusedInputId: "given-name", 19 profileData: {}, 20 expectedResult: { 21 "street-addr": "", 22 city: "", 23 country: "", 24 email: "", 25 tel: "", 26 }, 27 }, 28 { 29 description: "Form with autocomplete properties and 1 token", 30 document: `<form><input id="given-name" autocomplete="given-name"> 31 <input id="family-name" autocomplete="family-name"> 32 <input id="street-addr" autocomplete="street-address"> 33 <input id="city" autocomplete="address-level2"> 34 <select id="country" autocomplete="country"> 35 <option/> 36 <option value="US">United States</option> 37 </select> 38 <input id="email" autocomplete="email"> 39 <input id="tel" autocomplete="tel"></form>`, 40 focusedInputId: "given-name", 41 profileData: { 42 guid: "123", 43 "street-address": "2 Harrison St line2", 44 "-moz-street-address-one-line": "2 Harrison St line2", 45 "address-level2": "San Francisco", 46 country: "US", 47 email: "foo@mozilla.com", 48 tel: "1234567", 49 }, 50 expectedResult: { 51 "street-addr": "2 Harrison St line2", 52 city: "San Francisco", 53 country: "US", 54 email: "foo@mozilla.com", 55 tel: "1234567", 56 }, 57 }, 58 { 59 description: "Form with autocomplete properties and 2 tokens", 60 document: `<form><input id="given-name" autocomplete="shipping given-name"> 61 <input id="family-name" autocomplete="shipping family-name"> 62 <input id="street-addr" autocomplete="shipping street-address"> 63 <input id="city" autocomplete="shipping address-level2"> 64 <select id="country" autocomplete="shipping country"> 65 <option/> 66 <option value="US">United States</option> 67 </select> 68 <input id='email' autocomplete="shipping email"> 69 <input id="tel" autocomplete="shipping tel"></form>`, 70 focusedInputId: "given-name", 71 profileData: { 72 guid: "123", 73 "street-address": "2 Harrison St", 74 "address-level2": "San Francisco", 75 country: "US", 76 email: "foo@mozilla.com", 77 tel: "1234567", 78 }, 79 expectedResult: { 80 "street-addr": "2 Harrison St", 81 city: "San Francisco", 82 country: "US", 83 email: "foo@mozilla.com", 84 tel: "1234567", 85 }, 86 }, 87 { 88 description: 89 "Form with autocomplete properties and profile is partly matched", 90 document: `<form><input id="given-name" autocomplete="shipping given-name"> 91 <input id="family-name" autocomplete="shipping family-name"> 92 <input id="street-addr" autocomplete="shipping street-address"> 93 <input id="city" autocomplete="shipping address-level2"> 94 <input id="country" autocomplete="shipping country"> 95 <input id='email' autocomplete="shipping email"> 96 <input id="tel" autocomplete="shipping tel"></form>`, 97 focusedInputId: "given-name", 98 profileData: { 99 guid: "123", 100 "street-address": "2 Harrison St", 101 "address-level2": "San Francisco", 102 country: "US", 103 email: "", 104 tel: "", 105 }, 106 expectedResult: { 107 "street-addr": "2 Harrison St", 108 city: "San Francisco", 109 country: "US", 110 email: "", 111 tel: "", 112 }, 113 }, 114 { 115 description: "Form with autocomplete properties but mismatched", 116 document: `<form><input id="given-name" autocomplete="shipping given-name"> 117 <input id="family-name" autocomplete="shipping family-name"> 118 <input id="street-addr" autocomplete="billing street-address"> 119 <input id="city" autocomplete="billing address-level2"> 120 <input id="country" autocomplete="billing country"> 121 <input id='email' autocomplete="shipping email"> 122 <input id="tel" autocomplete="shipping tel"></form>`, 123 focusedInputId: "given-name", 124 profileData: { 125 "street-address": "", 126 "address-level2": "", 127 country: "", 128 email: "foo@mozilla.com", 129 tel: "1234567", 130 }, 131 expectedResult: { 132 "street-addr": "", 133 city: "", 134 country: "", 135 email: "foo@mozilla.com", 136 tel: "1234567", 137 }, 138 }, 139 { 140 description: `Form with elements that have autocomplete set to "off"`, 141 document: `<form> 142 <input id="given-name" autocomplete="off"> 143 <input id="family-name" autocomplete="off"> 144 <input id="street-address" autocomplete="off"> 145 <input id="organization" autocomplete="off"> 146 <input id="country" autocomplete="off"> 147 </form>`, 148 focusedInputId: "given-name", 149 profileData: { 150 "given-name": "John", 151 "family-name": "Doe", 152 "street-address": "2 Harrison St", 153 country: "US", 154 organization: "Test organization", 155 }, 156 expectedResult: { 157 "given-name": "John", 158 "family-name": "Doe", 159 "street-address": "2 Harrison St", 160 organization: "Test organization", 161 country: "US", 162 }, 163 }, 164 { 165 description: `Form with autocomplete set to "off" and no autocomplete attribute on the form's elements`, 166 document: `<form autocomplete="off"> 167 <input id="given-name"> 168 <input id="family-name"> 169 <input id="street-address"> 170 <input id="city"> 171 <input id="country"> 172 </form>`, 173 focusedInputId: "given-name", 174 profileData: { 175 "given-name": "John", 176 "family-name": "Doe", 177 "street-address": "2 Harrison St", 178 country: "US", 179 "address-level2": "Somewhere", 180 }, 181 expectedResult: { 182 "given-name": "John", 183 "family-name": "Doe", 184 "street-address": "2 Harrison St", 185 city: "Somewhere", 186 country: "US", 187 }, 188 }, 189 { 190 description: 191 "Form with autocomplete select elements and matching option values", 192 document: `<form> 193 <input id="given-name" autocomplete="shipping given-name"> 194 <select id="country" autocomplete="shipping country"> 195 <option value=""></option> 196 <option value="US">United States</option> 197 </select> 198 <select id="state" autocomplete="shipping address-level1"> 199 <option value=""></option> 200 <option value="CA">California</option> 201 <option value="WA">Washington</option> 202 </select> 203 </form>`, 204 focusedInputId: "given-name", 205 profileData: { 206 country: "US", 207 "address-level1": "CA", 208 }, 209 expectedResult: { 210 country: "US", 211 state: "CA", 212 }, 213 }, 214 { 215 description: 216 "Form with autocomplete select elements and matching option texts", 217 document: `<form> 218 <input id="given-name" autocomplete="shipping given-name"> 219 <select id="country" autocomplete="shipping country"> 220 <option value=""></option> 221 <option value="US">United States</option> 222 </select> 223 <select id="state" autocomplete="shipping address-level1"> 224 <option value=""></option> 225 <option value="CA">California</option> 226 <option value="WA">Washington</option> 227 </select> 228 </form>`, 229 focusedInputId: "given-name", 230 profileData: { 231 country: "United States", 232 "address-level1": "California", 233 }, 234 expectedResult: { 235 country: "US", 236 state: "CA", 237 }, 238 }, 239 { 240 description: "Form with a readonly input and non-readonly inputs", 241 document: `<form> 242 <input id="given-name" autocomplete="given-name"> 243 <input id="family-name" autocomplete="family-name"> 244 <input id="street-addr" autocomplete="street-address"> 245 <input id="city" autocomplete="address-level2" readonly value="TEST CITY"> 246 </form>`, 247 focusedInputId: "given-name", 248 profileData: { 249 "given-name": "John", 250 "family-name": "Doe", 251 "street-address": "100 Main Street", 252 city: "Hamilton", 253 }, 254 expectedResult: { 255 "given-name": "John", 256 "family-name": "Doe", 257 "street-addr": "100 Main Street", 258 city: "TEST CITY", 259 }, 260 }, 261 { 262 description: "Fill address fields in a form with addr and CC fields.", 263 document: `<form> 264 <input id="given-name" autocomplete="given-name"> 265 <input id="family-name" autocomplete="family-name"> 266 <input id="street-addr" autocomplete="street-address"> 267 <input id="city" autocomplete="address-level2"> 268 <select id="country" autocomplete="country"> 269 <option/> 270 <option value="US">United States</option> 271 </select> 272 <input id="email" autocomplete="email"> 273 <input id="tel" autocomplete="tel"> 274 <input id="cc-number" autocomplete="cc-number"> 275 <input id="cc-name" autocomplete="cc-name"> 276 <input id="cc-exp-month" autocomplete="cc-exp-month"> 277 <input id="cc-exp-year" autocomplete="cc-exp-year"> 278 </form>`, 279 focusedInputId: "given-name", 280 profileData: { 281 "street-address": "2 Harrison St line2", 282 "-moz-street-address-one-line": "2 Harrison St line2", 283 "address-level2": "San Francisco", 284 country: "US", 285 email: "foo@mozilla.com", 286 tel: "1234567", 287 }, 288 expectedResult: { 289 "street-addr": "2 Harrison St line2", 290 city: "San Francisco", 291 country: "US", 292 email: "foo@mozilla.com", 293 tel: "1234567", 294 "cc-number": "", 295 "cc-name": "", 296 "cc-exp-month": "", 297 "cc-exp-year": "", 298 }, 299 }, 300 { 301 description: 302 "Fill credit card fields in a form with address and CC fields.", 303 document: `<form> 304 <input id="given-name" autocomplete="given-name"> 305 <input id="family-name" autocomplete="family-name"> 306 <input id="street-addr" autocomplete="street-address"> 307 <input id="city" autocomplete="address-level2"> 308 <select id="country" autocomplete="country"> 309 <option/> 310 <option value="US">United States</option> 311 </select> 312 <input id="email" autocomplete="email"> 313 <input id="tel" autocomplete="tel"> 314 <input id="cc-number" autocomplete="cc-number"> 315 <input id="cc-name" autocomplete="cc-name"> 316 <input id="cc-exp-month" autocomplete="cc-exp-month"> 317 <input id="cc-exp-year" autocomplete="cc-exp-year"> 318 </form>`, 319 focusedInputId: "cc-number", 320 profileData: { 321 "cc-number": "4111111111111111", 322 "cc-name": "test name", 323 "cc-exp-month": 6, 324 "cc-exp-year": 25, 325 }, 326 expectedResult: { 327 "street-addr": "", 328 city: "", 329 country: "", 330 email: "", 331 tel: "", 332 "cc-number": "4111111111111111", 333 "cc-name": "test name", 334 "cc-exp-month": "06", 335 "cc-exp-year": "25", 336 }, 337 }, 338 { 339 description: 340 "Fill credit card fields in a form with a placeholder on expiration month input field", 341 document: `<form> 342 <input id="cc-number" autocomplete="cc-number"> 343 <input id="cc-name" autocomplete="cc-name"> 344 <input id="cc-exp-month" autocomplete="cc-exp-month" placeholder="MM"> 345 <input id="cc-exp-year" autocomplete="cc-exp-year"> 346 </form> 347 `, 348 focusedInputId: "cc-number", 349 profileData: { 350 "cc-number": "4111111111111111", 351 "cc-name": "test name", 352 "cc-exp-month": 6, 353 "cc-exp-year": 25, 354 }, 355 expectedResult: { 356 "cc-number": "4111111111111111", 357 "cc-name": "test name", 358 "cc-exp-month": "06", 359 "cc-exp-year": "25", 360 }, 361 }, 362 { 363 description: 364 "Fill credit card fields in a form without a placeholder on expiration month and expiration year input fields", 365 document: `<form> 366 <input id="cc-number" autocomplete="cc-number"> 367 <input id="cc-name" autocomplete="cc-name"> 368 <input id="cc-exp-month" autocomplete="cc-exp-month"> 369 <input id="cc-exp-year" autocomplete="cc-exp-year"> 370 </form> 371 `, 372 focusedInputId: "cc-number", 373 profileData: { 374 "cc-number": "4111111111111111", 375 "cc-name": "test name", 376 "cc-exp-month": 6, 377 "cc-exp-year": 25, 378 }, 379 expectedResult: { 380 "cc-number": "4111111111111111", 381 "cc-name": "test name", 382 "cc-exp-month": "06", 383 "cc-exp-year": "25", 384 }, 385 }, 386 { 387 description: 388 "Fill credit card fields in a form with a placeholder on expiration year input field", 389 document: `<form> 390 <input id="cc-number" autocomplete="cc-number"> 391 <input id="cc-name" autocomplete="cc-name"> 392 <input id="cc-exp-month" autocomplete="cc-exp-month"> 393 <input id="cc-exp-year" autocomplete="cc-exp-year" placeholder="YY"> 394 </form> 395 `, 396 focusedInputId: "cc-number", 397 profileData: { 398 "cc-number": "4111111111111111", 399 "cc-name": "test name", 400 "cc-exp-month": 6, 401 "cc-exp-year": 2025, 402 }, 403 expectedResult: { 404 "cc-number": "4111111111111111", 405 "cc-name": "test name", 406 "cc-exp-month": "06", 407 "cc-exp-year": "25", 408 }, 409 }, 410 { 411 description: 412 "Form with hidden input and visible input that share the same autocomplete attribute", 413 document: `<form> 414 <input id="hidden-cc" autocomplete="cc-number" hidden> 415 <input id="hidden-cc-2" autocomplete="cc-number" style="display:none"> 416 <input id="visible-cc" autocomplete="cc-number"> 417 <input id="hidden-name" autocomplete="cc-name" hidden> 418 <input id="hidden-name-2" autocomplete="cc-name" style="display:none"> 419 <input id="visible-name" autocomplete="cc-name"> 420 <input id="cc-exp-month" autocomplete="cc-exp-month"> 421 <input id="cc-exp-year" autocomplete="cc-exp-year"> 422 </form>`, 423 focusedInputId: "visible-cc", 424 profileData: { 425 "cc-number": "4111111111111111", 426 "cc-name": "test name", 427 "cc-exp-month": 6, 428 "cc-exp-year": 25, 429 }, 430 expectedResult: { 431 "visible-cc": "4111111111111111", 432 "visible-name": "test name", 433 "cc-exp-month": "06", 434 "cc-exp-year": "25", 435 "hidden-cc": "4111111111111111", 436 "hidden-cc-2": "4111111111111111", 437 "hidden-name": "test name", 438 "hidden-name-2": "test name", 439 }, 440 }, 441 { 442 description: 443 "Fill credit card fields in a form where the value property is being used as a placeholder for cardholder name", 444 document: `<form> 445 <input id="cc-number" autocomplete="cc-number"> 446 <input id="cc-name" autocomplete="cc-name" value="JOHN DOE"> 447 <input id="cc-exp-month" autocomplete="cc-exp-month"> 448 <input id="cc-exp-year" autocomplete="cc-exp-year"> 449 </form>`, 450 focusedInputId: "cc-number", 451 profileData: { 452 "cc-number": "4111111111111111", 453 "cc-name": "test name", 454 "cc-exp-month": 6, 455 "cc-exp-year": 25, 456 }, 457 expectedResult: { 458 "cc-number": "4111111111111111", 459 "cc-name": "test name", 460 "cc-exp-month": "06", 461 "cc-exp-year": "25", 462 }, 463 }, 464 { 465 description: 466 "Fill credit card number fields in a form with multiple cc-number inputs", 467 document: `<form> 468 <input id="cc-number1" maxlength="4"> 469 <input id="cc-number2" maxlength="4"> 470 <input id="cc-number3" maxlength="4"> 471 <input id="cc-number4" maxlength="4"> 472 <input id="cc-exp-month" autocomplete="cc-exp-month"> 473 <input id="cc-exp-year" autocomplete="cc-exp-year"> 474 </form>`, 475 focusedInputId: "cc-number1", 476 profileData: { 477 "cc-number": "371449635398431", 478 "cc-exp-month": 6, 479 "cc-exp-year": 25, 480 }, 481 expectedResult: { 482 "cc-number1": "3714", 483 "cc-number2": "4963", 484 "cc-number3": "5398", 485 "cc-number4": "431", 486 "cc-exp-month": "06", 487 "cc-exp-year": "25", 488 }, 489 }, 490 // TODO: Bug 1902233 - Migrate this test to browser test 491 //{ 492 //description: 493 //"Fill credit card number fields in a form with multiple valid credit card sections", 494 //document: `<form> 495 //<input id="cc-type1"> 496 //<input id="cc-number1" maxlength="4"> 497 //<input id="cc-number2" maxlength="4"> 498 //<input id="cc-number3" maxlength="4"> 499 //<input id="cc-number4" maxlength="4"> 500 //<input id="cc-exp-month1"> 501 //<input id="cc-exp-year1"> 502 //<input id="cc-type2"> 503 //<input id="cc-number5" maxlength="4"> 504 //<input id="cc-number6" maxlength="4"> 505 //<input id="cc-number7" maxlength="4"> 506 //<input id="cc-number8" maxlength="4"> 507 //<input id="cc-exp-month2"> 508 //<input id="cc-exp-year2"> 509 //<input> 510 //<input> 511 //<input> 512 //</form> 513 //`, 514 //focusedInputId: "cc-number1", 515 //profileData: { 516 //guid: "123", 517 //"cc-type": "mastercard", 518 //"cc-number": "371449635398431", 519 //"cc-exp-month": 6, 520 //"cc-exp-year": 25, 521 //}, 522 //expectedResult: { 523 //guid: "123", 524 //"cc-type1": "mastercard", 525 //"cc-number1": "3714", 526 //"cc-number2": "4963", 527 //"cc-number3": "5398", 528 //"cc-number4": "431", 529 //"cc-exp-month1": "06", 530 //"cc-exp-year1": "25", 531 //"cc-type2": "", 532 //"cc-number-5": "", 533 //"cc-number-6": "", 534 //"cc-number-7": "", 535 //"cc-number-8": "", 536 //"cc-exp-month2": "", 537 //"cc-exp-year2": "", 538 //}, 539 //}, 540 { 541 description: 542 "Fill credit card fields in a form with placeholders on month and year and these inputs are type=tel", 543 document: `<form> 544 <input id="cardHolder"> 545 <input id="cardNumber"> 546 <input id="month" type="tel" name="month" placeholder="MM"> 547 <input id="year" type="tel" name="year" placeholder="YY"> 548 </form> 549 `, 550 focusedInputId: "cardHolder", 551 profileData: { 552 "cc-number": "4111111111111111", 553 "cc-name": "test name", 554 "cc-exp-month": 6, 555 "cc-exp-year": 2025, 556 }, 557 expectedResult: { 558 cardHolder: "test name", 559 cardNumber: "4111111111111111", 560 month: "06", 561 year: "25", 562 }, 563 }, 564 ]; 565 566 const TESTCASES_INPUT_UNCHANGED = [ 567 { 568 description: 569 "Form with autocomplete select elements; with default and no matching options", 570 document: `<form> 571 <input id="given-name" autocomplete="shipping given-name"> 572 <select id="country" autocomplete="shipping country"> 573 <option value="US">United States</option> 574 </select> 575 <select id="state" autocomplete="shipping address-level1"> 576 <option value=""></option> 577 <option value="CA">California</option> 578 <option value="WA">Washington</option> 579 </select> 580 </form>`, 581 focusedInputId: "given-name", 582 profileData: { 583 country: "US", 584 "address-level1": "unknown state", 585 }, 586 expectedResult: { 587 country: "US", 588 state: "", 589 }, 590 }, 591 ]; 592 593 const TESTCASES_FILL_SELECT = [ 594 // US States 595 { 596 description: "Form with US states select elements", 597 document: `<form> 598 <input id="given-name" autocomplete="shipping given-name"> 599 <input id="family-name" autocomplete="shipping family-name"> 600 <select id="state" autocomplete="shipping address-level1"> 601 <option value=""></option> 602 <option value="CA">California</option> 603 </select></form>`, 604 focusedInputId: "given-name", 605 profileData: { 606 country: "US", 607 "address-level1": "CA", 608 }, 609 expectedResult: { 610 state: "CA", 611 }, 612 }, 613 { 614 description: 615 "Form with US states select elements; with lower case state key", 616 document: `<form> 617 <input id="given-name" autocomplete="shipping given-name"> 618 <input id="family-name" autocomplete="shipping family-name"> 619 <select id="state" autocomplete="shipping address-level1"> 620 <option value=""></option> 621 <option value="ca">ca</option> 622 </select></form>`, 623 focusedInputId: "given-name", 624 profileData: { 625 guid: "123", 626 country: "US", 627 "address-level1": "CA", 628 }, 629 expectedResult: { 630 state: "ca", 631 }, 632 }, 633 { 634 description: 635 "Form with US states select elements; with state name and extra spaces", 636 document: `<form> 637 <input id="given-name" autocomplete="shipping given-name"> 638 <input id="family-name" autocomplete="shipping family-name"> 639 <select id="state" autocomplete="shipping address-level1"> 640 <option value=""></option> 641 <option value="CA">CA</option> 642 </select></form>`, 643 focusedInputId: "given-name", 644 profileData: { 645 country: "US", 646 "address-level1": " California ", 647 }, 648 expectedResult: { 649 state: "CA", 650 }, 651 }, 652 { 653 description: 654 "Form with US states select elements; with partial state key match", 655 document: `<form> 656 <input id="given-name" autocomplete="shipping given-name"> 657 <input id="family-name" autocomplete="shipping family-name"> 658 <select id="state" autocomplete="shipping address-level1"> 659 <option value=""></option> 660 <option value="US-WA">WA-Washington</option> 661 </select></form>`, 662 focusedInputId: "given-name", 663 profileData: { 664 country: "US", 665 "address-level1": "WA", 666 }, 667 expectedResult: { 668 state: "US-WA", 669 }, 670 }, 671 672 // Country 673 { 674 description: "Form with country select elements", 675 document: `<form> 676 <input id="given-name" autocomplete="given-name"> 677 <input id="family-name" autocomplete="family-name"> 678 <select id="country" autocomplete="country"> 679 <option value=""></option> 680 <option value="US">United States</option> 681 </select></form>`, 682 focusedInputId: "given-name", 683 profileData: { 684 country: "US", 685 }, 686 expectedResult: { 687 country: "US", 688 }, 689 }, 690 { 691 description: "Form with country select elements; with lower case key", 692 document: `<form> 693 <input id="given-name" autocomplete="given-name"> 694 <input id="family-name" autocomplete="family-name"> 695 <select id="country" autocomplete="country"> 696 <option value=""></option> 697 <option value="us">us</option> 698 </select></form>`, 699 focusedInputId: "given-name", 700 profileData: { 701 country: "US", 702 }, 703 expectedResult: { 704 country: "us", 705 }, 706 }, 707 { 708 description: "Form with country select elements; with alternative name 1", 709 document: `<form> 710 <input id="given-name" autocomplete="given-name"> 711 <input id="family-name" autocomplete="family-name"> 712 <select id="country" autocomplete="country"> 713 <option value=""></option> 714 <option value="XX">United States</option> 715 </select></form>`, 716 focusedInputId: "given-name", 717 profileData: { 718 country: "US", 719 }, 720 expectedResult: { 721 country: "XX", 722 }, 723 }, 724 { 725 description: "Form with country select elements; with alternative name 2", 726 document: `<form> 727 <input id="given-name" autocomplete="given-name"> 728 <input id="family-name" autocomplete="family-name"> 729 <select id="country" autocomplete="country"> 730 <option value=""></option> 731 <option value="XX">America</option> 732 </select></form>`, 733 focusedInputId: "given-name", 734 profileData: { 735 country: "US", 736 }, 737 expectedResult: { 738 country: "XX", 739 }, 740 }, 741 { 742 description: 743 "Form with country select elements; with partial matching value", 744 document: `<form> 745 <input id="given-name" autocomplete="given-name"> 746 <input id="family-name" autocomplete="family-name"> 747 <select id="country" autocomplete="country"> 748 <option value=""></option> 749 <option value="XX">Ship to America</option> 750 </select></form>`, 751 focusedInputId: "given-name", 752 profileData: { 753 country: "US", 754 }, 755 expectedResult: { 756 country: "XX", 757 }, 758 }, 759 { 760 description: 761 "Fill credit card expiration month field in a form with select field", 762 document: `<form> 763 <input id="cc-number" autocomplete="cc-number"> 764 <input id="cc-name" autocomplete="cc-name"> 765 <select id="cc-exp-month" autocomplete="cc-exp-month"> 766 <option value="">MM</option> 767 <option value="6">06</option> 768 </select></form>`, 769 focusedInputId: "cc-number", 770 profileData: { 771 "cc-number": "4111111111111111", 772 "cc-name": "test name", 773 "cc-exp-month": 6, 774 "cc-exp-year": 25, 775 }, 776 expectedResult: { 777 "cc-number": "4111111111111111", 778 "cc-name": "test name", 779 "cc-exp-month": "6", 780 "cc-exp-year": "2025", 781 }, 782 }, 783 { 784 description: 785 "Fill credit card information correctly when one of the card type options is 'American Express'", 786 document: `<form> 787 <select id="cc-type" autocomplete="cc-type"> 788 <option value="">Please select</option> 789 <option value="MA">Mastercard</option> 790 <option value="AX">American Express</option> 791 </select> 792 <input id="cc-number" autocomplete="cc-number"> 793 <input id="cc-name" autocomplete="cc-name"> 794 <input id="cc-exp-month" autocomplete="cc-exp-month"> 795 <input id="cc-exp-year" autocomplete="cc-exp-year"> 796 </form>`, 797 focusedInputId: "cc-number", 798 profileData: { 799 "cc-number": "378282246310005", 800 "cc-type": "amex", 801 "cc-name": "test name", 802 "cc-exp-month": 8, 803 "cc-exp-year": 26, 804 }, 805 expectedResult: { 806 "cc-number": "378282246310005", 807 "cc-type": "AX", 808 "cc-name": "test name", 809 "cc-exp-month": 8, 810 "cc-exp-year": 26, 811 }, 812 }, 813 ]; 814 815 const TESTCASES_BOTH_CHANGED_AND_UNCHANGED = [ 816 { 817 description: 818 "Form with a disabled input and non-disabled inputs. The 'country' field should not change", 819 document: `<form> 820 <input id="given-name" autocomplete="given-name"> 821 <input id="family-name" autocomplete="family-name"> 822 <input id="street-addr" autocomplete="street-address"> 823 <input id="country" autocomplete="country" disabled value="DE"> 824 </form>`, 825 focusedInputId: "given-name", 826 profileData: { 827 "given-name": "John", 828 "family-name": "Doe", 829 "street-address": "100 Main Street", 830 country: "CA", 831 }, 832 expectedResult: { 833 "given-name": "John", 834 "family-name": "Doe", 835 "street-addr": "100 Main Street", 836 country: "DE", 837 }, 838 }, 839 ]; 840 841 function do_test(testcases, testFn) { 842 for (const tc of testcases) { 843 (function () { 844 const testcase = tc; 845 add_task(async function () { 846 info("Starting testcase: " + testcase.description); 847 const doc = MockDocument.createTestDocument( 848 "http://localhost:8080/test/", 849 testcase.document 850 ); 851 const form = doc.querySelector("form"); 852 const formLike = FormLikeFactory.createFromForm(form); 853 const handler = new FormAutofillHandler(formLike); 854 const promises = []; 855 856 const fieldDetails = FormAutofillHandler.collectFormFieldDetails( 857 handler.form 858 ); 859 // TODO: This test should be a browser test instead 860 FormAutofillHeuristics.parseAndUpdateFieldNamesParent(fieldDetails); 861 handler.setIdentifiedFieldDetails(fieldDetails); 862 863 let focusedInputIdentifier; 864 handler.fieldDetails.forEach(field => { 865 const element = field.element; 866 if (element.id == testcase.focusedInputId) { 867 focusedInputIdentifier = field.elementId; 868 } 869 if (!testcase.profileData[field.fieldName]) { 870 // Avoid waiting for `change` event of a input with a blank value to 871 // be filled. 872 return; 873 } 874 promises.push(...testFn(testcase, element)); 875 }); 876 877 const ids = handler.fieldDetails.map( 878 fieldDetail => fieldDetail.elementId 879 ); 880 await handler.fillFields( 881 focusedInputIdentifier, 882 ids, 883 testcase.profileData 884 ); 885 await Promise.all(promises); 886 }); 887 })(); 888 } 889 } 890 891 do_test(TESTCASES, (testcase, element) => { 892 let id = element.id; 893 return [ 894 new Promise(resolve => { 895 element.addEventListener( 896 "input", 897 () => { 898 Assert.ok(true, "Checking " + id + " field fires input event"); 899 resolve(); 900 }, 901 { once: true } 902 ); 903 }), 904 new Promise(resolve => { 905 element.addEventListener( 906 "change", 907 () => { 908 Assert.ok(true, "Checking " + id + " field fires change event"); 909 Assert.equal( 910 element.value, 911 testcase.expectedResult[id], 912 "Check the " + id + " field was filled with correct data" 913 ); 914 resolve(); 915 }, 916 { once: true } 917 ); 918 }), 919 ]; 920 }); 921 922 do_test(TESTCASES_INPUT_UNCHANGED, (testcase, element) => { 923 return [ 924 new Promise((resolve, reject) => { 925 // Make sure no change or input event is fired when no change occurs. 926 let cleaner; 927 let timer = setTimeout(() => { 928 let id = element.id; 929 element.removeEventListener("change", cleaner); 930 element.removeEventListener("input", cleaner); 931 Assert.equal( 932 element.value, 933 testcase.expectedResult[id], 934 "Check no value is changed on the " + id + " field" 935 ); 936 resolve(); 937 }, 1000); 938 cleaner = event => { 939 clearTimeout(timer); 940 reject(`${event.type} event should not fire`); 941 }; 942 element.addEventListener("change", cleaner); 943 element.addEventListener("input", cleaner); 944 }), 945 ]; 946 }); 947 948 do_test(TESTCASES_FILL_SELECT, (testcase, element) => { 949 let id = element.id; 950 return [ 951 new Promise(resolve => { 952 element.addEventListener( 953 "input", 954 () => { 955 Assert.equal( 956 element.value, 957 testcase.expectedResult[id], 958 "Check the " + id + " field was filled with correct data" 959 ); 960 resolve(); 961 }, 962 { once: true } 963 ); 964 }), 965 ]; 966 }); 967 968 do_test(TESTCASES_BOTH_CHANGED_AND_UNCHANGED, (testcase, element) => { 969 // Ensure readonly and disabled inputs are not autofilled 970 if (element.readOnly || element.disabled) { 971 return [ 972 new Promise((resolve, reject) => { 973 // Make sure no change or input event is fired when no change occurs. 974 let cleaner; 975 let timer = setTimeout(() => { 976 let id = element.id; 977 element.removeEventListener("change", cleaner); 978 element.removeEventListener("input", cleaner); 979 Assert.equal( 980 element.value, 981 testcase.expectedResult[id], 982 "Check no value is changed on the " + id + " field" 983 ); 984 resolve(); 985 }, 1000); 986 cleaner = event => { 987 clearTimeout(timer); 988 reject(`${event.type} event should not fire`); 989 }; 990 element.addEventListener("change", cleaner); 991 element.addEventListener("input", cleaner); 992 }), 993 ]; 994 } 995 let id = element.id; 996 // Ensure that non-disabled and non-readonly fields are filled correctly 997 return [ 998 new Promise(resolve => { 999 element.addEventListener( 1000 "input", 1001 () => { 1002 Assert.ok(true, "Checking " + id + " field fires input event"); 1003 resolve(); 1004 }, 1005 { once: true } 1006 ); 1007 }), 1008 new Promise(resolve => { 1009 element.addEventListener( 1010 "change", 1011 () => { 1012 Assert.ok(true, "Checking " + id + " field fires change event"); 1013 Assert.equal( 1014 element.value, 1015 testcase.expectedResult[id], 1016 "Check the " + id + " field was filled with correct data" 1017 ); 1018 resolve(); 1019 }, 1020 { once: true } 1021 ); 1022 }), 1023 ]; 1024 });