зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1362911 - [Form Autofill] Rename "profiles" to "addresses" in the storage. r=MattN
MozReview-Commit-ID: J5QnWv343xq --HG-- extra : rebase_source : 25bb9534f4f5aabd7f33875f52f2d00cd480fda8
This commit is contained in:
Родитель
43998dbb90
Коммит
0538cf7020
|
@ -106,7 +106,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
this._getProfiles({info, searchString}).then((profiles) => {
|
||||
this._getAddresses({info, searchString}).then((addresses) => {
|
||||
if (this.forceStop) {
|
||||
return;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
|||
let result = new ProfileAutoCompleteResult(searchString,
|
||||
info.fieldName,
|
||||
allFieldNames,
|
||||
profiles,
|
||||
addresses,
|
||||
{});
|
||||
|
||||
listener.onSearchResult(this, result);
|
||||
|
@ -132,27 +132,27 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Get the profile data from parent process for AutoComplete result.
|
||||
* Get the address data from parent process for AutoComplete result.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} data
|
||||
* Parameters for querying the corresponding result.
|
||||
* @param {string} data.searchString
|
||||
* The typed string for filtering out the matched profile.
|
||||
* The typed string for filtering out the matched address.
|
||||
* @param {string} data.info
|
||||
* The input autocomplete property's information.
|
||||
* @returns {Promise}
|
||||
* Promise that resolves when profiles returned from parent process.
|
||||
* Promise that resolves when addresses returned from parent process.
|
||||
*/
|
||||
_getProfiles(data) {
|
||||
this.log.debug("_getProfiles with data:", data);
|
||||
_getAddresses(data) {
|
||||
this.log.debug("_getAddresses with data:", data);
|
||||
return new Promise((resolve) => {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
|
||||
resolve(result.data);
|
||||
});
|
||||
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", data);
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", data);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -76,9 +76,9 @@ FormAutofillParent.prototype = {
|
|||
this._profileStore.initialize();
|
||||
|
||||
Services.obs.addObserver(this, "advanced-pane-loaded");
|
||||
Services.ppmm.addMessageListener("FormAutofill:GetProfiles", this);
|
||||
Services.ppmm.addMessageListener("FormAutofill:SaveProfile", this);
|
||||
Services.ppmm.addMessageListener("FormAutofill:RemoveProfiles", this);
|
||||
Services.ppmm.addMessageListener("FormAutofill:GetAddresses", this);
|
||||
Services.ppmm.addMessageListener("FormAutofill:SaveAddress", this);
|
||||
Services.ppmm.addMessageListener("FormAutofill:RemoveAddresses", this);
|
||||
|
||||
// Observing the pref and storage changes
|
||||
Services.prefs.addObserver(ENABLED_PREF, this);
|
||||
|
@ -182,19 +182,19 @@ FormAutofillParent.prototype = {
|
|||
*/
|
||||
receiveMessage({name, data, target}) {
|
||||
switch (name) {
|
||||
case "FormAutofill:GetProfiles": {
|
||||
this._getProfiles(data, target);
|
||||
case "FormAutofill:GetAddresses": {
|
||||
this._getAddresses(data, target);
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:SaveProfile": {
|
||||
case "FormAutofill:SaveAddress": {
|
||||
if (data.guid) {
|
||||
this.getProfileStore().update(data.guid, data.profile);
|
||||
this.getProfileStore().update(data.guid, data.address);
|
||||
} else {
|
||||
this.getProfileStore().add(data.profile);
|
||||
this.getProfileStore().add(data.address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:RemoveProfiles": {
|
||||
case "FormAutofill:RemoveAddresses": {
|
||||
data.guids.forEach(guid => this.getProfileStore().remove(guid));
|
||||
break;
|
||||
}
|
||||
|
@ -223,34 +223,35 @@ FormAutofillParent.prototype = {
|
|||
this._profileStore = null;
|
||||
}
|
||||
|
||||
Services.ppmm.removeMessageListener("FormAutofill:GetProfiles", this);
|
||||
Services.ppmm.removeMessageListener("FormAutofill:SaveProfile", this);
|
||||
Services.ppmm.removeMessageListener("FormAutofill:RemoveProfiles", this);
|
||||
Services.ppmm.removeMessageListener("FormAutofill:GetAddresses", this);
|
||||
Services.ppmm.removeMessageListener("FormAutofill:SaveAddress", this);
|
||||
Services.ppmm.removeMessageListener("FormAutofill:RemoveAddresses", this);
|
||||
Services.obs.removeObserver(this, "advanced-pane-loaded");
|
||||
Services.prefs.removeObserver(ENABLED_PREF, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the profile data from profile store and return profiles back to content process.
|
||||
* Get the address data from profile store and return addresses back to content
|
||||
* process.
|
||||
*
|
||||
* @private
|
||||
* @param {string} data.searchString
|
||||
* The typed string for filtering out the matched profile.
|
||||
* The typed string for filtering out the matched address.
|
||||
* @param {string} data.info
|
||||
* The input autocomplete property's information.
|
||||
* @param {nsIFrameMessageManager} target
|
||||
* Content's message manager.
|
||||
*/
|
||||
_getProfiles({searchString, info}, target) {
|
||||
let profiles = [];
|
||||
_getAddresses({searchString, info}, target) {
|
||||
let addresses = [];
|
||||
|
||||
if (info && info.fieldName) {
|
||||
profiles = this._profileStore.getByFilter({searchString, info});
|
||||
addresses = this._profileStore.getByFilter({searchString, info});
|
||||
} else {
|
||||
profiles = this._profileStore.getAll();
|
||||
addresses = this._profileStore.getAll();
|
||||
}
|
||||
|
||||
target.sendAsyncMessage("FormAutofill:Profiles", profiles);
|
||||
target.sendAsyncMessage("FormAutofill:Addresses", addresses);
|
||||
},
|
||||
|
||||
_updateSavedFieldNames() {
|
||||
|
@ -260,9 +261,9 @@ FormAutofillParent.prototype = {
|
|||
Services.ppmm.initialProcessData.autofillSavedFieldNames.clear();
|
||||
}
|
||||
|
||||
this._profileStore.getAll().forEach((profile) => {
|
||||
Object.keys(profile).forEach((fieldName) => {
|
||||
if (!profile[fieldName]) {
|
||||
this._profileStore.getAll().forEach((address) => {
|
||||
Object.keys(address).forEach((fieldName) => {
|
||||
if (!address[fieldName]) {
|
||||
return;
|
||||
}
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames.add(fieldName);
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
*
|
||||
* {
|
||||
* version: 1,
|
||||
* profiles: [
|
||||
* addresses: [
|
||||
* {
|
||||
* guid, // 12 character...
|
||||
* guid, // 12 characters
|
||||
*
|
||||
* // profile
|
||||
* // address fields
|
||||
* given-name,
|
||||
* additional-name,
|
||||
* family-name,
|
||||
|
@ -30,6 +30,7 @@
|
|||
*
|
||||
* // computed fields (These fields are not stored in the file as they are
|
||||
* // generated at runtime.)
|
||||
* name,
|
||||
* address-line1,
|
||||
* address-line2,
|
||||
* address-line3,
|
||||
|
@ -87,26 +88,12 @@ const VALID_FIELDS = [
|
|||
"email",
|
||||
];
|
||||
|
||||
// TODO: Remove this once we can add profile from preference.
|
||||
const MOCK_MODE = false;
|
||||
const MOCK_STORAGE = [{
|
||||
guid: "test-guid-1",
|
||||
organization: "Sesame Street",
|
||||
"street-address": "123 Sesame Street.",
|
||||
tel: "1-345-345-3456",
|
||||
}, {
|
||||
guid: "test-guid-2",
|
||||
organization: "Mozilla",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
tel: "1-650-903-0800",
|
||||
}];
|
||||
|
||||
function ProfileStorage(path) {
|
||||
this._path = path;
|
||||
}
|
||||
|
||||
ProfileStorage.prototype = {
|
||||
// These fields are defined internally for each profile.
|
||||
// These fields are defined internally for each record.
|
||||
INTERNAL_FIELDS:
|
||||
["guid", "timeCreated", "timeLastUsed", "timeLastModified", "timesUsed"],
|
||||
/**
|
||||
|
@ -125,160 +112,160 @@ ProfileStorage.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Adds a new profile.
|
||||
* Adds a new address.
|
||||
*
|
||||
* @param {Profile} profile
|
||||
* The new profile for saving.
|
||||
* @param {Address} address
|
||||
* The new address for saving.
|
||||
*/
|
||||
add(profile) {
|
||||
log.debug("add:", profile);
|
||||
add(address) {
|
||||
log.debug("add:", address);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileToSave = this._clone(profile);
|
||||
this._normalizeProfile(profileToSave);
|
||||
let addressToSave = this._clone(address);
|
||||
this._normalizeAddress(addressToSave);
|
||||
|
||||
profileToSave.guid = gUUIDGenerator.generateUUID().toString()
|
||||
addressToSave.guid = gUUIDGenerator.generateUUID().toString()
|
||||
.replace(/[{}-]/g, "").substring(0, 12);
|
||||
|
||||
// Metadata
|
||||
let now = Date.now();
|
||||
profileToSave.timeCreated = now;
|
||||
profileToSave.timeLastModified = now;
|
||||
profileToSave.timeLastUsed = 0;
|
||||
profileToSave.timesUsed = 0;
|
||||
addressToSave.timeCreated = now;
|
||||
addressToSave.timeLastModified = now;
|
||||
addressToSave.timeLastUsed = 0;
|
||||
addressToSave.timesUsed = 0;
|
||||
|
||||
this._store.data.profiles.push(profileToSave);
|
||||
this._store.data.addresses.push(addressToSave);
|
||||
|
||||
this._store.saveSoon();
|
||||
Services.obs.notifyObservers(null, "formautofill-storage-changed", "add");
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the specified profile.
|
||||
* Update the specified address.
|
||||
*
|
||||
* @param {string} guid
|
||||
* Indicates which profile to update.
|
||||
* @param {Profile} profile
|
||||
* The new profile used to overwrite the old one.
|
||||
* Indicates which address to update.
|
||||
* @param {Address} address
|
||||
* The new address used to overwrite the old one.
|
||||
*/
|
||||
update(guid, profile) {
|
||||
log.debug("update:", guid, profile);
|
||||
update(guid, address) {
|
||||
log.debug("update:", guid, address);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileFound = this._findByGUID(guid);
|
||||
if (!profileFound) {
|
||||
throw new Error("No matching profile.");
|
||||
let addressFound = this._findByGUID(guid);
|
||||
if (!addressFound) {
|
||||
throw new Error("No matching record.");
|
||||
}
|
||||
|
||||
let profileToUpdate = this._clone(profile);
|
||||
this._normalizeProfile(profileToUpdate);
|
||||
let addressToUpdate = this._clone(address);
|
||||
this._normalizeAddress(addressToUpdate);
|
||||
|
||||
for (let field of VALID_FIELDS) {
|
||||
if (profileToUpdate[field] !== undefined) {
|
||||
profileFound[field] = profileToUpdate[field];
|
||||
if (addressToUpdate[field] !== undefined) {
|
||||
addressFound[field] = addressToUpdate[field];
|
||||
} else {
|
||||
delete profileFound[field];
|
||||
delete addressFound[field];
|
||||
}
|
||||
}
|
||||
|
||||
profileFound.timeLastModified = Date.now();
|
||||
addressFound.timeLastModified = Date.now();
|
||||
|
||||
this._store.saveSoon();
|
||||
Services.obs.notifyObservers(null, "formautofill-storage-changed", "update");
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies the stroage of the use of the specified profile, so we can update
|
||||
* Notifies the stroage of the use of the specified address, so we can update
|
||||
* the metadata accordingly.
|
||||
*
|
||||
* @param {string} guid
|
||||
* Indicates which profile to be notified.
|
||||
* Indicates which address to be notified.
|
||||
*/
|
||||
notifyUsed(guid) {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileFound = this._findByGUID(guid);
|
||||
if (!profileFound) {
|
||||
throw new Error("No matching profile.");
|
||||
let addressFound = this._findByGUID(guid);
|
||||
if (!addressFound) {
|
||||
throw new Error("No matching record.");
|
||||
}
|
||||
|
||||
profileFound.timesUsed++;
|
||||
profileFound.timeLastUsed = Date.now();
|
||||
addressFound.timesUsed++;
|
||||
addressFound.timeLastUsed = Date.now();
|
||||
|
||||
this._store.saveSoon();
|
||||
Services.obs.notifyObservers(null, "formautofill-storage-changed", "notifyUsed");
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the specified profile. No error occurs if the profile isn't found.
|
||||
* Removes the specified address. No error occurs if the address isn't found.
|
||||
*
|
||||
* @param {string} guid
|
||||
* Indicates which profile to remove.
|
||||
* Indicates which address to remove.
|
||||
*/
|
||||
remove(guid) {
|
||||
log.debug("remove:", guid);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
this._store.data.profiles =
|
||||
this._store.data.profiles.filter(profile => profile.guid != guid);
|
||||
this._store.data.addresses =
|
||||
this._store.data.addresses.filter(address => address.guid != guid);
|
||||
this._store.saveSoon();
|
||||
Services.obs.notifyObservers(null, "formautofill-storage-changed", "remove");
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the profile with the specified GUID.
|
||||
* Returns the address with the specified GUID.
|
||||
*
|
||||
* @param {string} guid
|
||||
* Indicates which profile to retrieve.
|
||||
* @returns {Profile}
|
||||
* A clone of the profile.
|
||||
* Indicates which address to retrieve.
|
||||
* @returns {Address}
|
||||
* A clone of the address.
|
||||
*/
|
||||
get(guid) {
|
||||
log.debug("get:", guid);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileFound = this._findByGUID(guid);
|
||||
if (!profileFound) {
|
||||
throw new Error("No matching profile.");
|
||||
let addressFound = this._findByGUID(guid);
|
||||
if (!addressFound) {
|
||||
throw new Error("No matching record.");
|
||||
}
|
||||
|
||||
// Profile is cloned to avoid accidental modifications from outside.
|
||||
let clonedProfile = this._clone(profileFound);
|
||||
this._computeFields(clonedProfile);
|
||||
return clonedProfile;
|
||||
// The record is cloned to avoid accidental modifications from outside.
|
||||
let clonedAddress = this._clone(addressFound);
|
||||
this._computeFields(clonedAddress);
|
||||
return clonedAddress;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all profiles.
|
||||
* Returns all addresses.
|
||||
*
|
||||
* @returns {Array.<Profile>}
|
||||
* An array containing clones of all profiles.
|
||||
* @returns {Array.<Address>}
|
||||
* An array containing clones of all addresses.
|
||||
*/
|
||||
getAll() {
|
||||
log.debug("getAll");
|
||||
this._store.ensureDataReady();
|
||||
|
||||
// Profiles are cloned to avoid accidental modifications from outside.
|
||||
let clonedProfiles = this._store.data.profiles.map(this._clone);
|
||||
clonedProfiles.forEach(this._computeFields);
|
||||
return clonedProfiles;
|
||||
// Records are cloned to avoid accidental modifications from outside.
|
||||
let clonedAddresses = this._store.data.addresses.map(this._clone);
|
||||
clonedAddresses.forEach(this._computeFields);
|
||||
return clonedAddresses;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the filtered profiles based on input's information and searchString.
|
||||
* Returns the filtered addresses based on input's information and searchString.
|
||||
*
|
||||
* @returns {Array.<Profile>}
|
||||
* An array containing clones of matched profiles.
|
||||
* @returns {Array.<Address>}
|
||||
* An array containing clones of matched addresses.
|
||||
*/
|
||||
getByFilter({info, searchString}) {
|
||||
log.debug("getByFilter:", info, searchString);
|
||||
|
||||
let lcSearchString = searchString.toLowerCase();
|
||||
let result = this.getAll().filter(profile => {
|
||||
let result = this.getAll().filter(address => {
|
||||
// Return true if string is not provided and field exists.
|
||||
// TODO: We'll need to check if the address is for billing or shipping.
|
||||
// (Bug 1358941)
|
||||
let name = profile[info.fieldName];
|
||||
let name = address[info.fieldName];
|
||||
|
||||
if (!searchString) {
|
||||
return !!name;
|
||||
|
@ -291,88 +278,88 @@ ProfileStorage.prototype = {
|
|||
return result;
|
||||
},
|
||||
|
||||
_clone(profile) {
|
||||
return Object.assign({}, profile);
|
||||
_clone(record) {
|
||||
return Object.assign({}, record);
|
||||
},
|
||||
|
||||
_findByGUID(guid) {
|
||||
return this._store.data.profiles.find(profile => profile.guid == guid);
|
||||
return this._store.data.addresses.find(address => address.guid == guid);
|
||||
},
|
||||
|
||||
_computeFields(profile) {
|
||||
_computeFields(address) {
|
||||
// Compute name
|
||||
profile.name = FormAutofillNameUtils.joinNameParts({
|
||||
given: profile["given-name"],
|
||||
middle: profile["additional-name"],
|
||||
family: profile["family-name"],
|
||||
address.name = FormAutofillNameUtils.joinNameParts({
|
||||
given: address["given-name"],
|
||||
middle: address["additional-name"],
|
||||
family: address["family-name"],
|
||||
});
|
||||
|
||||
// Compute address
|
||||
if (profile["street-address"]) {
|
||||
let streetAddress = profile["street-address"].split("\n");
|
||||
if (address["street-address"]) {
|
||||
let streetAddress = address["street-address"].split("\n");
|
||||
// TODO: we should prevent the dataloss by concatenating the rest of lines
|
||||
// with a locale-specific character in the future (bug 1360114).
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (streetAddress[i]) {
|
||||
profile["address-line" + (i + 1)] = streetAddress[i];
|
||||
address["address-line" + (i + 1)] = streetAddress[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_normalizeAddress(profile) {
|
||||
if (profile["address-line1"] || profile["address-line2"] ||
|
||||
profile["address-line3"]) {
|
||||
_normalizeAddressLines(address) {
|
||||
if (address["address-line1"] || address["address-line2"] ||
|
||||
address["address-line3"]) {
|
||||
// Treat "street-address" as "address-line1" if it contains only one line
|
||||
// and "address-line1" is omitted.
|
||||
if (!profile["address-line1"] && profile["street-address"] &&
|
||||
!profile["street-address"].includes("\n")) {
|
||||
profile["address-line1"] = profile["street-address"];
|
||||
delete profile["street-address"];
|
||||
if (!address["address-line1"] && address["street-address"] &&
|
||||
!address["street-address"].includes("\n")) {
|
||||
address["address-line1"] = address["street-address"];
|
||||
delete address["street-address"];
|
||||
}
|
||||
|
||||
// Remove "address-line*" but keep the values.
|
||||
let addressLines = [1, 2, 3].map(i => {
|
||||
let value = profile["address-line" + i];
|
||||
delete profile["address-line" + i];
|
||||
let value = address["address-line" + i];
|
||||
delete address["address-line" + i];
|
||||
return value;
|
||||
});
|
||||
|
||||
// Concatenate "address-line*" if "street-address" is omitted.
|
||||
if (!profile["street-address"]) {
|
||||
profile["street-address"] = addressLines.join("\n");
|
||||
if (!address["street-address"]) {
|
||||
address["street-address"] = addressLines.join("\n");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_normalizeName(profile) {
|
||||
if (!profile.name) {
|
||||
_normalizeName(address) {
|
||||
if (!address.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nameParts = FormAutofillNameUtils.splitName(profile.name);
|
||||
if (!profile["given-name"] && nameParts.given) {
|
||||
profile["given-name"] = nameParts.given;
|
||||
let nameParts = FormAutofillNameUtils.splitName(address.name);
|
||||
if (!address["given-name"] && nameParts.given) {
|
||||
address["given-name"] = nameParts.given;
|
||||
}
|
||||
if (!profile["additional-name"] && nameParts.middle) {
|
||||
profile["additional-name"] = nameParts.middle;
|
||||
if (!address["additional-name"] && nameParts.middle) {
|
||||
address["additional-name"] = nameParts.middle;
|
||||
}
|
||||
if (!profile["family-name"] && nameParts.family) {
|
||||
profile["family-name"] = nameParts.family;
|
||||
if (!address["family-name"] && nameParts.family) {
|
||||
address["family-name"] = nameParts.family;
|
||||
}
|
||||
delete profile.name;
|
||||
delete address.name;
|
||||
},
|
||||
|
||||
_normalizeProfile(profile) {
|
||||
this._normalizeName(profile);
|
||||
this._normalizeAddress(profile);
|
||||
_normalizeAddress(address) {
|
||||
this._normalizeName(address);
|
||||
this._normalizeAddressLines(address);
|
||||
|
||||
for (let key in profile) {
|
||||
for (let key in address) {
|
||||
if (!VALID_FIELDS.includes(key)) {
|
||||
throw new Error(`"${key}" is not a valid field.`);
|
||||
}
|
||||
if (typeof profile[key] !== "string" &&
|
||||
typeof profile[key] !== "number") {
|
||||
if (typeof address[key] !== "string" &&
|
||||
typeof address[key] !== "number") {
|
||||
throw new Error(`"${key}" contains invalid data type.`);
|
||||
}
|
||||
}
|
||||
|
@ -380,8 +367,8 @@ ProfileStorage.prototype = {
|
|||
|
||||
_dataPostProcessor(data) {
|
||||
data.version = SCHEMA_VERSION;
|
||||
if (!data.profiles) {
|
||||
data.profiles = MOCK_MODE ? MOCK_STORAGE : [];
|
||||
if (!data.addresses) {
|
||||
data.addresses = [];
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
|
|
@ -9,8 +9,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
function EditDialog(profile) {
|
||||
this._profile = profile;
|
||||
function EditDialog(address) {
|
||||
this._address = address;
|
||||
window.addEventListener("DOMContentLoaded", this, {once: true});
|
||||
}
|
||||
|
||||
|
@ -25,26 +25,26 @@ EditDialog.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Asks FormAutofillParent to save or update a profile.
|
||||
* Asks FormAutofillParent to save or update an address.
|
||||
* @param {object} data
|
||||
* {
|
||||
* {string} guid [optional]
|
||||
* {object} profile
|
||||
* {object} address
|
||||
* }
|
||||
*/
|
||||
saveProfile(data) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:SaveProfile", data);
|
||||
saveAddress(data) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fill the form with a profile object.
|
||||
* @param {object} profile
|
||||
* Fill the form with an address object.
|
||||
* @param {object} address
|
||||
*/
|
||||
loadInitialValues(profile) {
|
||||
for (let field in profile) {
|
||||
loadInitialValues(address) {
|
||||
for (let field in address) {
|
||||
let input = document.getElementById(field);
|
||||
if (input) {
|
||||
input.value = profile[field];
|
||||
input.value = address[field];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -53,7 +53,7 @@ EditDialog.prototype = {
|
|||
* Get inputs from the form.
|
||||
* @returns {object}
|
||||
*/
|
||||
buildProfileObject() {
|
||||
buildAddressObject() {
|
||||
return Array.from(document.forms[0].elements).reduce((obj, input) => {
|
||||
if (input.value) {
|
||||
obj[input.id] = input.value;
|
||||
|
@ -71,8 +71,8 @@ EditDialog.prototype = {
|
|||
switch (event.type) {
|
||||
case "DOMContentLoaded": {
|
||||
this.init();
|
||||
if (this._profile) {
|
||||
this.loadInitialValues(this._profile);
|
||||
if (this._address) {
|
||||
this.loadInitialValues(this._address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ EditDialog.prototype = {
|
|||
case "input": {
|
||||
// Toggle disabled attribute on the save button based on
|
||||
// whether the form is filled or empty.
|
||||
if (Object.keys(this.buildProfileObject()).length == 0) {
|
||||
if (Object.keys(this.buildAddressObject()).length == 0) {
|
||||
this.refs.save.setAttribute("disabled", true);
|
||||
} else {
|
||||
this.refs.save.removeAttribute("disabled");
|
||||
|
@ -104,14 +104,14 @@ EditDialog.prototype = {
|
|||
window.close();
|
||||
}
|
||||
if (event.target == this.refs.save) {
|
||||
if (this._profile) {
|
||||
this.saveProfile({
|
||||
guid: this._profile.guid,
|
||||
profile: this.buildProfileObject(),
|
||||
if (this._address) {
|
||||
this.saveAddress({
|
||||
guid: this._address.guid,
|
||||
address: this.buildAddressObject(),
|
||||
});
|
||||
} else {
|
||||
this.saveProfile({
|
||||
profile: this.buildProfileObject(),
|
||||
this.saveAddress({
|
||||
address: this.buildAddressObject(),
|
||||
});
|
||||
}
|
||||
this.detachEventListeners();
|
||||
|
|
|
@ -25,23 +25,23 @@ ManageProfileDialog.prototype = {
|
|||
|
||||
/**
|
||||
* Count the number of "formautofill-storage-changed" events epected to
|
||||
* receive to prevent repeatedly loading profiles.
|
||||
* receive to prevent repeatedly loading addresses.
|
||||
* @type {number}
|
||||
*/
|
||||
_pendingChangeCount: 0,
|
||||
|
||||
/**
|
||||
* Get the selected options on the profiles element.
|
||||
* Get the selected options on the addresses element.
|
||||
*
|
||||
* @returns {array<DOMElement>}
|
||||
*/
|
||||
get _selectedOptions() {
|
||||
return Array.from(this._elements.profiles.selectedOptions);
|
||||
return Array.from(this._elements.addresses.selectedOptions);
|
||||
},
|
||||
|
||||
init() {
|
||||
this._elements = {
|
||||
profiles: document.getElementById("profiles"),
|
||||
addresses: document.getElementById("profiles"),
|
||||
controlsContainer: document.getElementById("controls-container"),
|
||||
remove: document.getElementById("remove"),
|
||||
add: document.getElementById("add"),
|
||||
|
@ -57,84 +57,84 @@ ManageProfileDialog.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Load profiles and render them.
|
||||
* Load addresses and render them.
|
||||
*
|
||||
* @returns {promise}
|
||||
*/
|
||||
loadProfiles() {
|
||||
return this.getProfiles().then(profiles => {
|
||||
log.debug("profiles:", profiles);
|
||||
loadAddresses() {
|
||||
return this.getAddresses().then(addresses => {
|
||||
log.debug("addresses:", addresses);
|
||||
// Sort by last modified time starting with most recent
|
||||
profiles.sort((a, b) => b.timeLastModified - a.timeLastModified);
|
||||
this.renderProfileElements(profiles);
|
||||
addresses.sort((a, b) => b.timeLastModified - a.timeLastModified);
|
||||
this.renderAddressElements(addresses);
|
||||
this.updateButtonsStates(this._selectedOptions.length);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get profiles from storage.
|
||||
* Get addresses from storage.
|
||||
*
|
||||
* @returns {promise}
|
||||
*/
|
||||
getProfiles() {
|
||||
getAddresses() {
|
||||
return new Promise(resolve => {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
|
||||
resolve(result.data);
|
||||
});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", {});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", {});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Render the profiles onto the page while maintaining selected options if
|
||||
* Render the addresses onto the page while maintaining selected options if
|
||||
* they still exist.
|
||||
*
|
||||
* @param {array<object>} profiles
|
||||
* @param {array<object>} addresses
|
||||
*/
|
||||
renderProfileElements(profiles) {
|
||||
renderAddressElements(addresses) {
|
||||
let selectedGuids = this._selectedOptions.map(option => option.value);
|
||||
this.clearProfileElements();
|
||||
for (let profile of profiles) {
|
||||
let option = new Option(this.getProfileLabel(profile),
|
||||
profile.guid,
|
||||
this.clearAddressElements();
|
||||
for (let address of addresses) {
|
||||
let option = new Option(this.getAddressLabel(address),
|
||||
address.guid,
|
||||
false,
|
||||
selectedGuids.includes(profile.guid));
|
||||
option.profile = profile;
|
||||
this._elements.profiles.appendChild(option);
|
||||
selectedGuids.includes(address.guid));
|
||||
option.address = address;
|
||||
this._elements.addresses.appendChild(option);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all existing profile elements.
|
||||
* Remove all existing address elements.
|
||||
*/
|
||||
clearProfileElements() {
|
||||
let parent = this._elements.profiles;
|
||||
clearAddressElements() {
|
||||
let parent = this._elements.addresses;
|
||||
while (parent.lastChild) {
|
||||
parent.removeChild(parent.lastChild);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove profiles by guids.
|
||||
* Remove addresses by guids.
|
||||
* Keep track of the number of "formautofill-storage-changed" events to
|
||||
* ignore before loading profiles.
|
||||
* ignore before loading addresses.
|
||||
*
|
||||
* @param {array<string>} guids
|
||||
*/
|
||||
removeProfiles(guids) {
|
||||
removeAddresses(guids) {
|
||||
this._pendingChangeCount += guids.length - 1;
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveProfiles", {guids});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses", {guids});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get profile display label. It should display up to two pieces of
|
||||
* Get address display label. It should display up to two pieces of
|
||||
* information, separated by a comma.
|
||||
*
|
||||
* @param {object} profile
|
||||
* @param {object} address
|
||||
* @returns {string}
|
||||
*/
|
||||
getProfileLabel(profile) {
|
||||
getAddressLabel(address) {
|
||||
// TODO: Implement a smarter way for deciding what to display
|
||||
// as option text. Possibly improve the algorithm in
|
||||
// ProfileAutoCompleteResult.jsm and reuse it here.
|
||||
|
@ -152,7 +152,7 @@ ManageProfileDialog.prototype = {
|
|||
|
||||
let parts = [];
|
||||
for (const fieldName of fieldOrder) {
|
||||
let string = profile[fieldName];
|
||||
let string = address[fieldName];
|
||||
if (string) {
|
||||
parts.push(string);
|
||||
}
|
||||
|
@ -164,14 +164,14 @@ ManageProfileDialog.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Open the edit profile dialog to create/edit a profile.
|
||||
* Open the edit address dialog to create/edit an address.
|
||||
*
|
||||
* @param {object} profile [optional]
|
||||
* @param {object} address [optional]
|
||||
*/
|
||||
openEditDialog(profile) {
|
||||
openEditDialog(address) {
|
||||
window.openDialog(EDIT_PROFILE_URL, null,
|
||||
"chrome,centerscreen,modal,width=600,height=450",
|
||||
profile);
|
||||
address);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -203,7 +203,7 @@ ManageProfileDialog.prototype = {
|
|||
switch (event.type) {
|
||||
case "DOMContentLoaded": {
|
||||
this.init();
|
||||
this.loadProfiles();
|
||||
this.loadAddresses();
|
||||
break;
|
||||
}
|
||||
case "click": {
|
||||
|
@ -228,11 +228,11 @@ ManageProfileDialog.prototype = {
|
|||
*/
|
||||
handleClick(event) {
|
||||
if (event.target == this._elements.remove) {
|
||||
this.removeProfiles(this._selectedOptions.map(option => option.value));
|
||||
this.removeAddresses(this._selectedOptions.map(option => option.value));
|
||||
} else if (event.target == this._elements.add) {
|
||||
this.openEditDialog();
|
||||
} else if (event.target == this._elements.edit) {
|
||||
this.openEditDialog(this._selectedOptions[0].profile);
|
||||
this.openEditDialog(this._selectedOptions[0].address);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -243,7 +243,7 @@ ManageProfileDialog.prototype = {
|
|||
this._pendingChangeCount -= 1;
|
||||
return;
|
||||
}
|
||||
this.loadProfiles();
|
||||
this.loadAddresses();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -253,7 +253,7 @@ ManageProfileDialog.prototype = {
|
|||
*/
|
||||
attachEventListeners() {
|
||||
window.addEventListener("unload", this, {once: true});
|
||||
this._elements.profiles.addEventListener("change", this);
|
||||
this._elements.addresses.addEventListener("change", this);
|
||||
this._elements.controlsContainer.addEventListener("click", this);
|
||||
Services.obs.addObserver(this, "formautofill-storage-changed");
|
||||
},
|
||||
|
@ -262,7 +262,7 @@ ManageProfileDialog.prototype = {
|
|||
* Remove event listener
|
||||
*/
|
||||
detachEventListeners() {
|
||||
this._elements.profiles.removeEventListener("change", this);
|
||||
this._elements.addresses.removeEventListener("change", this);
|
||||
this._elements.controlsContainer.removeEventListener("click", this);
|
||||
Services.obs.removeObserver(this, "formautofill-storage-changed");
|
||||
},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
registerCleanupFunction(function* () {
|
||||
let profiles = yield getProfiles();
|
||||
if (profiles.length) {
|
||||
yield removeProfiles(profiles.map(profile => profile.guid));
|
||||
let addresses = yield getAddresses();
|
||||
if (addresses.length) {
|
||||
yield removeAddresses(addresses.map(address => address.guid));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -20,7 +20,7 @@ add_task(function* test_cancelEditProfileDialog() {
|
|||
});
|
||||
});
|
||||
|
||||
add_task(function* test_saveProfile() {
|
||||
add_task(function* test_saveAddress() {
|
||||
yield new Promise(resolve => {
|
||||
let win = window.openDialog(EDIT_PROFILE_DIALOG_URL, null, null, null);
|
||||
win.addEventListener("load", () => {
|
||||
|
@ -29,46 +29,46 @@ add_task(function* test_saveProfile() {
|
|||
resolve();
|
||||
}, {once: true});
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["given-name"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["given-name"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["additional-name"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["additional-name"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["family-name"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["family-name"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1.organization, {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1.organization, {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["street-address"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["street-address"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["address-level2"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["address-level2"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["address-level1"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["address-level1"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1["postal-code"], {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1["postal-code"], {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1.country, {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1.country, {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1.email, {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1.email, {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey(TEST_PROFILE_1.tel, {}, win);
|
||||
EventUtils.synthesizeKey(TEST_ADDRESS_1.tel, {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
EventUtils.synthesizeKey("VK_TAB", {}, win);
|
||||
info("saving profile");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, win);
|
||||
}, {once: true});
|
||||
});
|
||||
let profiles = yield getProfiles();
|
||||
let addresses = yield getAddresses();
|
||||
|
||||
is(profiles.length, 1, "only one profile is in storage");
|
||||
is(Object.keys(TEST_PROFILE_1).length, 11, "Sanity check number of properties");
|
||||
for (let [fieldName, fieldValue] of Object.entries(TEST_PROFILE_1)) {
|
||||
is(profiles[0][fieldName], fieldValue, "check " + fieldName);
|
||||
is(addresses.length, 1, "only one address is in storage");
|
||||
is(Object.keys(TEST_ADDRESS_1).length, 11, "Sanity check number of properties");
|
||||
for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_1)) {
|
||||
is(addresses[0][fieldName], fieldValue, "check " + fieldName);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_editProfile() {
|
||||
let profiles = yield getProfiles();
|
||||
let addresses = yield getAddresses();
|
||||
yield new Promise(resolve => {
|
||||
let win = window.openDialog(EDIT_PROFILE_DIALOG_URL, null, null, profiles[0]);
|
||||
let win = window.openDialog(EDIT_PROFILE_DIALOG_URL, null, null, addresses[0]);
|
||||
win.addEventListener("load", () => {
|
||||
win.addEventListener("unload", () => {
|
||||
ok(true, "Edit profile dialog is closed");
|
||||
|
@ -79,12 +79,12 @@ add_task(function* test_editProfile() {
|
|||
win.document.querySelector("#save").click();
|
||||
}, {once: true});
|
||||
});
|
||||
profiles = yield getProfiles();
|
||||
addresses = yield getAddresses();
|
||||
|
||||
is(profiles.length, 1, "only one profile is in storage");
|
||||
is(profiles[0]["given-name"], TEST_PROFILE_1["given-name"] + "test", "given-name changed");
|
||||
yield removeProfiles([profiles[0].guid]);
|
||||
is(addresses.length, 1, "only one address is in storage");
|
||||
is(addresses[0]["given-name"], TEST_ADDRESS_1["given-name"] + "test", "given-name changed");
|
||||
yield removeAddresses([addresses[0].guid]);
|
||||
|
||||
profiles = yield getProfiles();
|
||||
is(profiles.length, 0, "Profile storage is empty");
|
||||
addresses = yield getAddresses();
|
||||
is(addresses.length, 0, "Address storage is empty");
|
||||
});
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_SELECTORS = {
|
||||
selProfiles: "#profiles",
|
||||
selAddresses: "#profiles",
|
||||
btnRemove: "#remove",
|
||||
btnAdd: "#add",
|
||||
btnEdit: "#edit",
|
||||
};
|
||||
|
||||
function waitForProfiles() {
|
||||
function waitForAddresses() {
|
||||
return new Promise(resolve => {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
|
||||
// Wait for the next tick for elements to get rendered.
|
||||
SimpleTest.executeSoon(resolve.bind(null, result.data));
|
||||
});
|
||||
|
@ -18,21 +18,21 @@ function waitForProfiles() {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function* () {
|
||||
let profiles = yield getProfiles();
|
||||
if (profiles.length) {
|
||||
yield removeProfiles(profiles.map(profile => profile.guid));
|
||||
let addresses = yield getAddresses();
|
||||
if (addresses.length) {
|
||||
yield removeAddresses(addresses.map(address => address.guid));
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_manageProfilesInitialState() {
|
||||
yield BrowserTestUtils.withNewTab({gBrowser, url: MANAGE_PROFILES_DIALOG_URL}, function* (browser) {
|
||||
yield ContentTask.spawn(browser, TEST_SELECTORS, (args) => {
|
||||
let selProfiles = content.document.querySelector(args.selProfiles);
|
||||
let selAddresses = content.document.querySelector(args.selAddresses);
|
||||
let btnRemove = content.document.querySelector(args.btnRemove);
|
||||
let btnEdit = content.document.querySelector(args.btnEdit);
|
||||
let btnAdd = content.document.querySelector(args.btnAdd);
|
||||
|
||||
is(selProfiles.length, 0, "No profile");
|
||||
is(selAddresses.length, 0, "No address");
|
||||
is(btnAdd.disabled, false, "Add button enabled");
|
||||
is(btnRemove.disabled, true, "Remove button disabled");
|
||||
is(btnEdit.disabled, true, "Edit button disabled");
|
||||
|
@ -41,50 +41,50 @@ add_task(function* test_manageProfilesInitialState() {
|
|||
});
|
||||
|
||||
add_task(function* test_removingSingleAndMultipleProfiles() {
|
||||
yield saveProfile(TEST_PROFILE_1);
|
||||
yield saveProfile(TEST_PROFILE_2);
|
||||
yield saveProfile(TEST_PROFILE_3);
|
||||
yield saveAddress(TEST_ADDRESS_1);
|
||||
yield saveAddress(TEST_ADDRESS_2);
|
||||
yield saveAddress(TEST_ADDRESS_3);
|
||||
|
||||
let win = window.openDialog(MANAGE_PROFILES_DIALOG_URL);
|
||||
yield waitForProfiles();
|
||||
yield waitForAddresses();
|
||||
|
||||
let selProfiles = win.document.querySelector(TEST_SELECTORS.selProfiles);
|
||||
let selAddresses = win.document.querySelector(TEST_SELECTORS.selAddresses);
|
||||
let btnRemove = win.document.querySelector(TEST_SELECTORS.btnRemove);
|
||||
let btnEdit = win.document.querySelector(TEST_SELECTORS.btnEdit);
|
||||
|
||||
is(selProfiles.length, 3, "Three profiles");
|
||||
is(selAddresses.length, 3, "Three addresses");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(selProfiles.children[0], {}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(selAddresses.children[0], {}, win);
|
||||
is(btnRemove.disabled, false, "Remove button enabled");
|
||||
is(btnEdit.disabled, false, "Edit button enabled");
|
||||
EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win);
|
||||
yield waitForProfiles();
|
||||
is(selProfiles.length, 2, "Two profiles left");
|
||||
yield waitForAddresses();
|
||||
is(selAddresses.length, 2, "Two addresses left");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(selProfiles.children[0], {}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(selProfiles.children[1],
|
||||
EventUtils.synthesizeMouseAtCenter(selAddresses.children[0], {}, win);
|
||||
EventUtils.synthesizeMouseAtCenter(selAddresses.children[1],
|
||||
{shiftKey: true}, win);
|
||||
is(btnEdit.disabled, true, "Edit button disabled when multi-select");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win);
|
||||
yield waitForProfiles();
|
||||
is(selProfiles.length, 0, "All profiles are removed");
|
||||
yield waitForAddresses();
|
||||
is(selAddresses.length, 0, "All addresses are removed");
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
add_task(function* test_profilesDialogWatchesStorageChanges() {
|
||||
let win = window.openDialog(MANAGE_PROFILES_DIALOG_URL);
|
||||
yield waitForProfiles();
|
||||
yield waitForAddresses();
|
||||
|
||||
let selProfiles = win.document.querySelector(TEST_SELECTORS.selProfiles);
|
||||
let selAddresses = win.document.querySelector(TEST_SELECTORS.selAddresses);
|
||||
|
||||
yield saveProfile(TEST_PROFILE_1);
|
||||
let profiles = yield waitForProfiles();
|
||||
is(selProfiles.length, 1, "One profile is shown");
|
||||
yield saveAddress(TEST_ADDRESS_1);
|
||||
let addresses = yield waitForAddresses();
|
||||
is(selAddresses.length, 1, "One address is shown");
|
||||
|
||||
yield removeProfiles([profiles[0].guid]);
|
||||
yield waitForProfiles();
|
||||
is(selProfiles.length, 0, "Profile is removed");
|
||||
yield removeAddresses([addresses[0].guid]);
|
||||
yield waitForAddresses();
|
||||
is(selAddresses.length, 0, "Address is removed");
|
||||
win.close();
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* exported MANAGE_PROFILES_DIALOG_URL, EDIT_PROFILE_DIALOG_URL,
|
||||
TEST_PROFILE_1, TEST_PROFILE_2, TEST_PROFILE_3,
|
||||
getProfiles, saveProfile, removeProfiles */
|
||||
TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3,
|
||||
getAddresses, saveAddress, removeAddresses */
|
||||
|
||||
"use strict";
|
||||
|
||||
const MANAGE_PROFILES_DIALOG_URL = "chrome://formautofill/content/manageProfiles.xhtml";
|
||||
const EDIT_PROFILE_DIALOG_URL = "chrome://formautofill/content/editProfile.xhtml";
|
||||
|
||||
const TEST_PROFILE_1 = {
|
||||
const TEST_ADDRESS_1 = {
|
||||
"given-name": "John",
|
||||
"additional-name": "R.",
|
||||
"family-name": "Smith",
|
||||
|
@ -21,32 +21,32 @@ const TEST_PROFILE_1 = {
|
|||
email: "timbl@w3.org",
|
||||
};
|
||||
|
||||
const TEST_PROFILE_2 = {
|
||||
const TEST_ADDRESS_2 = {
|
||||
"street-address": "Some Address",
|
||||
country: "US",
|
||||
};
|
||||
|
||||
const TEST_PROFILE_3 = {
|
||||
const TEST_ADDRESS_3 = {
|
||||
"street-address": "Other Address",
|
||||
"postal-code": "12345",
|
||||
};
|
||||
|
||||
function getProfiles() {
|
||||
function getAddresses() {
|
||||
return new Promise(resolve => {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
|
||||
resolve(result.data);
|
||||
});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", {});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", {});
|
||||
});
|
||||
}
|
||||
|
||||
function saveProfile(profile) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:SaveProfile", {profile});
|
||||
function saveAddress(address) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", {address});
|
||||
return TestUtils.topicObserved("formautofill-storage-changed");
|
||||
}
|
||||
|
||||
function removeProfiles(guids) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveProfiles", {guids});
|
||||
function removeAddresses(guids) {
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses", {guids});
|
||||
return TestUtils.topicObserved("formautofill-storage-changed");
|
||||
}
|
||||
|
|
|
@ -21,33 +21,33 @@ function checkMenuEntries(expectedValues) {
|
|||
}
|
||||
}
|
||||
|
||||
function addProfile(profile) {
|
||||
function addAddress(address) {
|
||||
return new Promise(resolve => {
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddProfile", {profile});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileAdded", function onAdded(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileAdded", onAdded);
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddAddress", {address});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:AddressAdded", function onAdded(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressAdded", onAdded);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeProfile(guid) {
|
||||
function removeAddress(guid) {
|
||||
return new Promise(resolve => {
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveProfile", {guid});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileRemoved", function onDeleted(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileRemoved", onDeleted);
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveAddress", {guid});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:AddressRemoved", function onDeleted(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressRemoved", onDeleted);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateProfile(guid, profile) {
|
||||
function updateAddress(guid, address) {
|
||||
return new Promise(resolve => {
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateProfile", {profile, guid});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileUpdated", function onUpdated(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileUpdated", onUpdated);
|
||||
formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateAddress", {address, guid});
|
||||
formFillChromeScript.addMessageListener("FormAutofillTest:AddressUpdated", function onUpdated(data) {
|
||||
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressUpdated", onUpdated);
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
|
|
@ -8,19 +8,19 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var ParentUtils = {
|
||||
cleanUpProfile() {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
cleanUpAddress() {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
|
||||
|
||||
let profiles = result.data;
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveProfiles",
|
||||
{guids: profiles.map(profile => profile.guid)});
|
||||
let addresses = result.data;
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses",
|
||||
{guids: addresses.map(address => address.guid)});
|
||||
});
|
||||
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", {searchString: ""});
|
||||
Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", {searchString: ""});
|
||||
},
|
||||
|
||||
updateProfile(type, chromeMsg, msgData, contentMsg) {
|
||||
updateAddress(type, chromeMsg, msgData, contentMsg) {
|
||||
Services.cpmm.sendAsyncMessage(chromeMsg, msgData);
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
if (data != type) {
|
||||
|
@ -39,23 +39,23 @@ var ParentUtils = {
|
|||
|
||||
cleanup() {
|
||||
Services.obs.removeObserver(this, "formautofill-storage-changed");
|
||||
this.cleanUpProfile();
|
||||
this.cleanUpAddress();
|
||||
},
|
||||
};
|
||||
|
||||
ParentUtils.cleanUpProfile();
|
||||
ParentUtils.cleanUpAddress();
|
||||
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
|
||||
|
||||
addMessageListener("FormAutofillTest:AddProfile", (msg) => {
|
||||
ParentUtils.updateProfile("add", "FormAutofill:SaveProfile", msg, "FormAutofillTest:ProfileAdded");
|
||||
addMessageListener("FormAutofillTest:AddAddress", (msg) => {
|
||||
ParentUtils.updateAddress("add", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressAdded");
|
||||
});
|
||||
|
||||
addMessageListener("FormAutofillTest:RemoveProfile", (msg) => {
|
||||
ParentUtils.updateProfile("remove", "FormAutofill:Removefile", msg, "FormAutofillTest:ProfileRemoved");
|
||||
addMessageListener("FormAutofillTest:RemoveAddress", (msg) => {
|
||||
ParentUtils.updateAddress("remove", "FormAutofill:RemoveAddress", msg, "FormAutofillTest:AddressRemoved");
|
||||
});
|
||||
|
||||
addMessageListener("FormAutofillTest:UpdateProfile", (msg) => {
|
||||
ParentUtils.updateProfile("update", "FormAutofill:SaveProfile", msg, "FormAutofillTest:ProfileUpdated");
|
||||
addMessageListener("FormAutofillTest:UpdateAddress", (msg) => {
|
||||
ParentUtils.updateAddress("update", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressUpdated");
|
||||
});
|
||||
|
||||
addMessageListener("cleanup", () => {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Form autofill test: simple form profile autofill
|
||||
Form autofill test: simple form address autofill
|
||||
|
||||
<script>
|
||||
/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */
|
||||
|
@ -63,23 +63,23 @@ function checkAutoCompleteInputFilled(element, expectedvalue) {
|
|||
});
|
||||
}
|
||||
|
||||
function checkFormFilled(profile) {
|
||||
function checkFormFilled(address) {
|
||||
let promises = [];
|
||||
for (let prop in profile) {
|
||||
for (let prop in address) {
|
||||
let element = document.getElementById(prop);
|
||||
if (document.activeElement == element) {
|
||||
promises.push(checkAutoCompleteInputFilled(element, profile[prop]));
|
||||
promises.push(checkAutoCompleteInputFilled(element, address[prop]));
|
||||
} else {
|
||||
promises.push(checkInputFilled(element, profile[prop]));
|
||||
promises.push(checkInputFilled(element, address[prop]));
|
||||
}
|
||||
}
|
||||
doKey("return");
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function* setupProfileStorage() {
|
||||
yield addProfile(MOCK_STORAGE[0]);
|
||||
yield addProfile(MOCK_STORAGE[1]);
|
||||
function* setupAddressStorage() {
|
||||
yield addAddress(MOCK_STORAGE[0]);
|
||||
yield addAddress(MOCK_STORAGE[1]);
|
||||
}
|
||||
|
||||
function* setupFormHistory() {
|
||||
|
@ -99,33 +99,33 @@ add_task(function* history_only_menu_checking() {
|
|||
checkMenuEntries(["1-234-567-890"]);
|
||||
});
|
||||
|
||||
// Form with both history and profile storage.
|
||||
// Form with both history and address storage.
|
||||
add_task(function* check_menu_when_both_existed() {
|
||||
yield setupProfileStorage();
|
||||
yield setupAddressStorage();
|
||||
|
||||
setInput("#organization", "");
|
||||
doKey("down");
|
||||
yield expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(profile =>
|
||||
JSON.stringify({primary: profile.organization, secondary: profile["street-address"]})
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
|
||||
));
|
||||
|
||||
setInput("#street-address", "");
|
||||
doKey("down");
|
||||
yield expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(profile =>
|
||||
JSON.stringify({primary: profile["street-address"], secondary: profile.organization})
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address["street-address"], secondary: address.organization})
|
||||
));
|
||||
|
||||
setInput("#tel", "");
|
||||
doKey("down");
|
||||
yield expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(profile =>
|
||||
JSON.stringify({primary: profile.tel, secondary: profile["street-address"]})
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.tel, secondary: address["street-address"]})
|
||||
));
|
||||
});
|
||||
|
||||
// Display history search result if no matched data in profiles.
|
||||
// Display history search result if no matched data in addresses.
|
||||
add_task(function* check_fallback_for_mismatched_field() {
|
||||
setInput("#country", "");
|
||||
doKey("down");
|
||||
|
@ -133,19 +133,19 @@ add_task(function* check_fallback_for_mismatched_field() {
|
|||
checkMenuEntries(["US"]);
|
||||
});
|
||||
|
||||
// Autofill the profile from dropdown menu.
|
||||
// Autofill the address from dropdown menu.
|
||||
add_task(function* check_fields_after_form_autofill() {
|
||||
setInput("#organization", "Moz");
|
||||
doKey("down");
|
||||
yield expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(profile =>
|
||||
JSON.stringify({primary: profile.organization, secondary: profile["street-address"]})
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
|
||||
).slice(1));
|
||||
doKey("down");
|
||||
yield checkFormFilled(MOCK_STORAGE[1]);
|
||||
});
|
||||
|
||||
// Fallback to history search after autofill profile.
|
||||
// Fallback to history search after autofill address.
|
||||
add_task(function* check_fallback_after_form_autofill() {
|
||||
setInput("#tel", "");
|
||||
doKey("down");
|
||||
|
|
|
@ -9,7 +9,7 @@ Cu.import("resource://formautofill/ProfileStorage.jsm");
|
|||
|
||||
const TEST_STORE_FILE_NAME = "test-profile.json";
|
||||
|
||||
const TEST_PROFILE_1 = {
|
||||
const TEST_ADDRESS_1 = {
|
||||
"given-name": "Timothy",
|
||||
"additional-name": "John",
|
||||
"family-name": "Berners-Lee",
|
||||
|
@ -23,36 +23,36 @@ const TEST_PROFILE_1 = {
|
|||
email: "timbl@w3.org",
|
||||
};
|
||||
|
||||
const TEST_PROFILE_2 = {
|
||||
const TEST_ADDRESS_2 = {
|
||||
"street-address": "Some Address",
|
||||
country: "US",
|
||||
};
|
||||
|
||||
const TEST_PROFILE_3 = {
|
||||
const TEST_ADDRESS_3 = {
|
||||
"street-address": "Other Address",
|
||||
"postal-code": "12345",
|
||||
};
|
||||
|
||||
const TEST_PROFILE_WITH_INVALID_FIELD = {
|
||||
const TEST_ADDRESS_WITH_INVALID_FIELD = {
|
||||
"street-address": "Another Address",
|
||||
invalidField: "INVALID",
|
||||
};
|
||||
|
||||
let prepareTestProfiles = Task.async(function* (path) {
|
||||
let prepareTestRecords = Task.async(function* (path) {
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
profileStorage.add(TEST_PROFILE_1);
|
||||
profileStorage.add(TEST_ADDRESS_1);
|
||||
yield onChanged;
|
||||
profileStorage.add(TEST_PROFILE_2);
|
||||
profileStorage.add(TEST_ADDRESS_2);
|
||||
yield profileStorage._saveImmediately();
|
||||
});
|
||||
|
||||
let do_check_profile_matches = (profileWithMeta, profile) => {
|
||||
for (let key in profile) {
|
||||
do_check_eq(profileWithMeta[key], profile[key]);
|
||||
let do_check_record_matches = (recordWithMeta, record) => {
|
||||
for (let key in record) {
|
||||
do_check_eq(recordWithMeta[key], record[key]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,7 @@ add_task(function* test_initialize() {
|
|||
yield profileStorage.initialize();
|
||||
|
||||
do_check_eq(profileStorage._store.data.version, 1);
|
||||
do_check_eq(profileStorage._store.data.profiles.length, 0);
|
||||
do_check_eq(profileStorage._store.data.addresses.length, 0);
|
||||
|
||||
let data = profileStorage._store.data;
|
||||
|
||||
|
@ -76,150 +76,150 @@ add_task(function* test_initialize() {
|
|||
|
||||
add_task(function* test_getAll() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let addresses = profileStorage.getAll();
|
||||
|
||||
do_check_eq(profiles.length, 2);
|
||||
do_check_profile_matches(profiles[0], TEST_PROFILE_1);
|
||||
do_check_profile_matches(profiles[1], TEST_PROFILE_2);
|
||||
do_check_eq(addresses.length, 2);
|
||||
do_check_record_matches(addresses[0], TEST_ADDRESS_1);
|
||||
do_check_record_matches(addresses[1], TEST_ADDRESS_2);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
profiles[0].organization = "test";
|
||||
do_check_profile_matches(profileStorage.getAll()[0], TEST_PROFILE_1);
|
||||
addresses[0].organization = "test";
|
||||
do_check_record_matches(profileStorage.getAll()[0], TEST_ADDRESS_1);
|
||||
});
|
||||
|
||||
add_task(function* test_get() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let guid = profiles[0].guid;
|
||||
let addresses = profileStorage.getAll();
|
||||
let guid = addresses[0].guid;
|
||||
|
||||
let profile = profileStorage.get(guid);
|
||||
do_check_profile_matches(profile, TEST_PROFILE_1);
|
||||
let address = profileStorage.get(guid);
|
||||
do_check_record_matches(address, TEST_ADDRESS_1);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
profile.organization = "test";
|
||||
do_check_profile_matches(profileStorage.get(guid), TEST_PROFILE_1);
|
||||
address.organization = "test";
|
||||
do_check_record_matches(profileStorage.get(guid), TEST_ADDRESS_1);
|
||||
|
||||
Assert.throws(() => profileStorage.get("INVALID_GUID"),
|
||||
/No matching profile\./);
|
||||
/No matching record\./);
|
||||
});
|
||||
|
||||
add_task(function* test_getByFilter() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let filter = {info: {fieldName: "street-address"}, searchString: "Some"};
|
||||
let profiles = profileStorage.getByFilter(filter);
|
||||
do_check_eq(profiles.length, 1);
|
||||
do_check_profile_matches(profiles[0], TEST_PROFILE_2);
|
||||
let addresses = profileStorage.getByFilter(filter);
|
||||
do_check_eq(addresses.length, 1);
|
||||
do_check_record_matches(addresses[0], TEST_ADDRESS_2);
|
||||
|
||||
filter = {info: {fieldName: "country"}, searchString: "u"};
|
||||
profiles = profileStorage.getByFilter(filter);
|
||||
do_check_eq(profiles.length, 2);
|
||||
do_check_profile_matches(profiles[0], TEST_PROFILE_1);
|
||||
do_check_profile_matches(profiles[1], TEST_PROFILE_2);
|
||||
addresses = profileStorage.getByFilter(filter);
|
||||
do_check_eq(addresses.length, 2);
|
||||
do_check_record_matches(addresses[0], TEST_ADDRESS_1);
|
||||
do_check_record_matches(addresses[1], TEST_ADDRESS_2);
|
||||
|
||||
filter = {info: {fieldName: "street-address"}, searchString: "test"};
|
||||
profiles = profileStorage.getByFilter(filter);
|
||||
do_check_eq(profiles.length, 0);
|
||||
addresses = profileStorage.getByFilter(filter);
|
||||
do_check_eq(addresses.length, 0);
|
||||
|
||||
filter = {info: {fieldName: "street-address"}, searchString: ""};
|
||||
profiles = profileStorage.getByFilter(filter);
|
||||
do_check_eq(profiles.length, 2);
|
||||
addresses = profileStorage.getByFilter(filter);
|
||||
do_check_eq(addresses.length, 2);
|
||||
|
||||
// Check if the filtering logic is free from searching special chars.
|
||||
filter = {info: {fieldName: "street-address"}, searchString: ".*"};
|
||||
profiles = profileStorage.getByFilter(filter);
|
||||
do_check_eq(profiles.length, 0);
|
||||
addresses = profileStorage.getByFilter(filter);
|
||||
do_check_eq(addresses.length, 0);
|
||||
});
|
||||
|
||||
add_task(function* test_add() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let addresses = profileStorage.getAll();
|
||||
|
||||
do_check_eq(profiles.length, 2);
|
||||
do_check_eq(addresses.length, 2);
|
||||
|
||||
do_check_profile_matches(profiles[0], TEST_PROFILE_1);
|
||||
do_check_profile_matches(profiles[1], TEST_PROFILE_2);
|
||||
do_check_record_matches(addresses[0], TEST_ADDRESS_1);
|
||||
do_check_record_matches(addresses[1], TEST_ADDRESS_2);
|
||||
|
||||
do_check_neq(profiles[0].guid, undefined);
|
||||
do_check_neq(profiles[0].timeCreated, undefined);
|
||||
do_check_eq(profiles[0].timeLastModified, profiles[0].timeCreated);
|
||||
do_check_eq(profiles[0].timeLastUsed, 0);
|
||||
do_check_eq(profiles[0].timesUsed, 0);
|
||||
do_check_neq(addresses[0].guid, undefined);
|
||||
do_check_neq(addresses[0].timeCreated, undefined);
|
||||
do_check_eq(addresses[0].timeLastModified, addresses[0].timeCreated);
|
||||
do_check_eq(addresses[0].timeLastUsed, 0);
|
||||
do_check_eq(addresses[0].timesUsed, 0);
|
||||
|
||||
Assert.throws(() => profileStorage.add(TEST_PROFILE_WITH_INVALID_FIELD),
|
||||
Assert.throws(() => profileStorage.add(TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./);
|
||||
});
|
||||
|
||||
add_task(function* test_update() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let guid = profiles[1].guid;
|
||||
let timeLastModified = profiles[1].timeLastModified;
|
||||
let addresses = profileStorage.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
let timeLastModified = addresses[1].timeLastModified;
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "update");
|
||||
|
||||
do_check_neq(profiles[1].country, undefined);
|
||||
do_check_neq(addresses[1].country, undefined);
|
||||
|
||||
profileStorage.update(guid, TEST_PROFILE_3);
|
||||
profileStorage.update(guid, TEST_ADDRESS_3);
|
||||
yield onChanged;
|
||||
yield profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profile = profileStorage.get(guid);
|
||||
let address = profileStorage.get(guid);
|
||||
|
||||
do_check_eq(profile.country, undefined);
|
||||
do_check_neq(profile.timeLastModified, timeLastModified);
|
||||
do_check_profile_matches(profile, TEST_PROFILE_3);
|
||||
do_check_eq(address.country, undefined);
|
||||
do_check_neq(address.timeLastModified, timeLastModified);
|
||||
do_check_record_matches(address, TEST_ADDRESS_3);
|
||||
|
||||
Assert.throws(
|
||||
() => profileStorage.update("INVALID_GUID", TEST_PROFILE_3),
|
||||
/No matching profile\./
|
||||
() => profileStorage.update("INVALID_GUID", TEST_ADDRESS_3),
|
||||
/No matching record\./
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => profileStorage.update(guid, TEST_PROFILE_WITH_INVALID_FIELD),
|
||||
() => profileStorage.update(guid, TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_notifyUsed() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let guid = profiles[1].guid;
|
||||
let timeLastUsed = profiles[1].timeLastUsed;
|
||||
let timesUsed = profiles[1].timesUsed;
|
||||
let addresses = profileStorage.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
let timeLastUsed = addresses[1].timeLastUsed;
|
||||
let timesUsed = addresses[1].timesUsed;
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "notifyUsed");
|
||||
|
@ -231,29 +231,29 @@ add_task(function* test_notifyUsed() {
|
|||
profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profile = profileStorage.get(guid);
|
||||
let address = profileStorage.get(guid);
|
||||
|
||||
do_check_eq(profile.timesUsed, timesUsed + 1);
|
||||
do_check_neq(profile.timeLastUsed, timeLastUsed);
|
||||
do_check_eq(address.timesUsed, timesUsed + 1);
|
||||
do_check_neq(address.timeLastUsed, timeLastUsed);
|
||||
|
||||
Assert.throws(() => profileStorage.notifyUsed("INVALID_GUID"),
|
||||
/No matching profile\./);
|
||||
/No matching record\./);
|
||||
});
|
||||
|
||||
add_task(function* test_remove() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
yield prepareTestProfiles(path);
|
||||
yield prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let guid = profiles[1].guid;
|
||||
let addresses = profileStorage.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "remove");
|
||||
|
||||
do_check_eq(profiles.length, 2);
|
||||
do_check_eq(addresses.length, 2);
|
||||
|
||||
profileStorage.remove(guid);
|
||||
yield onChanged;
|
||||
|
@ -262,9 +262,9 @@ add_task(function* test_remove() {
|
|||
profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
profiles = profileStorage.getAll();
|
||||
addresses = profileStorage.getAll();
|
||||
|
||||
do_check_eq(profiles.length, 1);
|
||||
do_check_eq(addresses.length, 1);
|
||||
|
||||
Assert.throws(() => profileStorage.get(guid), /No matching profile\./);
|
||||
Assert.throws(() => profileStorage.get(guid), /No matching record\./);
|
||||
});
|
||||
|
|
|
@ -12,8 +12,8 @@ const TEST_STORE_FILE_NAME = "test-profile.json";
|
|||
const COMPUTE_TESTCASES = [
|
||||
// Empty
|
||||
{
|
||||
description: "Empty profile",
|
||||
profile: {
|
||||
description: "Empty address",
|
||||
address: {
|
||||
},
|
||||
expectedResult: {
|
||||
},
|
||||
|
@ -22,7 +22,7 @@ const COMPUTE_TESTCASES = [
|
|||
// Name
|
||||
{
|
||||
description: "Has split names",
|
||||
profile: {
|
||||
address: {
|
||||
"given-name": "Timothy",
|
||||
"additional-name": "John",
|
||||
"family-name": "Berners-Lee",
|
||||
|
@ -38,7 +38,7 @@ const COMPUTE_TESTCASES = [
|
|||
// Address
|
||||
{
|
||||
description: "\"street-address\" with single line",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "single line",
|
||||
},
|
||||
expectedResult: {
|
||||
|
@ -48,7 +48,7 @@ const COMPUTE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "\"street-address\" with multiple lines",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "line1\nline2\nline3",
|
||||
},
|
||||
expectedResult: {
|
||||
|
@ -60,7 +60,7 @@ const COMPUTE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "\"street-address\" with multiple lines but line2 is omitted",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "line1\n\nline3",
|
||||
},
|
||||
expectedResult: {
|
||||
|
@ -72,7 +72,7 @@ const COMPUTE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "\"street-address\" with 4 lines",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "line1\nline2\nline3\nline4",
|
||||
},
|
||||
expectedResult: {
|
||||
|
@ -87,8 +87,8 @@ const COMPUTE_TESTCASES = [
|
|||
const NORMALIZE_TESTCASES = [
|
||||
// Empty
|
||||
{
|
||||
description: "Empty profile",
|
||||
profile: {
|
||||
description: "Empty address",
|
||||
address: {
|
||||
},
|
||||
expectedResult: {
|
||||
},
|
||||
|
@ -97,7 +97,7 @@ const NORMALIZE_TESTCASES = [
|
|||
// Name
|
||||
{
|
||||
description: "Has \"name\", and the split names are omitted",
|
||||
profile: {
|
||||
address: {
|
||||
"name": "Timothy John Berners-Lee",
|
||||
},
|
||||
expectedResult: {
|
||||
|
@ -108,7 +108,7 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "Has both \"name\" and split names",
|
||||
profile: {
|
||||
address: {
|
||||
"name": "John Doe",
|
||||
"given-name": "Timothy",
|
||||
"additional-name": "John",
|
||||
|
@ -122,7 +122,7 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "Has \"name\", and some of split names are omitted",
|
||||
profile: {
|
||||
address: {
|
||||
"name": "John Doe",
|
||||
"given-name": "Timothy",
|
||||
},
|
||||
|
@ -136,7 +136,7 @@ const NORMALIZE_TESTCASES = [
|
|||
// Address
|
||||
{
|
||||
description: "Has \"address-line1~3\" and \"street-address\" is omitted",
|
||||
profile: {
|
||||
address: {
|
||||
"address-line1": "line1",
|
||||
"address-line2": "line2",
|
||||
"address-line3": "line3",
|
||||
|
@ -147,7 +147,7 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "Has both \"address-line1~3\" and \"street-address\"",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "street address",
|
||||
"address-line1": "line1",
|
||||
"address-line2": "line2",
|
||||
|
@ -159,7 +159,7 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "Has \"address-line2~3\" and single-line \"street-address\"",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "street address",
|
||||
"address-line2": "line2",
|
||||
"address-line3": "line3",
|
||||
|
@ -170,7 +170,7 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
{
|
||||
description: "Has \"address-line2~3\" and multiple-line \"street-address\"",
|
||||
profile: {
|
||||
address: {
|
||||
"street-address": "street address\nstreet address line 2",
|
||||
"address-line2": "line2",
|
||||
"address-line3": "line3",
|
||||
|
@ -181,9 +181,9 @@ const NORMALIZE_TESTCASES = [
|
|||
},
|
||||
];
|
||||
|
||||
let do_check_profile_matches = (expectedProfile, profile) => {
|
||||
for (let key in expectedProfile) {
|
||||
do_check_eq(expectedProfile[key], profile[key] || "");
|
||||
let do_check_record_matches = (expectedRecord, record) => {
|
||||
for (let key in expectedRecord) {
|
||||
do_check_eq(expectedRecord[key], record[key] || "");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -193,36 +193,36 @@ add_task(function* test_computeFields() {
|
|||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
COMPUTE_TESTCASES.forEach(testcase => profileStorage.add(testcase.profile));
|
||||
COMPUTE_TESTCASES.forEach(testcase => profileStorage.add(testcase.address));
|
||||
yield profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let addresses = profileStorage.getAll();
|
||||
|
||||
for (let i in profiles) {
|
||||
for (let i in addresses) {
|
||||
do_print("Verify testcase: " + COMPUTE_TESTCASES[i].description);
|
||||
do_check_profile_matches(COMPUTE_TESTCASES[i].expectedResult, profiles[i]);
|
||||
do_check_record_matches(COMPUTE_TESTCASES[i].expectedResult, addresses[i]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_normalizeProfile() {
|
||||
add_task(function* test_normalizeFields() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
NORMALIZE_TESTCASES.forEach(testcase => profileStorage.add(testcase.profile));
|
||||
NORMALIZE_TESTCASES.forEach(testcase => profileStorage.add(testcase.address));
|
||||
yield profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
yield profileStorage.initialize();
|
||||
|
||||
let profiles = profileStorage.getAll();
|
||||
let addresses = profileStorage.getAll();
|
||||
|
||||
for (let i in profiles) {
|
||||
for (let i in addresses) {
|
||||
do_print("Verify testcase: " + NORMALIZE_TESTCASES[i].description);
|
||||
do_check_profile_matches(NORMALIZE_TESTCASES[i].expectedResult, profiles[i]);
|
||||
do_check_record_matches(NORMALIZE_TESTCASES[i].expectedResult, addresses[i]);
|
||||
}
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче