Bug 1370764 - (Part 2) Create a dialog to add/edit/view a credit card entry. r=lchang
MozReview-Commit-ID: 7d6cfcShrwc
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -59,16 +59,23 @@ this.FormAutofillUtils = {
isAddressField(fieldName) {
return !!this._fieldNameInfo[fieldName] && !this.isCreditCardField(fieldName);
},
isCreditCardField(fieldName) {
return this._fieldNameInfo[fieldName] == "creditCard";
},
+ isCCNumber(ccNumber) {
+ // Based on the information on wiki[1], the shortest valid length should be
+ // 12 digits(Maestro).
+ // [1] https://en.wikipedia.org/wiki/Payment_card_number
+ return ccNumber ? ccNumber.replace(/\s/g, "").match(/^\d{12,}$/) : false;
+ },
+
getCategoryFromFieldName(fieldName) {
return this._fieldNameInfo[fieldName];
},
getCategoriesFromFieldNames(fieldNames) {
let categories = new Set();
for (let fieldName of fieldNames) {
let info = this.getCategoryFromFieldName(fieldName);
--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -1508,25 +1508,18 @@ class CreditCards extends AutofillRecord
// Fields that should not be set by content.
delete creditCard["cc-number-encrypted"];
// Validate and encrypt credit card numbers, and calculate the masked numbers
if (creditCard["cc-number"]) {
let ccNumber = creditCard["cc-number"].replace(/\s/g, "");
delete creditCard["cc-number"];
- if (!/^\d+$/.test(ccNumber)) {
- throw new Error("Credit card number contains invalid characters.");
- }
-
- // Based on the information on wiki[1], the shortest valid length should be
- // 12 digits(Maestro).
- // [1] https://en.wikipedia.org/wiki/Payment_card_number
- if (ccNumber.length < 12) {
- throw new Error("Invalid credit card number because length is under 12 digits.");
+ if (!FormAutofillUtils.isCCNumber(ccNumber)) {
+ throw new Error("Credit card number contains invalid characters or is under 12 digits.");
}
creditCard["cc-number-encrypted"] = await MasterPassword.encrypt(ccNumber);
creditCard["cc-number"] = "*".repeat(ccNumber.length - 4) + ccNumber.substr(-4);
}
}
}
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -1,22 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" width="620">
<head>
- <title data-localization="addNewDialogTitle"/>
- <link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css" />
- <link rel="stylesheet" href="chrome://formautofill/skin/editAddress.css" />
+ <title data-localization="addNewAddressTitle"/>
+ <link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/>
+ <link rel="stylesheet" href="chrome://formautofill-shared/skin/editAddress.css"/>
+ <link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/>
<script src="chrome://formautofill/content/editDialog.js"></script>
</head>
<body>
- <form autocomplete="off">
+ <form id="form" autocomplete="off">
<label id="given-name-container">
<span data-localization="givenName"/>
<input id="given-name" type="text"/>
</label>
<label id="additional-name-container">
<span data-localization="additionalName"/>
<input id="additional-name" type="text"/>
</label>
@@ -62,13 +63,22 @@
</label>
</form>
<div id="controls-container">
<button id="cancel" data-localization="cancel"/>
<button id="save" disabled="disabled" data-localization="save"/>
</div>
<script type="application/javascript"><![CDATA[
"use strict";
- // Localize strings before DOMContentLoaded to prevent flash
- window.dialog.localizeDocument();
+ /* global EditAddress */
+ new EditAddress({
+ title: document.querySelector("title"),
+ form: document.getElementById("form"),
+ addressLevel1Label: document.querySelector("#address-level1-container > span"),
+ postalCodeLabel: document.querySelector("#postal-code-container > span"),
+ country: document.getElementById("country"),
+ controlsContainer: document.getElementById("controls-container"),
+ cancel: document.getElementById("cancel"),
+ save: document.getElementById("save"),
+ }, window.arguments && window.arguments[0]);
]]></script>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/content/editCreditCard.xhtml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" width="500" style="width: 500px">
+<head>
+ <title data-localization="addNewCreditCardTitle"/>
+ <link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/>
+ <link rel="stylesheet" href="chrome://formautofill-shared/skin/editCreditCard.css"/>
+ <link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/>
+ <script src="chrome://formautofill/content/editDialog.js"></script>
+</head>
+<body>
+ <form id="form" autocomplete="off">
+ <label>
+ <span data-localization="cardNumber"/>
+ <input id="cc-number" type="text"/>
+ </label>
+ <label>
+ <span data-localization="nameOnCard"/>
+ <input id="cc-name" type="text"/>
+ </label>
+ <div>
+ <span data-localization="cardExpires"/>
+ <select id="cc-exp-month">
+ <option/>
+ <option value="1">01</option>
+ <option value="2">02</option>
+ <option value="3">03</option>
+ <option value="4">04</option>
+ <option value="5">05</option>
+ <option value="6">06</option>
+ <option value="7">07</option>
+ <option value="8">08</option>
+ <option value="9">09</option>
+ <option value="10">10</option>
+ <option value="11">11</option>
+ <option value="12">12</option>
+ </select>
+ <select id="cc-exp-year">
+ <option/>
+ </select>
+ </div>
+ </form>
+ <div id="controls-container">
+ <button id="cancel" data-localization="cancel"/>
+ <button id="save" disabled="disabled" data-localization="save"/>
+ </div>
+ <script type="application/javascript"><![CDATA[
+ "use strict";
+ /* global EditCreditCard */
+ new EditCreditCard({
+ title: document.querySelector("title"),
+ form: document.getElementById("form"),
+ ccNumber: document.getElementById("cc-number"),
+ year: document.getElementById("cc-exp-year"),
+ controlsContainer: document.getElementById("controls-container"),
+ cancel: document.getElementById("cancel"),
+ save: document.getElementById("save"),
+ }, window.arguments && window.arguments[0]);
+ ]]></script>
+</body>
+</html>
--- a/browser/extensions/formautofill/content/editDialog.js
+++ b/browser/extensions/formautofill/content/editDialog.js
@@ -1,201 +1,277 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* exported EditAddress, EditCreditCard */
+
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const AUTOFILL_BUNDLE_URI = "chrome://formautofill/locale/formautofill.properties";
const REGIONS_BUNDLE_URI = "chrome://global/locale/regionNames.properties";
Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
-function EditDialog() {
- this._address = window.arguments && window.arguments[0];
- window.addEventListener("DOMContentLoaded", this, {once: true});
-}
+XPCOMUtils.defineLazyModuleGetter(this, "profileStorage",
+ "resource://formautofill/ProfileStorage.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "MasterPassword",
+ "resource://formautofill/MasterPassword.jsm");
-EditDialog.prototype = {
- get _elements() {
- if (this._elementRefs) {
- return this._elementRefs;
+class EditDialog {
+ constructor(subStorageName, elements, record) {
+ this._storageInitPromise = profileStorage.initialize();
+ this._subStorageName = subStorageName;
+ this._elements = elements;
+ this._record = record;
+ this.localizeDocument();
+ window.addEventListener("DOMContentLoaded", this, {once: true});
+ }
+
+ async init() {
+ if (this._record) {
+ await this.loadInitialValues(this._record);
}
- this._elementRefs = {
- title: document.querySelector("title"),
- addressLevel1Label: document.querySelector("#address-level1-container > span"),
- postalCodeLabel: document.querySelector("#postal-code-container > span"),
- country: document.getElementById("country"),
- controlsContainer: document.getElementById("controls-container"),
- cancel: document.getElementById("cancel"),
- save: document.getElementById("save"),
- };
- return this._elementRefs;
- },
-
- set _elements(refs) {
- this._elementRefs = refs;
- },
-
- init() {
this.attachEventListeners();
- },
+ }
uninit() {
this.detachEventListeners();
this._elements = null;
- },
+ }
+
+ /**
+ * Fill the form with a record object.
+ * @param {object} record
+ */
+ loadInitialValues(record) {
+ for (let field in record) {
+ let input = document.getElementById(field);
+ if (input) {
+ input.value = record[field];
+ }
+ }
+ }
+
+ /**
+ * Get inputs from the form.
+ * @returns {object}
+ */
+ buildFormObject() {
+ return Array.from(document.forms[0].elements).reduce((obj, input) => {
+ if (input.value) {
+ obj[input.id] = input.value;
+ }
+ return obj;
+ }, {});
+ }
+
+ /**
+ * Get storage and ensure it has been initialized.
+ * @returns {object}
+ */
+ async getStorage() {
+ await this._storageInitPromise;
+ return profileStorage[this._subStorageName];
+ }
+
+ /**
+ * Asks FormAutofillParent to save or update an record.
+ * @param {object} record
+ * @param {string} guid [optional]
+ */
+ async saveRecord(record, guid) {
+ let storage = await this.getStorage();
+ if (guid) {
+ storage.update(guid, record);
+ } else {
+ storage.add(record);
+ }
+ }
+
+ /**
+ * Handle events
+ *
+ * @param {DOMEvent} event
+ */
+ handleEvent(event) {
+ switch (event.type) {
+ case "DOMContentLoaded": {
+ this.init();
+ break;
+ }
+ case "unload": {
+ this.uninit();
+ break;
+ }
+ case "click": {
+ this.handleClick(event);
+ break;
+ }
+ case "input": {
+ this.handleInput(event);
+ break;
+ }
+ case "keypress": {
+ this.handleKeyPress(event);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handle click events
+ *
+ * @param {DOMEvent} event
+ */
+ handleClick(event) {
+ if (event.target == this._elements.cancel) {
+ window.close();
+ }
+ if (event.target == this._elements.save) {
+ this.handleSubmit();
+ }
+ }
+
+ /**
+ * Handle input events
+ *
+ * @param {DOMEvent} event
+ */
+ handleInput(event) {
+ // Toggle disabled attribute on the save button based on
+ // whether the form is filled or empty.
+ if (Object.keys(this.buildFormObject()).length == 0) {
+ this._elements.save.setAttribute("disabled", true);
+ } else {
+ this._elements.save.removeAttribute("disabled");
+ }
+ }
+
+ /**
+ * Handle key press events
+ *
+ * @param {DOMEvent} event
+ */
+ handleKeyPress(event) {
+ if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
+ window.close();
+ }
+ }
+
+ /**
+ * Attach event listener
+ */
+ attachEventListeners() {
+ window.addEventListener("keypress", this);
+ this._elements.controlsContainer.addEventListener("click", this);
+ document.addEventListener("input", this);
+ }
+
+ /**
+ * Remove event listener
+ */
+ detachEventListeners() {
+ window.removeEventListener("keypress", this);
+ this._elements.controlsContainer.removeEventListener("click", this);
+ document.removeEventListener("input", this);
+ }
+}
+
+class EditAddress extends EditDialog {
+ constructor(elements, record) {
+ super("addresses", elements, record);
+ this.formatForm(record && record.country);
+ }
/**
* Format the form based on country. The address-level1 and postal-code labels
* should be specific to the given country.
* @param {string} country
*/
formatForm(country) {
// TODO: Use fmt to show/hide and order fields (Bug 1383687)
const {addressLevel1Label, postalCodeLabel} = FormAutofillUtils.getFormFormat(country);
this._elements.addressLevel1Label.dataset.localization = addressLevel1Label;
this._elements.postalCodeLabel.dataset.localization = postalCodeLabel;
FormAutofillUtils.localizeMarkup(AUTOFILL_BUNDLE_URI, document);
- },
+ }
localizeDocument() {
- if (this._address) {
- this._elements.title.dataset.localization = "editDialogTitle";
+ if (this._record) {
+ this._elements.title.dataset.localization = "editAddressTitle";
}
FormAutofillUtils.localizeMarkup(REGIONS_BUNDLE_URI, this._elements.country);
- this.formatForm(this._address && this._address.country);
- },
+ }
+
+ async handleSubmit() {
+ await this.saveRecord(this.buildFormObject(), this._record ? this._record.guid : null);
+ window.close();
+ }
+}
- /**
- * Asks FormAutofillParent to save or update an address.
- * @param {object} data
- * {
- * {string} guid [optional]
- * {object} address
- * }
- */
- saveAddress(data) {
- Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", data);
- },
+class EditCreditCard extends EditDialog {
+ constructor(elements, record) {
+ super("creditCards", elements, record);
+ this.generateYears();
+ }
+
+ generateYears() {
+ const count = 11;
+ const currentYear = new Date().getFullYear();
+ const ccExpYear = this._record && this._record["cc-exp-year"];
- /**
- * Fill the form with an address object.
- * @param {object} address
- */
- loadInitialValues(address) {
- for (let field in address) {
- let input = document.getElementById(field);
- if (input) {
- input.value = address[field];
- }
+ if (ccExpYear && ccExpYear < currentYear) {
+ this._elements.year.appendChild(new Option(ccExpYear));
}
- },
+
+ for (let i = 0; i < count; i++) {
+ let year = currentYear + i;
+ let option = new Option(year);
+ this._elements.year.appendChild(option);
+ }
- /**
- * Get inputs from the form.
- * @returns {object}
- */
- buildAddressObject() {
- return Array.from(document.forms[0].elements).reduce((obj, input) => {
- if (input.value) {
- obj[input.id] = input.value;
- }
- return obj;
- }, {});
- },
+ if (ccExpYear && ccExpYear > currentYear + count) {
+ this._elements.year.appendChild(new Option(ccExpYear));
+ }
+ }
+
+ localizeDocument() {
+ if (this._record) {
+ this._elements.title.dataset.localization = "editCreditCardTitle";
+ }
+ FormAutofillUtils.localizeMarkup(AUTOFILL_BUNDLE_URI, document);
+ }
/**
- * Handle events
- *
- * @param {DOMEvent} event
+ * Decrypt cc-number first and fill the form.
+ * @param {object} creditCard
*/
- handleEvent(event) {
- switch (event.type) {
- case "DOMContentLoaded": {
- this.init();
- if (this._address) {
- this.loadInitialValues(this._address);
- }
- break;
- }
- case "click": {
- this.handleClick(event);
- break;
- }
- case "input": {
- // Toggle disabled attribute on the save button based on
- // whether the form is filled or empty.
- if (Object.keys(this.buildAddressObject()).length == 0) {
- this._elements.save.setAttribute("disabled", true);
- } else {
- this._elements.save.removeAttribute("disabled");
- }
- break;
- }
- case "unload": {
- this.uninit();
- break;
- }
- case "keypress": {
- this.handleKeyPress(event);
- break;
- }
- }
- },
+ async loadInitialValues(creditCard) {
+ let decryptedCC = await MasterPassword.decrypt(creditCard["cc-number-encrypted"]);
+ super.loadInitialValues(Object.assign({}, creditCard, {"cc-number": decryptedCC}));
+ }
- /**
- * Handle click events
- *
- * @param {DOMEvent} event
- */
- handleClick(event) {
- if (event.target == this._elements.cancel) {
- window.close();
+ async handleSubmit() {
+ let creditCard = this.buildFormObject();
+ // Show error on the cc-number field if it's empty or invalid
+ if (!FormAutofillUtils.isCCNumber(creditCard["cc-number"])) {
+ this._elements.ccNumber.setCustomValidity(true);
+ return;
}
- if (event.target == this._elements.save) {
- if (this._address) {
- this.saveAddress({
- guid: this._address.guid,
- address: this.buildAddressObject(),
- });
- } else {
- this.saveAddress({
- address: this.buildAddressObject(),
- });
- }
- window.close();
- }
- },
+ let storage = await this.getStorage();
+ await storage.normalizeCCNumberFields(creditCard);
+ await this.saveRecord(creditCard, this._record ? this._record.guid : null);
+ window.close();
+ }
- /**
- * Handle key press events
- *
- * @param {DOMEvent} event
- */
- handleKeyPress(event) {
- if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
- window.close();
+ handleInput(event) {
+ // Clear the error message if cc-number is valid
+ if (event.target == this._elements.ccNumber &&
+ FormAutofillUtils.isCCNumber(this._elements.ccNumber.value)) {
+ this._elements.ccNumber.setCustomValidity("");
}
- },
-
- /**
- * Attach event listener
- */
- attachEventListeners() {
- window.addEventListener("keypress", this);
- this._elements.controlsContainer.addEventListener("click", this);
- document.addEventListener("input", this);
- },
-
- /**
- * Remove event listener
- */
- detachEventListeners() {
- window.removeEventListener("keypress", this);
- this._elements.controlsContainer.removeEventListener("click", this);
- document.removeEventListener("input", this);
- },
-};
-
-window.dialog = new EditDialog();
+ super.handleInput(event);
+ }
+}
--- a/browser/extensions/formautofill/locales/en-US/formautofill.properties
+++ b/browser/extensions/formautofill/locales/en-US/formautofill.properties
@@ -34,18 +34,18 @@ phishingWarningMessage = Also autofills
phishingWarningMessage2 = Autofills %S
manageDialogTitle = Saved Addresses
addressListHeader = Addresses
remove = Remove
add = Add…
edit = Edit…
-addNewDialogTitle = Add New Address
-editDialogTitle = Edit Address
+addNewAddressTitle = Add New Address
+editAddressTitle = Edit Address
givenName = First Name
additionalName = Middle Name
familyName = Last Name
organization = Company
streetAddress = Street Address
city = City
province = Province
state = State
@@ -53,9 +53,15 @@ postalCode = Postal Code
zip = Zip Code
country = Country or Region
tel = Phone
email = Email
cancel = Cancel
save = Save
countryWarningMessage = Autofill is currently available only for US addresses
+addNewCreditCardTitle = Add New Credit Card
+editCreditCardTitle = Edit Credit Card
+cardNumber = Card Number
+nameOnCard = Name on Card
+cardExpires = Expires
+
insecureFieldWarningDescription = %S has detected an insecure site. Credit card autofill is temporarily disabled
rename from browser/extensions/formautofill/skin/linux/editAddress.css
rename to browser/extensions/formautofill/skin/linux/editDialog.css
rename from browser/extensions/formautofill/skin/osx/editAddress.css
rename to browser/extensions/formautofill/skin/osx/editDialog.css
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/skin/shared/editAddress.css
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+label > span {
+ flex: 0 0 9.5em;
+}
+
+input,
+select {
+ width: calc(50% - 9.5em);
+}
+
+#given-name-container,
+#additional-name-container,
+#address-level1-container,
+#postal-code-container,
+#country-container {
+ flex: 0 1 50%;
+}
+
+#family-name-container,
+#organization-container,
+#street-address-container,
+#address-level2-container,
+#email-container,
+#tel-container {
+ flex: 0 1 100%;
+}
+
+#family-name,
+#organization,
+#address-level2,
+#tel {
+ flex: 0 0 auto;
+}
+
+#street-address,
+#email {
+ flex: 1 0 auto;
+}
+
+#country-warning-message {
+ flex: 1;
+ align-items: center;
+ text-align: start;
+ color: #737373;
+ padding-inline-start: 1em;
+}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/skin/shared/editCreditCard.css
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+form {
+ justify-content: center;
+ /* Add extra space to ensure invalid input box is displayed properly */
+ padding: 2px;
+}
+
+form > label,
+form > div {
+ flex: 1 0 100%;
+ align-self: center;
+ font-size: 1.3em;
+ margin: 0 0 0.5em !important;
+}
+
+select {
+ flex: 0 0 5em;
+ margin: 0;
+ margin-inline-end: 0.7em;
+}
+
+label > span,
+div > span {
+ flex: 0 0 9.5em;
+}
--- a/browser/extensions/formautofill/skin/shared/editDialog.css
+++ b/browser/extensions/formautofill/skin/shared/editDialog.css
@@ -17,80 +17,43 @@ form {
flex-wrap: wrap;
}
label,
p {
margin: 0 0 0.5em;
}
-label > span {
+label > span,
+div > span {
box-sizing: border-box;
- flex: 0 0 9.5em;
- padding-inline-end: 0.5em;
+ padding-inline-end: 0.7em;
align-self: center;
text-align: end;
-moz-user-select: none;
}
-input,
-select {
- box-sizing: border-box;
- flex: 1 0 auto;
- width: calc(50% - 9.5em);
-}
-
option {
- padding: 5px 10px;
+ padding: 0.3em 0.5em;
}
textarea {
resize: none;
}
button {
font-size: 1.2em;
padding: 3px 2em;
margin-inline-start: 10px;
margin-inline-end: 0;
}
-#given-name-container,
-#additional-name-container,
-#address-level1-container,
-#postal-code-container,
-#country-container {
- flex: 0 1 50%;
-}
-
-#family-name-container,
-#organization-container,
-#street-address-container,
-#address-level2-container,
-#email-container,
-#tel-container,
-#controls-container {
- flex: 0 1 100%;
+input,
+select {
+ box-sizing: border-box;
+ flex: 1 0 auto;
}
#controls-container {
+ flex: 0 1 100%;
justify-content: end;
-}
-
-#family-name,
-#organization,
-#address-level2,
-#tel {
- flex: 0 0 auto;
+ margin: 1em 0 0;
}
-
-#street-address,
-#email {
- flex: 1 0 auto;
-}
-
-#country-warning-message {
- flex: 1;
- align-items: center;
- text-align: start;
- color: #737373;
- padding-inline-start: 1em;
-}
rename from browser/extensions/formautofill/skin/windows/editAddress.css
rename to browser/extensions/formautofill/skin/windows/editDialog.css
--- a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
@@ -254,24 +254,24 @@ add_task(async function test_validate()
do_check_eq(creditCards[1]["cc-exp"], year + "-" + month.toString().padStart(2, "0"));
do_check_eq(creditCards[2]["cc-number"].length, 16);
try {
await profileStorage.creditCards.normalizeCCNumberFields(TEST_CREDIT_CARD_WITH_INVALID_NUMBERS);
throw new Error("Not receiving invalid characters error");
} catch (e) {
- Assert.equal(e.message, "Credit card number contains invalid characters.");
+ Assert.equal(e.message, "Credit card number contains invalid characters or is under 12 digits.");
}
try {
await profileStorage.creditCards.normalizeCCNumberFields(TEST_CREDIT_CARD_WITH_SHORT_NUMBERS);
throw new Error("Not receiving invalid characters error");
} catch (e) {
- Assert.equal(e.message, "Invalid credit card number because length is under 12 digits.");
+ Assert.equal(e.message, "Credit card number contains invalid characters or is under 12 digits.");
}
});
add_task(async function test_notifyUsed() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
await prepareTestCreditCards(path);
let profileStorage = new ProfileStorage(path);