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:
Luke Chang 2017-05-08 10:43:37 +08:00
Родитель 43998dbb90
Коммит 0538cf7020
13 изменённых файлов: 435 добавлений и 447 удалений

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

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