tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 });