Bug 1427961 - Test fixes, will need to shuffle some code around. draft
authorJared Wein <jwein@mozilla.com>
Thu, 21 Jun 2018 02:15:17 -0400
changeset 809083 cb8bb2b8f879b7291b61618d898344df6105e16d
parent 809082 645b2a0ceb1709f1cc16de6e536298fd41c05f23
push id113540
push userbmo:jaws@mozilla.com
push dateThu, 21 Jun 2018 06:16:36 +0000
bugs1427961
milestone62.0a1
Bug 1427961 - Test fixes, will need to shuffle some code around. MozReview-Commit-ID: FRAMhgJdAdQ
browser/components/payments/res/containers/address-form.css
browser/components/payments/res/containers/address-form.js
browser/components/payments/res/unprivileged-fallbacks.js
browser/components/payments/test/browser/browser_address_edit.js
browser/components/payments/test/browser/browser_card_edit.js
browser/components/payments/test/browser/browser_payments_onboarding_wizard.js
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/content/autofillEditForms.js
--- a/browser/components/payments/res/containers/address-form.css
+++ b/browser/components/payments/res/containers/address-form.css
@@ -30,17 +30,18 @@ label[required] > span:first-of-type::af
 
 .error-text:not(:empty) {
   color: #fff;
   background-color: #d70022;
   border-radius: 2px;
   /* The padding-top and padding-bottom are referenced by address-form.js */
   padding: 5px 12px;
   position: absolute;
-  z-index: 5;
+  z-index: 1;
+  pointer-events: none;
 }
 
 body[dir="ltr"] .error-text {
   left: 3px;
 }
 
 body[dir="rtl"] .error-text {
   right: 3px;
--- a/browser/components/payments/res/containers/address-form.js
+++ b/browser/components/payments/res/containers/address-form.js
@@ -83,48 +83,16 @@ export default class AddressForm extends
       });
 
       this.appendChild(this.persistCheckbox);
       this.appendChild(this.genericErrorText);
       this.appendChild(this.cancelButton);
       this.appendChild(this.backButton);
       this.appendChild(this.saveButton);
 
-      // Add validation to some address fields
-      let zipCodeInput = form.querySelector("#postal-code");
-      let countrySelect = form.querySelector("#country");
-      countrySelect.addEventListener("change", event => {
-        let country = countrySelect.value;
-        if (country) {
-          let {addressData} = PaymentDialogUtils.getFormFormat(country);
-          // Note, this doesn't handle level1, such as CA--fr
-          let countryAddressData = addressData[`data/${country}`];
-          zipCodeInput.setAttribute("pattern", countryAddressData.zip);
-        } else {
-          zipCodeInput.removeAttribute("pattern");
-        }
-      });
-      let streetInput = form.querySelector("#street-address");
-      let cityInput = form.querySelector("#address-level2");
-      let stateInput = form.querySelector("#address-level1");
-      let nameInputs = form.querySelectorAll("#name-container > label > input");
-      let requiredInputs = [nameInputs[0], streetInput, cityInput, zipCodeInput, stateInput];
-      for (let input of requiredInputs) {
-        let container = input.closest(`#${input.id}-container`);
-        if (container.style.display != "none") {
-          container.setAttribute("required", "true");
-          input.setAttribute("required", "true");
-        }
-
-        // Disable the Save button if any of the fields are invalid
-        input.addEventListener("change", this);
-        input.addEventListener("invalid", this);
-      }
-      this.updateSaveButtonValidity();
-
       // Only call the connected super callback(s) once our markup is fully
       // connected, including the shared form fetched asynchronously.
       super.connectedCallback();
     });
   }
 
   render(state) {
     let record = {};
@@ -142,22 +110,16 @@ export default class AddressForm extends
     this.cancelButton.textContent = this.dataset.cancelButtonLabel;
     this.backButton.textContent = this.dataset.backButtonLabel;
     this.saveButton.textContent = this.dataset.saveButtonLabel;
     this.persistCheckbox.label = this.dataset.persistCheckboxLabel;
 
     this.backButton.hidden = page.onboardingWizard;
     this.cancelButton.hidden = !page.onboardingWizard;
 
-    if (addressPage.addressFields) {
-      this.setAttribute("address-fields", addressPage.addressFields);
-    } else {
-      this.removeAttribute("address-fields");
-    }
-
     this.pageTitle.textContent = addressPage.title;
     this.genericErrorText.textContent = page.error;
 
     let editing = !!addressPage.guid;
     let addresses = paymentRequest.getAddresses(state);
 
     // If an address is selected we want to edit it.
     if (editing) {
@@ -170,37 +132,85 @@ export default class AddressForm extends
     } else {
       // Adding a new record: default persistence to checked when in a not-private session
       this.persistCheckbox.hidden = false;
       this.persistCheckbox.checked = !state.isPrivate;
     }
 
     this.formHandler.loadRecord(record);
 
+    // Add validation to some address fields. Need to do this in
+    // render since the required fields can change between renders
+    // if shippingAddressErrors or address-fields get set.
+    let zipCodeInput = this.form.querySelector("#postal-code");
+    let countrySelect = this.form.querySelector("#country");
+    countrySelect.addEventListener("change", this);
+    let streetInput = this.form.querySelector("#street-address");
+    let cityInput = this.form.querySelector("#address-level2");
+    let stateInput = this.form.querySelector("#address-level1");
+    let nameInputs = this.form.querySelectorAll("#name-container > label > input");
+    let requiredInputs = [nameInputs[0], streetInput, cityInput, zipCodeInput, stateInput];
+    for (let input of requiredInputs) {
+      let container = input.closest(`#${input.id}-container`);
+      if (container.style.display != "none") {
+        container.setAttribute("required", "true");
+        input.setAttribute("required", "true");
+      } else {
+        container.removeAttribute("required");
+        input.removeAttribute("required");
+      }
+
+      // Disable the Save button if any of the fields are invalid
+      input.addEventListener("change", this);
+      input.addEventListener("invalid", this);
+    }
+
     let shippingAddressErrors = request.paymentDetails.shippingAddressErrors;
-    if (!shippingAddressErrors || !Object.entries(shippingAddressErrors).length) {
-      return;
-    }
     for (let [errorName, errorSelector] of Object.entries(this._errorFieldMap)) {
       let field = document.querySelector(errorSelector);
-      let errorText = shippingAddressErrors[errorName];
+      let errorText = (shippingAddressErrors && shippingAddressErrors[errorName]) || "";
       if (errorText) {
         field.setAttribute("shipping-address-error", errorText);
 
         // These fields are not required by Firefox. Validation is only
         // added if the merchant provided a specific error for them.
         if (["organization", "phone", "country"].includes(errorName)) {
           field.addEventListener("change", this);
         }
       } else {
         field.removeAttribute("shipping-address-error");
       }
       this.setErrorTextForField(field, errorText);
     }
 
+    if (addressPage.addressFields) {
+      this.setAttribute("address-fields", addressPage.addressFields);
+      // Form elements that are hidden need their 'required' attribute removed.
+      let fieldNames = [
+        "name", "email", "tel",
+        "organization", "street-address", "address-level2",
+        "address-level1", "postal-code", "country",
+      ];
+      for (let field of addressPage.addressFields.split(" ")) {
+        let index = fieldNames.indexOf(field);
+        fieldNames.splice(index, 1);
+      }
+      for (let fieldName of fieldNames) {
+        let container = document.querySelector(`#${fieldName}-container`);
+        let inputs = [...container.querySelectorAll("input, textarea, select")];
+        for (let input of inputs) {
+          input.removeAttribute("required");
+          input.setCustomValidity("");
+        }
+      }
+    } else {
+      this.removeAttribute("address-fields");
+    }
+    this.updateSaveButtonValidity();
+
     // Position the error messages all at once so layout flushes only once.
     let formRect = this.form.getBoundingClientRect();
     let errorSpanData = [...this.form.querySelectorAll(".error-text:not(:empty)")].map(span => {
       let relatedInput = span.previousElementSibling;
       let relatedRect = relatedInput.getBoundingClientRect();
       return {
         span,
         top: relatedRect.bottom,
@@ -218,16 +228,19 @@ export default class AddressForm extends
         data.span.style.left = data.left + "px";
       }
     }
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "change": {
+        if (event.target.id == "country") {
+          this.updateCountryDependentFields(event);
+        }
         this.updateShippingAddressErrorVisibility(event);
         this.updateSaveButtonValidity();
         break;
       }
       case "click": {
         this.onClick(event);
         break;
       }
@@ -322,16 +335,28 @@ export default class AddressForm extends
     if (previousId) {
       state.successStateChange[previousId] = Object.assign({}, currentState[previousId]);
       state.successStateChange[previousId].preserveFieldValues = true;
     }
 
     paymentRequest.updateAutofillRecord("addresses", record, addressPage.guid, state);
   }
 
+  updateCountryDependentFields(event) {
+    let country = event.target.value;
+    let zipCodeInput = this.form.querySelector("#postal-code");
+    if (country) {
+      let {zipPattern} = PaymentDialogUtils.getFormFormat(country);
+      // Note, this doesn't handle level1, such as CA--fr
+      zipCodeInput.setAttribute("pattern", zipPattern);
+    } else {
+      zipCodeInput.removeAttribute("pattern");
+    }
+  }
+
   updateShippingAddressErrorVisibility(event) {
     let field = event.target;
     if (!field.validity.valueMissing) {
       field.setCustomValidity("");
       return;
     }
     let errorText = field.getAttribute("shipping-address-error") ||
                     field.validationMessage;
--- a/browser/components/payments/res/unprivileged-fallbacks.js
+++ b/browser/components/payments/res/unprivileged-fallbacks.js
@@ -37,21 +37,14 @@ var PaymentDialogUtils = {
       "fieldsOrder": [
         {fieldId: "name", newLine: true},
         {fieldId: "organization", newLine: true},
         {fieldId: "street-address", newLine: true},
         {fieldId: "address-level2"},
         {fieldId: "address-level1"},
         {fieldId: "postal-code"},
       ],
-
       // The following values come from addressReferences.js and should not be changed.
-      /* eslint-disable max-len */
-      "addressData": {
-        "data/CA": {"lang": "en", "upper": "ACNOSZ", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1", "name": "CANADA", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/CA", "languages": "en~fr", "sub_keys": "AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", "key": "CA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "require": "ACSZ", "sub_names": "Alberta~British Columbia~Manitoba~New Brunswick~Newfoundland and Labrador~Northwest Territories~Nova Scotia~Nunavut~Ontario~Prince Edward Island~Quebec~Saskatchewan~Yukon", "sub_zips": "T~V~R~E~A~X0E|X0G|X1A~B~X0A|X0B|X0C~K|L|M|N|P~C~G|H|J|K1A~S|R8A~Y"},
-        "data/CA--fr": {"lang": "fr", "upper": "ACNOSZ", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1", "name": "CANADA", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "fmt": "%N%n%O%n%A%n%C %S %Z", "require": "ACSZ", "sub_keys": "AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", "key": "CA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "id": "data/CA--fr", "sub_names": "Alberta~Colombie-Britannique~Île-du-Prince-Édouard~Manitoba~Nouveau-Brunswick~Nouvelle-Écosse~Nunavut~Ontario~Québec~Saskatchewan~Terre-Neuve-et-Labrador~Territoires du Nord-Ouest~Yukon", "sub_zips": "T~V~C~R~E~B~X0A|X0B|X0C~K|L|M|N|P~G|H|J|K1A~S|R8A~A~X0E|X0G|X1A~Y"},
-        "data/DE": {"zipex": "26133,53225", "name": "GERMANY", "zip": "\\d{5}", "fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DE", "key": "DE", "posturl": "http://www.postdirekt.de/plzserver/", "require": "ACZ"},
-        "data/US": {"lang": "en", "upper": "CS", "sub_zipexs": "35000,36999~99500,99999~96799~85000,86999~71600,72999~34000,34099~09000,09999~96200,96699~90000,96199~80000,81999~06000,06999~19700,19999~20000,56999~32000,34999~30000,39901~96910,96932~96700,96899~83200,83999~60000,62999~46000,47999~50000,52999~66000,67999~40000,42799~70000,71599~03900,04999~96960,96979~20600,21999~01000,05544~48000,49999~96941,96944~55000,56799~38600,39799~63000,65999~59000,59999~68000,69999~88900,89999~03000,03899~07000,08999~87000,88499~10000,00544~27000,28999~58000,58999~96950,96952~43000,45999~73000,74999~97000,97999~96940~15000,19699~00600,00999~02800,02999~29000,29999~57000,57999~37000,38599~75000,73344~84000,84999~05000,05999~00800,00899~20100,24699~98000,99499~24700,26999~53000,54999~82000,83414", "zipex": "95014,22162-1010", "name": "UNITED STATES", "zip": "(\\d{5})(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "fmt": "%N%n%O%n%A%n%C, %S %Z", "state_name_type": "state", "id": "data/US", "languages": "en", "sub_keys": "AL~AK~AS~AZ~AR~AA~AE~AP~CA~CO~CT~DE~DC~FL~GA~GU~HI~ID~IL~IN~IA~KS~KY~LA~ME~MH~MD~MA~MI~FM~MN~MS~MO~MT~NE~NV~NH~NJ~NM~NY~NC~ND~MP~OH~OK~OR~PW~PA~PR~RI~SC~SD~TN~TX~UT~VT~VI~VA~WA~WV~WI~WY", "key": "US", "posturl": "https://tools.usps.com/go/ZipLookupAction!input.action", "require": "ACSZ", "sub_names": "Alabama~Alaska~American Samoa~Arizona~Arkansas~Armed Forces (AA)~Armed Forces (AE)~Armed Forces (AP)~California~Colorado~Connecticut~Delaware~District of Columbia~Florida~Georgia~Guam~Hawaii~Idaho~Illinois~Indiana~Iowa~Kansas~Kentucky~Louisiana~Maine~Marshall Islands~Maryland~Massachusetts~Michigan~Micronesia~Minnesota~Mississippi~Missouri~Montana~Nebraska~Nevada~New Hampshire~New Jersey~New Mexico~New York~North Carolina~North Dakota~Northern Mariana Islands~Ohio~Oklahoma~Oregon~Palau~Pennsylvania~Puerto Rico~Rhode Island~South Carolina~South Dakota~Tennessee~Texas~Utah~Vermont~Virgin Islands~Virginia~Washington~West Virginia~Wisconsin~Wyoming", "sub_zips": "3[56]~99[5-9]~96799~8[56]~71[6-9]|72~340~09~96[2-6]~9[0-5]|96[01]~8[01]~06~19[7-9]~20[02-5]|569~3[23]|34[1-9]~3[01]|398|39901~969([1-2]\\d|3[12])~967[0-8]|9679[0-8]|968~83[2-9]~6[0-2]~4[67]~5[0-2]~6[67]~4[01]|42[0-7]~70|71[0-5]~039|04~969[67]~20[6-9]|21~01|02[0-7]|05501|05544~4[89]~9694[1-4]~55|56[0-7]~38[6-9]|39[0-7]~6[3-5]~59~6[89]~889|89~03[0-8]~0[78]~87|88[0-4]~1[0-4]|06390|00501|00544~2[78]~58~9695[0-2]~4[3-5]~7[34]~97~969(39|40)~1[5-8]|19[0-6]~00[679]~02[89]~29~57~37|38[0-5]~7[5-9]|885|73301|73344~84~05~008~201|2[23]|24[0-6]~98|99[0-4]~24[7-9]|2[56]~5[34]~82|83[01]|83414"},
-      },
-      /* eslint-enable */
+      /* eslint-disable-next-line max-len */
+      "zipPattern": country == "US" ? "(\\d{5})(?:[ \\-](\\d{4}))?" : "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d",
     };
   },
 };
--- a/browser/components/payments/test/browser/browser_address_edit.js
+++ b/browser/components/payments/test/browser/browser_address_edit.js
@@ -53,16 +53,17 @@ add_task(async function test_add_link() 
 
       info("filling fields");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
       content.document.querySelector("address-form button:last-of-type").click();
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
         return Object.keys(state.savedAddresses).length == 1;
       }, "Check address was added");
 
@@ -140,16 +141,17 @@ add_task(async function test_edit_link()
 
       let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
       ok(persistCheckbox.hidden, "checkbox should be hidden when editing an address");
 
       info("overwriting field values");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
       content.document.querySelector("address-form button:last-of-type").click();
 
       state = await PTU.DialogContentUtils.waitForState(content, (state) => {
         let addresses = Object.entries(state.savedAddresses);
         return addresses.length == 1 &&
@@ -229,16 +231,17 @@ add_task(async function test_add_payer_c
 
       info("filling fields");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
       info("check that non-payer requested fields are hidden");
       for (let selector of ["#organization", "#tel"]) {
         let element = content.document.querySelector(selector);
         ok(content.isHidden(element), selector + " should be hidden");
       }
@@ -312,16 +315,17 @@ add_task(async function test_edit_payer_
 
       let persistCheckbox = content.document.querySelector("address-form labelled-checkbox");
       ok(persistCheckbox.hidden, "checkbox should be hidden when editing an address");
 
       info("overwriting field values");
       for (let [key, val] of Object.entries(address)) {
         let field = content.document.getElementById(key);
         field.value = val + "1";
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
 
       info("check that non-payer requested fields are hidden");
       let formElements =
         content.document.querySelectorAll("address-form :-moz-any(input, select, textarea");
       let allowedFields = ["given-name", "additional-name", "family-name", "email", "tel"];
       for (let element of formElements) {
@@ -428,16 +432,17 @@ add_task(async function test_private_per
       ok(!Cu.waiveXrays(persistCheckbox).checked,
          "persist checkbox should be unchecked by default");
 
       info("add the temp address");
       let addressToAdd = PTU.Addresses.Temp;
       for (let [key, val] of Object.entries(addressToAdd)) {
         let field = content.document.getElementById(key);
         field.value = val;
+        field.dispatchEvent(new Event("change"));
       }
       content.document.querySelector("address-form button:last-of-type").click();
 
       info("wait until we return to the summary page");
       let state = await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "payment-summary";
       }, "Return to summary page");
 
--- a/browser/components/payments/test/browser/browser_card_edit.js
+++ b/browser/components/payments/test/browser/browser_card_edit.js
@@ -35,16 +35,17 @@ add_task(async function test_add_link() 
     ok(Cu.waiveXrays(persistCheckbox).checked, "persist checkbox should be checked by default");
 
     let card = Object.assign({}, PTU.BasicCards.JohnDoe);
 
     info("filling fields");
     for (let [key, val] of Object.entries(card)) {
       let field = content.document.getElementById(key);
       field.value = val;
+      field.dispatchEvent(new Event("change"));
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
     let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
     ok(content.isVisible(billingAddressSelect),
        "The billing address selector should always be visible");
     is(billingAddressSelect.childElementCount, 1,
        "Only one child option should exist by default");
@@ -87,16 +88,17 @@ add_task(async function test_add_link() 
 
     info("filling address fields");
     for (let [key, val] of Object.entries(PTU.Addresses.TimBL)) {
       let field = content.document.getElementById(key);
       if (!field) {
         ok(false, `${key} field not found`);
       }
       field.value = val;
+      field.dispatchEvent(new Event("change"));
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
     content.document.querySelector("address-form button:last-of-type").click();
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "basic-card-page" && !state["basic-card-page"].guid &&
              Object.keys(state.savedAddresses).length == 1;
     }, "Check address was added and we're back on basic-card page (add)");
@@ -174,16 +176,17 @@ add_task(async function test_edit_link()
     delete card["cc-number"];
     card["cc-exp-year"]++;
     card["cc-exp-month"]++;
 
     info("overwriting field values");
     for (let [key, val] of Object.entries(card)) {
       let field = content.document.getElementById(key);
       field.value = val;
+      field.dispatchEvent(new Event("change"));
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
     ok(content.document.getElementById("cc-number").disabled, "cc-number field should be disabled");
 
     let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
     is(billingAddressSelect.childElementCount, 2,
        "Two options should exist in the billingAddressSelect");
     is(billingAddressSelect.selectedIndex, 1,
@@ -249,27 +252,28 @@ add_task(async function test_edit_link()
     }, "Check address page state (editing)");
 
     info("filling address fields");
     for (let [key, val] of Object.entries(PTU.Addresses.TimBL)) {
       let field = content.document.getElementById(key);
       if (!field) {
         ok(false, `${key} field not found`);
       }
-      field.value = val + "1";
+      field.value = val.slice(0, -1) + "7";
+      field.dispatchEvent(new Event("change"));
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
     content.document.querySelector("address-form button:last-of-type").click();
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return state.page.id == "basic-card-page" && state["basic-card-page"].guid &&
              Object.keys(state.savedAddresses).length == 1;
     }, "Check still only one address and we're back on basic-card page");
 
-    is(Object.values(state.savedAddresses)[0].tel, PTU.Addresses.TimBL.tel + "1",
+    is(Object.values(state.savedAddresses)[0].tel, PTU.Addresses.TimBL.tel.slice(0, -1) + "7",
        "Check that address was edited and saved");
 
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       let cards = Object.entries(state.savedBasicCards);
       return cards.length == 1 &&
              cards[0][1]["cc-name"] == card["cc-name"];
@@ -368,16 +372,17 @@ add_task(async function test_private_car
     let tempCardCount = Object.keys(state.tempBasicCards).length;
 
     let card = Object.assign({}, PTU.BasicCards.JohnDoe);
 
     info("filling fields");
     for (let [key, val] of Object.entries(card)) {
       let field = content.document.getElementById(key);
       field.value = val;
+      field.dispatchEvent(new Event("change"));
       ok(!field.disabled, `Field #${key} shouldn't be disabled`);
     }
 
     content.document.querySelector("basic-card-form button:last-of-type").click();
 
     state = await PTU.DialogContentUtils.waitForState(content, (state) => {
       return Object.keys(state.tempBasicCards).length > tempCardCount;
     },
--- a/browser/components/payments/test/browser/browser_payments_onboarding_wizard.js
+++ b/browser/components/payments/test/browser/browser_payments_onboarding_wizard.js
@@ -61,16 +61,17 @@ add_task(async function test_onboarding_
          "The cancel button on the address page is visible");
 
       for (let [key, val] of Object.entries(PTU.Addresses.TimBL2)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
       content.document.querySelector("address-form .save-button").click();
 
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "basic-card-page";
       }, "Basic card page is shown after the address page during on boarding");
 
@@ -85,16 +86,17 @@ add_task(async function test_onboarding_
       PTU.DialogContentUtils.waitForState((state) => {
         let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
         return state.selectedShippingAddress == billingAddressSelect.value;
       }, "Shipping address is selected as the billing address");
 
       for (let [key, val] of Object.entries(PTU.BasicCards.JohnDoe)) {
         let field = content.document.getElementById(key);
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
       content.document.querySelector("basic-card-form .save-button").click();
 
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "payment-summary";
       }, "Payment summary page is shown after the basic card page during on boarding");
 
@@ -267,16 +269,17 @@ add_task(async function test_onboarding_
       ok(content.isVisible(addressSaveButton), "Address save button is rendered");
 
       for (let [key, val] of Object.entries(PTU.Addresses.TimBL2)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
       content.document.querySelector("address-form .save-button").click();
 
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "payment-summary";
       }, "payment-summary is now visible");
 
@@ -330,16 +333,17 @@ add_task(async function test_onboarding_
          "Address page title is correctly shown");
 
       for (let [key, val] of Object.entries(PTU.Addresses.TimBL2)) {
         let field = content.document.getElementById(key);
         if (!field) {
           ok(false, `${key} field not found`);
         }
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
       content.document.querySelector("address-form .save-button").click();
 
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "basic-card-page";
       // eslint-disable-next-line max-len
       }, "Basic card page is shown after the billing address page during onboarding if requestShipping is turned off");
@@ -351,16 +355,17 @@ add_task(async function test_onboarding_
       PTU.DialogContentUtils.waitForState((state) => {
         let billingAddressSelect = content.document.querySelector("#billingAddressGUID");
         return state["basic-card-page"].billingAddressGUID == billingAddressSelect.value;
       }, "Billing Address is correctly shown");
 
       for (let [key, val] of Object.entries(PTU.BasicCards.JohnDoe)) {
         let field = content.document.getElementById(key);
         field.value = val;
+        field.dispatchEvent(new Event("change"));
         ok(!field.disabled, `Field #${key} shouldn't be disabled`);
       }
       content.document.querySelector("basic-card-form .save-button").click();
 
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.page.id == "payment-summary";
       }, "payment-summary is shown after the basic card page during on boarding");
 
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -778,17 +778,17 @@ this.FormAutofillUtils = {
    *         }
    */
   getFormFormat(country) {
     const dataset = this.getCountryAddressData(country);
     return {
       "addressLevel1Label": dataset.state_name_type || "province",
       "postalCodeLabel": dataset.zip_name_type || "postalCode",
       "fieldsOrder": this.parseAddressFormat(dataset.fmt || "%N%n%O%n%A%n%C, %S %Z"),
-      "addressData": this._addressData,
+      "zipPattern": dataset.zip,
     };
   },
 
   /**
    * Localize "data-localization" or "data-localization-region" attributes.
    * @param {Element} element
    * @param {string} attributeName
    */
--- a/browser/extensions/formautofill/content/autofillEditForms.js
+++ b/browser/extensions/formautofill/content/autofillEditForms.js
@@ -15,16 +15,17 @@ class EditAutofillForm {
   /**
    * Fill the form with a record object.
    * @param  {object} [record = {}]
    */
   loadRecord(record = {}) {
     for (let field of this._elements.form.elements) {
       let value = record[field.id];
       field.value = typeof(value) == "undefined" ? "" : value;
+      field.dispatchEvent(new Event("change"));
     }
   }
 
   /**
    * Get inputs from the form.
    * @returns {object}
    */
   buildFormObject() {