Bug 1402963 - Part 1: Deduplicate credit card by checking credit card storage and untouched fields. r=lchang

MozReview-Commit-ID: tuw36eyQnl

--HG--
extra : rebase_source : 303d79f19c0a460365364e322eb796ab8be72a18
This commit is contained in:
steveck-chung 2017-09-27 18:38:13 +08:00
Родитель 931faf3e27
Коммит d83919d49b
4 изменённых файлов: 170 добавлений и 13 удалений

Просмотреть файл

@ -431,24 +431,39 @@ FormAutofillParent.prototype = {
async _onCreditCardSubmit(creditCard, target, timeStartedFillingMS) {
// We'll show the credit card doorhanger if:
// - User applys autofill and changed
// - User fills form manually
if (creditCard.guid &&
Object.keys(creditCard.record).every(key => creditCard.untouchedFields.includes(key))) {
// Add probe to record credit card autofill(without modification).
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_autofill", 1);
this._recordFormFillingTime("creditCard", "autofill", timeStartedFillingMS);
return;
}
// Add the probe to record credit card manual filling or autofill but modified case.
// - User fills form manually and the filling data is not duplicated to storage
if (creditCard.guid) {
let originalCCData = this.profileStorage.creditCards.get(creditCard.guid);
let unchanged = Object.keys(creditCard.record).every(field => {
if (creditCard.record[field] === "" && !originalCCData[field]) {
return true;
}
return creditCard.untouchedFields.includes(field);
});
if (unchanged) {
this.profileStorage.creditCards.notifyUsed(creditCard.guid);
// Add probe to record credit card autofill(without modification).
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_autofill", 1);
this._recordFormFillingTime("creditCard", "autofill", timeStartedFillingMS);
return;
}
// Add the probe to record credit card autofill with modification.
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_autofill_modified", 1);
this._recordFormFillingTime("creditCard", "autofill-update", timeStartedFillingMS);
} else {
// Add the probe to record credit card manual filling.
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_manual", 1);
this._recordFormFillingTime("creditCard", "manual", timeStartedFillingMS);
}
// Early return if it's a duplicate data
let dupGuid = this.profileStorage.creditCards.getDuplicateGuid(creditCard.record);
if (dupGuid) {
this.profileStorage.creditCards.notifyUsed(dupGuid);
return;
}
let state = await FormAutofillDoorhanger.show(target, "creditCard");
if (state == "cancel") {
return;

Просмотреть файл

@ -1625,6 +1625,33 @@ class CreditCards extends AutofillRecords {
delete creditCard["cc-exp"];
}
/**
* Normailze the given record and retrun the first matched guid if storage has the same record.
* @param {Object} targetCreditCard
* The credit card for duplication checking.
* @returns {string|null}
* Return the first guid if storage has the same credit card and null otherwise.
*/
getDuplicateGuid(targetCreditCard) {
let clonedTargetCreditCard = this._clone(targetCreditCard);
this._normalizeRecord(clonedTargetCreditCard);
for (let creditCard of this.data) {
let isDuplicate = this.VALID_FIELDS.every(field => {
if (!clonedTargetCreditCard[field]) {
return !creditCard[field];
}
if (field == "cc-number") {
return this._getMaskedCCNumber(clonedTargetCreditCard[field]) == creditCard[field];
}
return clonedTargetCreditCard[field] == creditCard[field];
});
if (isDuplicate) {
return creditCard.guid;
}
}
return null;
}
}
function ProfileStorage(path) {

Просмотреть файл

@ -45,8 +45,9 @@ add_task(async function test_submit_creditCard_saved() {
name.focus();
name.setUserInput("User 1");
let number = form.querySelector("#cc-number");
number.setUserInput("1111222233334444");
form.querySelector("#cc-number").setUserInput("1111222233334444");
form.querySelector("#cc-exp-month").setUserInput("12");
form.querySelector("#cc-exp-year").setUserInput("2017");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => setTimeout(resolve, 1000));
@ -63,6 +64,120 @@ add_task(async function test_submit_creditCard_saved() {
is(creditCards[0]["cc-name"], "User 1", "Verify the name field");
});
add_task(async function test_submit_untouched_creditCard_form() {
await BrowserTestUtils.withNewTab({gBrowser, url: CREDITCARD_FORM_URL},
async function(browser) {
await openPopupOn(browser, "form #cc-name");
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => setTimeout(resolve, 1000));
form.querySelector("input[type=submit]").click();
});
await sleep(1000);
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
}
);
let creditCards = await getCreditCards();
is(creditCards.length, 1, "Still 1 credit card in storage");
is(creditCards[0]["cc-name"], "User 1", "Verify the name field");
is(creditCards[0].timesUsed, 1, "timesUsed field set to 1");
});
add_task(async function test_submit_changed_creditCard_form() {
await BrowserTestUtils.withNewTab({gBrowser, url: CREDITCARD_FORM_URL},
async function(browser) {
let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
"popupshown");
await openPopupOn(browser, "form #cc-name");
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
let name = form.querySelector("#cc-name");
name.focus();
await new Promise(resolve => setTimeout(resolve, 1000));
name.setUserInput("");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => setTimeout(resolve, 1000));
form.querySelector("input[type=submit]").click();
});
await promiseShown;
await clickDoorhangerButton(SECONDARY_BUTTON);
}
);
let creditCards = await getCreditCards();
is(creditCards.length, 1, "Still 1 credit card in storage");
is(creditCards[0]["cc-name"], "User 1", "Verify the name field");
});
add_task(async function test_submit_duplicate_creditCard_form() {
await BrowserTestUtils.withNewTab({gBrowser, url: CREDITCARD_FORM_URL},
async function(browser) {
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
let name = form.querySelector("#cc-name");
name.focus();
name.setUserInput("User 1");
form.querySelector("#cc-number").setUserInput("1111222233334444");
form.querySelector("#cc-exp-month").setUserInput("12");
form.querySelector("#cc-exp-year").setUserInput("2017");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => setTimeout(resolve, 1000));
form.querySelector("input[type=submit]").click();
});
await sleep(1000);
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
}
);
let creditCards = await getCreditCards();
is(creditCards.length, 1, "Still 1 credit card in storage");
is(creditCards[0]["cc-name"], "User 1", "Verify the name field");
is(creditCards[0].timesUsed, 1, "timesUsed field set to 1");
});
add_task(async function test_submit_unnormailzed_creditCard_form() {
await BrowserTestUtils.withNewTab({gBrowser, url: CREDITCARD_FORM_URL},
async function(browser) {
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
let name = form.querySelector("#cc-name");
name.focus();
name.setUserInput("User 1");
form.querySelector("#cc-number").setUserInput("1111222233334444");
form.querySelector("#cc-exp-month").setUserInput("12");
// Set unnormalized year
form.querySelector("#cc-exp-year").setUserInput("17");
// Wait 1000ms before submission to make sure the input value applied
await new Promise(resolve => setTimeout(resolve, 1000));
form.querySelector("input[type=submit]").click();
});
await sleep(1000);
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
}
);
let creditCards = await getCreditCards();
is(creditCards.length, 1, "Still 1 credit card in storage");
is(creditCards[0]["cc-exp-year"], "2017", "Verify the expiry year field");
});
add_task(async function test_submit_creditCard_never_save() {
await BrowserTestUtils.withNewTab({gBrowser, url: CREDITCARD_FORM_URL},
async function(browser) {

Просмотреть файл

@ -19,7 +19,7 @@ const EDIT_CREDIT_CARD_DIALOG_URL = "chrome://formautofill/content/editCreditCar
const BASE_URL = "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/";
const FORM_URL = "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/autocomplete_basic.html";
const CREDITCARD_FORM_URL =
"http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/autocomplete_creditcard_basic.html";
"https://example.org/browser/browser/extensions/formautofill/test/browser/autocomplete_creditcard_basic.html";
const FTU_PREF = "extensions.formautofill.firstTimeUse";
const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available";