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; return;
} }
this._getProfiles({info, searchString}).then((profiles) => { this._getAddresses({info, searchString}).then((addresses) => {
if (this.forceStop) { if (this.forceStop) {
return; return;
} }
@ -115,7 +115,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
let result = new ProfileAutoCompleteResult(searchString, let result = new ProfileAutoCompleteResult(searchString,
info.fieldName, info.fieldName,
allFieldNames, allFieldNames,
profiles, addresses,
{}); {});
listener.onSearchResult(this, result); 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 * @private
* @param {Object} data * @param {Object} data
* Parameters for querying the corresponding result. * Parameters for querying the corresponding result.
* @param {string} data.searchString * @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 * @param {string} data.info
* The input autocomplete property's information. * The input autocomplete property's information.
* @returns {Promise} * @returns {Promise}
* Promise that resolves when profiles returned from parent process. * Promise that resolves when addresses returned from parent process.
*/ */
_getProfiles(data) { _getAddresses(data) {
this.log.debug("_getProfiles with data:", data); this.log.debug("_getAddresses with data:", data);
return new Promise((resolve) => { return new Promise((resolve) => {
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) { Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult); Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
resolve(result.data); resolve(result.data);
}); });
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", data); Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", data);
}); });
}, },
}; };

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

@ -76,9 +76,9 @@ FormAutofillParent.prototype = {
this._profileStore.initialize(); this._profileStore.initialize();
Services.obs.addObserver(this, "advanced-pane-loaded"); Services.obs.addObserver(this, "advanced-pane-loaded");
Services.ppmm.addMessageListener("FormAutofill:GetProfiles", this); Services.ppmm.addMessageListener("FormAutofill:GetAddresses", this);
Services.ppmm.addMessageListener("FormAutofill:SaveProfile", this); Services.ppmm.addMessageListener("FormAutofill:SaveAddress", this);
Services.ppmm.addMessageListener("FormAutofill:RemoveProfiles", this); Services.ppmm.addMessageListener("FormAutofill:RemoveAddresses", this);
// Observing the pref and storage changes // Observing the pref and storage changes
Services.prefs.addObserver(ENABLED_PREF, this); Services.prefs.addObserver(ENABLED_PREF, this);
@ -182,19 +182,19 @@ FormAutofillParent.prototype = {
*/ */
receiveMessage({name, data, target}) { receiveMessage({name, data, target}) {
switch (name) { switch (name) {
case "FormAutofill:GetProfiles": { case "FormAutofill:GetAddresses": {
this._getProfiles(data, target); this._getAddresses(data, target);
break; break;
} }
case "FormAutofill:SaveProfile": { case "FormAutofill:SaveAddress": {
if (data.guid) { if (data.guid) {
this.getProfileStore().update(data.guid, data.profile); this.getProfileStore().update(data.guid, data.address);
} else { } else {
this.getProfileStore().add(data.profile); this.getProfileStore().add(data.address);
} }
break; break;
} }
case "FormAutofill:RemoveProfiles": { case "FormAutofill:RemoveAddresses": {
data.guids.forEach(guid => this.getProfileStore().remove(guid)); data.guids.forEach(guid => this.getProfileStore().remove(guid));
break; break;
} }
@ -223,34 +223,35 @@ FormAutofillParent.prototype = {
this._profileStore = null; this._profileStore = null;
} }
Services.ppmm.removeMessageListener("FormAutofill:GetProfiles", this); Services.ppmm.removeMessageListener("FormAutofill:GetAddresses", this);
Services.ppmm.removeMessageListener("FormAutofill:SaveProfile", this); Services.ppmm.removeMessageListener("FormAutofill:SaveAddress", this);
Services.ppmm.removeMessageListener("FormAutofill:RemoveProfiles", this); Services.ppmm.removeMessageListener("FormAutofill:RemoveAddresses", this);
Services.obs.removeObserver(this, "advanced-pane-loaded"); Services.obs.removeObserver(this, "advanced-pane-loaded");
Services.prefs.removeObserver(ENABLED_PREF, this); 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 * @private
* @param {string} data.searchString * @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 * @param {string} data.info
* The input autocomplete property's information. * The input autocomplete property's information.
* @param {nsIFrameMessageManager} target * @param {nsIFrameMessageManager} target
* Content's message manager. * Content's message manager.
*/ */
_getProfiles({searchString, info}, target) { _getAddresses({searchString, info}, target) {
let profiles = []; let addresses = [];
if (info && info.fieldName) { if (info && info.fieldName) {
profiles = this._profileStore.getByFilter({searchString, info}); addresses = this._profileStore.getByFilter({searchString, info});
} else { } else {
profiles = this._profileStore.getAll(); addresses = this._profileStore.getAll();
} }
target.sendAsyncMessage("FormAutofill:Profiles", profiles); target.sendAsyncMessage("FormAutofill:Addresses", addresses);
}, },
_updateSavedFieldNames() { _updateSavedFieldNames() {
@ -260,9 +261,9 @@ FormAutofillParent.prototype = {
Services.ppmm.initialProcessData.autofillSavedFieldNames.clear(); Services.ppmm.initialProcessData.autofillSavedFieldNames.clear();
} }
this._profileStore.getAll().forEach((profile) => { this._profileStore.getAll().forEach((address) => {
Object.keys(profile).forEach((fieldName) => { Object.keys(address).forEach((fieldName) => {
if (!profile[fieldName]) { if (!address[fieldName]) {
return; return;
} }
Services.ppmm.initialProcessData.autofillSavedFieldNames.add(fieldName); Services.ppmm.initialProcessData.autofillSavedFieldNames.add(fieldName);

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

@ -11,11 +11,11 @@
* *
* { * {
* version: 1, * version: 1,
* profiles: [ * addresses: [
* { * {
* guid, // 12 character... * guid, // 12 characters
* *
* // profile * // address fields
* given-name, * given-name,
* additional-name, * additional-name,
* family-name, * family-name,
@ -30,6 +30,7 @@
* *
* // computed fields (These fields are not stored in the file as they are * // computed fields (These fields are not stored in the file as they are
* // generated at runtime.) * // generated at runtime.)
* name,
* address-line1, * address-line1,
* address-line2, * address-line2,
* address-line3, * address-line3,
@ -87,26 +88,12 @@ const VALID_FIELDS = [
"email", "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) { function ProfileStorage(path) {
this._path = path; this._path = path;
} }
ProfileStorage.prototype = { ProfileStorage.prototype = {
// These fields are defined internally for each profile. // These fields are defined internally for each record.
INTERNAL_FIELDS: INTERNAL_FIELDS:
["guid", "timeCreated", "timeLastUsed", "timeLastModified", "timesUsed"], ["guid", "timeCreated", "timeLastUsed", "timeLastModified", "timesUsed"],
/** /**
@ -125,160 +112,160 @@ ProfileStorage.prototype = {
}, },
/** /**
* Adds a new profile. * Adds a new address.
* *
* @param {Profile} profile * @param {Address} address
* The new profile for saving. * The new address for saving.
*/ */
add(profile) { add(address) {
log.debug("add:", profile); log.debug("add:", address);
this._store.ensureDataReady(); this._store.ensureDataReady();
let profileToSave = this._clone(profile); let addressToSave = this._clone(address);
this._normalizeProfile(profileToSave); this._normalizeAddress(addressToSave);
profileToSave.guid = gUUIDGenerator.generateUUID().toString() addressToSave.guid = gUUIDGenerator.generateUUID().toString()
.replace(/[{}-]/g, "").substring(0, 12); .replace(/[{}-]/g, "").substring(0, 12);
// Metadata // Metadata
let now = Date.now(); let now = Date.now();
profileToSave.timeCreated = now; addressToSave.timeCreated = now;
profileToSave.timeLastModified = now; addressToSave.timeLastModified = now;
profileToSave.timeLastUsed = 0; addressToSave.timeLastUsed = 0;
profileToSave.timesUsed = 0; addressToSave.timesUsed = 0;
this._store.data.profiles.push(profileToSave); this._store.data.addresses.push(addressToSave);
this._store.saveSoon(); this._store.saveSoon();
Services.obs.notifyObservers(null, "formautofill-storage-changed", "add"); Services.obs.notifyObservers(null, "formautofill-storage-changed", "add");
}, },
/** /**
* Update the specified profile. * Update the specified address.
* *
* @param {string} guid * @param {string} guid
* Indicates which profile to update. * Indicates which address to update.
* @param {Profile} profile * @param {Address} address
* The new profile used to overwrite the old one. * The new address used to overwrite the old one.
*/ */
update(guid, profile) { update(guid, address) {
log.debug("update:", guid, profile); log.debug("update:", guid, address);
this._store.ensureDataReady(); this._store.ensureDataReady();
let profileFound = this._findByGUID(guid); let addressFound = this._findByGUID(guid);
if (!profileFound) { if (!addressFound) {
throw new Error("No matching profile."); throw new Error("No matching record.");
} }
let profileToUpdate = this._clone(profile); let addressToUpdate = this._clone(address);
this._normalizeProfile(profileToUpdate); this._normalizeAddress(addressToUpdate);
for (let field of VALID_FIELDS) { for (let field of VALID_FIELDS) {
if (profileToUpdate[field] !== undefined) { if (addressToUpdate[field] !== undefined) {
profileFound[field] = profileToUpdate[field]; addressFound[field] = addressToUpdate[field];
} else { } else {
delete profileFound[field]; delete addressFound[field];
} }
} }
profileFound.timeLastModified = Date.now(); addressFound.timeLastModified = Date.now();
this._store.saveSoon(); this._store.saveSoon();
Services.obs.notifyObservers(null, "formautofill-storage-changed", "update"); 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. * the metadata accordingly.
* *
* @param {string} guid * @param {string} guid
* Indicates which profile to be notified. * Indicates which address to be notified.
*/ */
notifyUsed(guid) { notifyUsed(guid) {
this._store.ensureDataReady(); this._store.ensureDataReady();
let profileFound = this._findByGUID(guid); let addressFound = this._findByGUID(guid);
if (!profileFound) { if (!addressFound) {
throw new Error("No matching profile."); throw new Error("No matching record.");
} }
profileFound.timesUsed++; addressFound.timesUsed++;
profileFound.timeLastUsed = Date.now(); addressFound.timeLastUsed = Date.now();
this._store.saveSoon(); this._store.saveSoon();
Services.obs.notifyObservers(null, "formautofill-storage-changed", "notifyUsed"); 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 * @param {string} guid
* Indicates which profile to remove. * Indicates which address to remove.
*/ */
remove(guid) { remove(guid) {
log.debug("remove:", guid); log.debug("remove:", guid);
this._store.ensureDataReady(); this._store.ensureDataReady();
this._store.data.profiles = this._store.data.addresses =
this._store.data.profiles.filter(profile => profile.guid != guid); this._store.data.addresses.filter(address => address.guid != guid);
this._store.saveSoon(); this._store.saveSoon();
Services.obs.notifyObservers(null, "formautofill-storage-changed", "remove"); 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 * @param {string} guid
* Indicates which profile to retrieve. * Indicates which address to retrieve.
* @returns {Profile} * @returns {Address}
* A clone of the profile. * A clone of the address.
*/ */
get(guid) { get(guid) {
log.debug("get:", guid); log.debug("get:", guid);
this._store.ensureDataReady(); this._store.ensureDataReady();
let profileFound = this._findByGUID(guid); let addressFound = this._findByGUID(guid);
if (!profileFound) { if (!addressFound) {
throw new Error("No matching profile."); throw new Error("No matching record.");
} }
// Profile is cloned to avoid accidental modifications from outside. // The record is cloned to avoid accidental modifications from outside.
let clonedProfile = this._clone(profileFound); let clonedAddress = this._clone(addressFound);
this._computeFields(clonedProfile); this._computeFields(clonedAddress);
return clonedProfile; return clonedAddress;
}, },
/** /**
* Returns all profiles. * Returns all addresses.
* *
* @returns {Array.<Profile>} * @returns {Array.<Address>}
* An array containing clones of all profiles. * An array containing clones of all addresses.
*/ */
getAll() { getAll() {
log.debug("getAll"); log.debug("getAll");
this._store.ensureDataReady(); this._store.ensureDataReady();
// Profiles are cloned to avoid accidental modifications from outside. // Records are cloned to avoid accidental modifications from outside.
let clonedProfiles = this._store.data.profiles.map(this._clone); let clonedAddresses = this._store.data.addresses.map(this._clone);
clonedProfiles.forEach(this._computeFields); clonedAddresses.forEach(this._computeFields);
return clonedProfiles; 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>} * @returns {Array.<Address>}
* An array containing clones of matched profiles. * An array containing clones of matched addresses.
*/ */
getByFilter({info, searchString}) { getByFilter({info, searchString}) {
log.debug("getByFilter:", info, searchString); log.debug("getByFilter:", info, searchString);
let lcSearchString = searchString.toLowerCase(); 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. // Return true if string is not provided and field exists.
// TODO: We'll need to check if the address is for billing or shipping. // TODO: We'll need to check if the address is for billing or shipping.
// (Bug 1358941) // (Bug 1358941)
let name = profile[info.fieldName]; let name = address[info.fieldName];
if (!searchString) { if (!searchString) {
return !!name; return !!name;
@ -291,88 +278,88 @@ ProfileStorage.prototype = {
return result; return result;
}, },
_clone(profile) { _clone(record) {
return Object.assign({}, profile); return Object.assign({}, record);
}, },
_findByGUID(guid) { _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 // Compute name
profile.name = FormAutofillNameUtils.joinNameParts({ address.name = FormAutofillNameUtils.joinNameParts({
given: profile["given-name"], given: address["given-name"],
middle: profile["additional-name"], middle: address["additional-name"],
family: profile["family-name"], family: address["family-name"],
}); });
// Compute address // Compute address
if (profile["street-address"]) { if (address["street-address"]) {
let streetAddress = profile["street-address"].split("\n"); let streetAddress = address["street-address"].split("\n");
// TODO: we should prevent the dataloss by concatenating the rest of lines // TODO: we should prevent the dataloss by concatenating the rest of lines
// with a locale-specific character in the future (bug 1360114). // with a locale-specific character in the future (bug 1360114).
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
if (streetAddress[i]) { if (streetAddress[i]) {
profile["address-line" + (i + 1)] = streetAddress[i]; address["address-line" + (i + 1)] = streetAddress[i];
} }
} }
} }
}, },
_normalizeAddress(profile) { _normalizeAddressLines(address) {
if (profile["address-line1"] || profile["address-line2"] || if (address["address-line1"] || address["address-line2"] ||
profile["address-line3"]) { address["address-line3"]) {
// Treat "street-address" as "address-line1" if it contains only one line // Treat "street-address" as "address-line1" if it contains only one line
// and "address-line1" is omitted. // and "address-line1" is omitted.
if (!profile["address-line1"] && profile["street-address"] && if (!address["address-line1"] && address["street-address"] &&
!profile["street-address"].includes("\n")) { !address["street-address"].includes("\n")) {
profile["address-line1"] = profile["street-address"]; address["address-line1"] = address["street-address"];
delete profile["street-address"]; delete address["street-address"];
} }
// Remove "address-line*" but keep the values. // Remove "address-line*" but keep the values.
let addressLines = [1, 2, 3].map(i => { let addressLines = [1, 2, 3].map(i => {
let value = profile["address-line" + i]; let value = address["address-line" + i];
delete profile["address-line" + i]; delete address["address-line" + i];
return value; return value;
}); });
// Concatenate "address-line*" if "street-address" is omitted. // Concatenate "address-line*" if "street-address" is omitted.
if (!profile["street-address"]) { if (!address["street-address"]) {
profile["street-address"] = addressLines.join("\n"); address["street-address"] = addressLines.join("\n");
} }
} }
}, },
_normalizeName(profile) { _normalizeName(address) {
if (!profile.name) { if (!address.name) {
return; return;
} }
let nameParts = FormAutofillNameUtils.splitName(profile.name); let nameParts = FormAutofillNameUtils.splitName(address.name);
if (!profile["given-name"] && nameParts.given) { if (!address["given-name"] && nameParts.given) {
profile["given-name"] = nameParts.given; address["given-name"] = nameParts.given;
} }
if (!profile["additional-name"] && nameParts.middle) { if (!address["additional-name"] && nameParts.middle) {
profile["additional-name"] = nameParts.middle; address["additional-name"] = nameParts.middle;
} }
if (!profile["family-name"] && nameParts.family) { if (!address["family-name"] && nameParts.family) {
profile["family-name"] = nameParts.family; address["family-name"] = nameParts.family;
} }
delete profile.name; delete address.name;
}, },
_normalizeProfile(profile) { _normalizeAddress(address) {
this._normalizeName(profile); this._normalizeName(address);
this._normalizeAddress(profile); this._normalizeAddressLines(address);
for (let key in profile) { for (let key in address) {
if (!VALID_FIELDS.includes(key)) { if (!VALID_FIELDS.includes(key)) {
throw new Error(`"${key}" is not a valid field.`); throw new Error(`"${key}" is not a valid field.`);
} }
if (typeof profile[key] !== "string" && if (typeof address[key] !== "string" &&
typeof profile[key] !== "number") { typeof address[key] !== "number") {
throw new Error(`"${key}" contains invalid data type.`); throw new Error(`"${key}" contains invalid data type.`);
} }
} }
@ -380,8 +367,8 @@ ProfileStorage.prototype = {
_dataPostProcessor(data) { _dataPostProcessor(data) {
data.version = SCHEMA_VERSION; data.version = SCHEMA_VERSION;
if (!data.profiles) { if (!data.addresses) {
data.profiles = MOCK_MODE ? MOCK_STORAGE : []; data.addresses = [];
} }
return data; 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://gre/modules/Services.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm"); Cu.import("resource://formautofill/FormAutofillUtils.jsm");
function EditDialog(profile) { function EditDialog(address) {
this._profile = profile; this._address = address;
window.addEventListener("DOMContentLoaded", this, {once: true}); 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 * @param {object} data
* { * {
* {string} guid [optional] * {string} guid [optional]
* {object} profile * {object} address
* } * }
*/ */
saveProfile(data) { saveAddress(data) {
Services.cpmm.sendAsyncMessage("FormAutofill:SaveProfile", data); Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", data);
}, },
/** /**
* Fill the form with a profile object. * Fill the form with an address object.
* @param {object} profile * @param {object} address
*/ */
loadInitialValues(profile) { loadInitialValues(address) {
for (let field in profile) { for (let field in address) {
let input = document.getElementById(field); let input = document.getElementById(field);
if (input) { if (input) {
input.value = profile[field]; input.value = address[field];
} }
} }
}, },
@ -53,7 +53,7 @@ EditDialog.prototype = {
* Get inputs from the form. * Get inputs from the form.
* @returns {object} * @returns {object}
*/ */
buildProfileObject() { buildAddressObject() {
return Array.from(document.forms[0].elements).reduce((obj, input) => { return Array.from(document.forms[0].elements).reduce((obj, input) => {
if (input.value) { if (input.value) {
obj[input.id] = input.value; obj[input.id] = input.value;
@ -71,8 +71,8 @@ EditDialog.prototype = {
switch (event.type) { switch (event.type) {
case "DOMContentLoaded": { case "DOMContentLoaded": {
this.init(); this.init();
if (this._profile) { if (this._address) {
this.loadInitialValues(this._profile); this.loadInitialValues(this._address);
} }
break; break;
} }
@ -83,7 +83,7 @@ EditDialog.prototype = {
case "input": { case "input": {
// Toggle disabled attribute on the save button based on // Toggle disabled attribute on the save button based on
// whether the form is filled or empty. // 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); this.refs.save.setAttribute("disabled", true);
} else { } else {
this.refs.save.removeAttribute("disabled"); this.refs.save.removeAttribute("disabled");
@ -104,14 +104,14 @@ EditDialog.prototype = {
window.close(); window.close();
} }
if (event.target == this.refs.save) { if (event.target == this.refs.save) {
if (this._profile) { if (this._address) {
this.saveProfile({ this.saveAddress({
guid: this._profile.guid, guid: this._address.guid,
profile: this.buildProfileObject(), address: this.buildAddressObject(),
}); });
} else { } else {
this.saveProfile({ this.saveAddress({
profile: this.buildProfileObject(), address: this.buildAddressObject(),
}); });
} }
this.detachEventListeners(); this.detachEventListeners();

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

@ -25,23 +25,23 @@ ManageProfileDialog.prototype = {
/** /**
* Count the number of "formautofill-storage-changed" events epected to * Count the number of "formautofill-storage-changed" events epected to
* receive to prevent repeatedly loading profiles. * receive to prevent repeatedly loading addresses.
* @type {number} * @type {number}
*/ */
_pendingChangeCount: 0, _pendingChangeCount: 0,
/** /**
* Get the selected options on the profiles element. * Get the selected options on the addresses element.
* *
* @returns {array<DOMElement>} * @returns {array<DOMElement>}
*/ */
get _selectedOptions() { get _selectedOptions() {
return Array.from(this._elements.profiles.selectedOptions); return Array.from(this._elements.addresses.selectedOptions);
}, },
init() { init() {
this._elements = { this._elements = {
profiles: document.getElementById("profiles"), addresses: document.getElementById("profiles"),
controlsContainer: document.getElementById("controls-container"), controlsContainer: document.getElementById("controls-container"),
remove: document.getElementById("remove"), remove: document.getElementById("remove"),
add: document.getElementById("add"), add: document.getElementById("add"),
@ -57,84 +57,84 @@ ManageProfileDialog.prototype = {
}, },
/** /**
* Load profiles and render them. * Load addresses and render them.
* *
* @returns {promise} * @returns {promise}
*/ */
loadProfiles() { loadAddresses() {
return this.getProfiles().then(profiles => { return this.getAddresses().then(addresses => {
log.debug("profiles:", profiles); log.debug("addresses:", addresses);
// Sort by last modified time starting with most recent // Sort by last modified time starting with most recent
profiles.sort((a, b) => b.timeLastModified - a.timeLastModified); addresses.sort((a, b) => b.timeLastModified - a.timeLastModified);
this.renderProfileElements(profiles); this.renderAddressElements(addresses);
this.updateButtonsStates(this._selectedOptions.length); this.updateButtonsStates(this._selectedOptions.length);
}); });
}, },
/** /**
* Get profiles from storage. * Get addresses from storage.
* *
* @returns {promise} * @returns {promise}
*/ */
getProfiles() { getAddresses() {
return new Promise(resolve => { return new Promise(resolve => {
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) { Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult); Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
resolve(result.data); 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. * they still exist.
* *
* @param {array<object>} profiles * @param {array<object>} addresses
*/ */
renderProfileElements(profiles) { renderAddressElements(addresses) {
let selectedGuids = this._selectedOptions.map(option => option.value); let selectedGuids = this._selectedOptions.map(option => option.value);
this.clearProfileElements(); this.clearAddressElements();
for (let profile of profiles) { for (let address of addresses) {
let option = new Option(this.getProfileLabel(profile), let option = new Option(this.getAddressLabel(address),
profile.guid, address.guid,
false, false,
selectedGuids.includes(profile.guid)); selectedGuids.includes(address.guid));
option.profile = profile; option.address = address;
this._elements.profiles.appendChild(option); this._elements.addresses.appendChild(option);
} }
}, },
/** /**
* Remove all existing profile elements. * Remove all existing address elements.
*/ */
clearProfileElements() { clearAddressElements() {
let parent = this._elements.profiles; let parent = this._elements.addresses;
while (parent.lastChild) { while (parent.lastChild) {
parent.removeChild(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 * Keep track of the number of "formautofill-storage-changed" events to
* ignore before loading profiles. * ignore before loading addresses.
* *
* @param {array<string>} guids * @param {array<string>} guids
*/ */
removeProfiles(guids) { removeAddresses(guids) {
this._pendingChangeCount += guids.length - 1; 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. * information, separated by a comma.
* *
* @param {object} profile * @param {object} address
* @returns {string} * @returns {string}
*/ */
getProfileLabel(profile) { getAddressLabel(address) {
// TODO: Implement a smarter way for deciding what to display // TODO: Implement a smarter way for deciding what to display
// as option text. Possibly improve the algorithm in // as option text. Possibly improve the algorithm in
// ProfileAutoCompleteResult.jsm and reuse it here. // ProfileAutoCompleteResult.jsm and reuse it here.
@ -152,7 +152,7 @@ ManageProfileDialog.prototype = {
let parts = []; let parts = [];
for (const fieldName of fieldOrder) { for (const fieldName of fieldOrder) {
let string = profile[fieldName]; let string = address[fieldName];
if (string) { if (string) {
parts.push(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, window.openDialog(EDIT_PROFILE_URL, null,
"chrome,centerscreen,modal,width=600,height=450", "chrome,centerscreen,modal,width=600,height=450",
profile); address);
}, },
/** /**
@ -203,7 +203,7 @@ ManageProfileDialog.prototype = {
switch (event.type) { switch (event.type) {
case "DOMContentLoaded": { case "DOMContentLoaded": {
this.init(); this.init();
this.loadProfiles(); this.loadAddresses();
break; break;
} }
case "click": { case "click": {
@ -228,11 +228,11 @@ ManageProfileDialog.prototype = {
*/ */
handleClick(event) { handleClick(event) {
if (event.target == this._elements.remove) { 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) { } else if (event.target == this._elements.add) {
this.openEditDialog(); this.openEditDialog();
} else if (event.target == this._elements.edit) { } 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; this._pendingChangeCount -= 1;
return; return;
} }
this.loadProfiles(); this.loadAddresses();
} }
} }
}, },
@ -253,7 +253,7 @@ ManageProfileDialog.prototype = {
*/ */
attachEventListeners() { attachEventListeners() {
window.addEventListener("unload", this, {once: true}); window.addEventListener("unload", this, {once: true});
this._elements.profiles.addEventListener("change", this); this._elements.addresses.addEventListener("change", this);
this._elements.controlsContainer.addEventListener("click", this); this._elements.controlsContainer.addEventListener("click", this);
Services.obs.addObserver(this, "formautofill-storage-changed"); Services.obs.addObserver(this, "formautofill-storage-changed");
}, },
@ -262,7 +262,7 @@ ManageProfileDialog.prototype = {
* Remove event listener * Remove event listener
*/ */
detachEventListeners() { detachEventListeners() {
this._elements.profiles.removeEventListener("change", this); this._elements.addresses.removeEventListener("change", this);
this._elements.controlsContainer.removeEventListener("click", this); this._elements.controlsContainer.removeEventListener("click", this);
Services.obs.removeObserver(this, "formautofill-storage-changed"); Services.obs.removeObserver(this, "formautofill-storage-changed");
}, },

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

@ -1,9 +1,9 @@
"use strict"; "use strict";
registerCleanupFunction(function* () { registerCleanupFunction(function* () {
let profiles = yield getProfiles(); let addresses = yield getAddresses();
if (profiles.length) { if (addresses.length) {
yield removeProfiles(profiles.map(profile => profile.guid)); 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 => { yield new Promise(resolve => {
let win = window.openDialog(EDIT_PROFILE_DIALOG_URL, null, null, null); let win = window.openDialog(EDIT_PROFILE_DIALOG_URL, null, null, null);
win.addEventListener("load", () => { win.addEventListener("load", () => {
@ -29,46 +29,46 @@ add_task(function* test_saveProfile() {
resolve(); resolve();
}, {once: true}); }, {once: true});
EventUtils.synthesizeKey("VK_TAB", {}, win); 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("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("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("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_PROFILE_1.organization, {}, win); EventUtils.synthesizeKey(TEST_ADDRESS_1.organization, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, 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("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("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("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("VK_TAB", {}, win);
EventUtils.synthesizeKey(TEST_PROFILE_1.country, {}, win); EventUtils.synthesizeKey(TEST_ADDRESS_1.country, {}, win);
EventUtils.synthesizeKey("VK_TAB", {}, 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("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);
EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win);
info("saving profile"); info("saving profile");
EventUtils.synthesizeKey("VK_RETURN", {}, win); EventUtils.synthesizeKey("VK_RETURN", {}, win);
}, {once: true}); }, {once: true});
}); });
let profiles = yield getProfiles(); let addresses = yield getAddresses();
is(profiles.length, 1, "only one profile is in storage"); is(addresses.length, 1, "only one address is in storage");
is(Object.keys(TEST_PROFILE_1).length, 11, "Sanity check number of properties"); is(Object.keys(TEST_ADDRESS_1).length, 11, "Sanity check number of properties");
for (let [fieldName, fieldValue] of Object.entries(TEST_PROFILE_1)) { for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_1)) {
is(profiles[0][fieldName], fieldValue, "check " + fieldName); is(addresses[0][fieldName], fieldValue, "check " + fieldName);
} }
}); });
add_task(function* test_editProfile() { add_task(function* test_editProfile() {
let profiles = yield getProfiles(); let addresses = yield getAddresses();
yield new Promise(resolve => { 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("load", () => {
win.addEventListener("unload", () => { win.addEventListener("unload", () => {
ok(true, "Edit profile dialog is closed"); ok(true, "Edit profile dialog is closed");
@ -79,12 +79,12 @@ add_task(function* test_editProfile() {
win.document.querySelector("#save").click(); win.document.querySelector("#save").click();
}, {once: true}); }, {once: true});
}); });
profiles = yield getProfiles(); addresses = yield getAddresses();
is(profiles.length, 1, "only one profile is in storage"); is(addresses.length, 1, "only one address is in storage");
is(profiles[0]["given-name"], TEST_PROFILE_1["given-name"] + "test", "given-name changed"); is(addresses[0]["given-name"], TEST_ADDRESS_1["given-name"] + "test", "given-name changed");
yield removeProfiles([profiles[0].guid]); yield removeAddresses([addresses[0].guid]);
profiles = yield getProfiles(); addresses = yield getAddresses();
is(profiles.length, 0, "Profile storage is empty"); is(addresses.length, 0, "Address storage is empty");
}); });

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

@ -1,16 +1,16 @@
"use strict"; "use strict";
const TEST_SELECTORS = { const TEST_SELECTORS = {
selProfiles: "#profiles", selAddresses: "#profiles",
btnRemove: "#remove", btnRemove: "#remove",
btnAdd: "#add", btnAdd: "#add",
btnEdit: "#edit", btnEdit: "#edit",
}; };
function waitForProfiles() { function waitForAddresses() {
return new Promise(resolve => { return new Promise(resolve => {
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) { Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult); Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
// Wait for the next tick for elements to get rendered. // Wait for the next tick for elements to get rendered.
SimpleTest.executeSoon(resolve.bind(null, result.data)); SimpleTest.executeSoon(resolve.bind(null, result.data));
}); });
@ -18,21 +18,21 @@ function waitForProfiles() {
} }
registerCleanupFunction(function* () { registerCleanupFunction(function* () {
let profiles = yield getProfiles(); let addresses = yield getAddresses();
if (profiles.length) { if (addresses.length) {
yield removeProfiles(profiles.map(profile => profile.guid)); yield removeAddresses(addresses.map(address => address.guid));
} }
}); });
add_task(function* test_manageProfilesInitialState() { add_task(function* test_manageProfilesInitialState() {
yield BrowserTestUtils.withNewTab({gBrowser, url: MANAGE_PROFILES_DIALOG_URL}, function* (browser) { yield BrowserTestUtils.withNewTab({gBrowser, url: MANAGE_PROFILES_DIALOG_URL}, function* (browser) {
yield ContentTask.spawn(browser, TEST_SELECTORS, (args) => { 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 btnRemove = content.document.querySelector(args.btnRemove);
let btnEdit = content.document.querySelector(args.btnEdit); let btnEdit = content.document.querySelector(args.btnEdit);
let btnAdd = content.document.querySelector(args.btnAdd); 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(btnAdd.disabled, false, "Add button enabled");
is(btnRemove.disabled, true, "Remove button disabled"); is(btnRemove.disabled, true, "Remove button disabled");
is(btnEdit.disabled, true, "Edit button disabled"); is(btnEdit.disabled, true, "Edit button disabled");
@ -41,50 +41,50 @@ add_task(function* test_manageProfilesInitialState() {
}); });
add_task(function* test_removingSingleAndMultipleProfiles() { add_task(function* test_removingSingleAndMultipleProfiles() {
yield saveProfile(TEST_PROFILE_1); yield saveAddress(TEST_ADDRESS_1);
yield saveProfile(TEST_PROFILE_2); yield saveAddress(TEST_ADDRESS_2);
yield saveProfile(TEST_PROFILE_3); yield saveAddress(TEST_ADDRESS_3);
let win = window.openDialog(MANAGE_PROFILES_DIALOG_URL); 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 btnRemove = win.document.querySelector(TEST_SELECTORS.btnRemove);
let btnEdit = win.document.querySelector(TEST_SELECTORS.btnEdit); 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(btnRemove.disabled, false, "Remove button enabled");
is(btnEdit.disabled, false, "Edit button enabled"); is(btnEdit.disabled, false, "Edit button enabled");
EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win); EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win);
yield waitForProfiles(); yield waitForAddresses();
is(selProfiles.length, 2, "Two profiles left"); is(selAddresses.length, 2, "Two addresses left");
EventUtils.synthesizeMouseAtCenter(selProfiles.children[0], {}, win); EventUtils.synthesizeMouseAtCenter(selAddresses.children[0], {}, win);
EventUtils.synthesizeMouseAtCenter(selProfiles.children[1], EventUtils.synthesizeMouseAtCenter(selAddresses.children[1],
{shiftKey: true}, win); {shiftKey: true}, win);
is(btnEdit.disabled, true, "Edit button disabled when multi-select"); is(btnEdit.disabled, true, "Edit button disabled when multi-select");
EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win); EventUtils.synthesizeMouseAtCenter(btnRemove, {}, win);
yield waitForProfiles(); yield waitForAddresses();
is(selProfiles.length, 0, "All profiles are removed"); is(selAddresses.length, 0, "All addresses are removed");
win.close(); win.close();
}); });
add_task(function* test_profilesDialogWatchesStorageChanges() { add_task(function* test_profilesDialogWatchesStorageChanges() {
let win = window.openDialog(MANAGE_PROFILES_DIALOG_URL); 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); yield saveAddress(TEST_ADDRESS_1);
let profiles = yield waitForProfiles(); let addresses = yield waitForAddresses();
is(selProfiles.length, 1, "One profile is shown"); is(selAddresses.length, 1, "One address is shown");
yield removeProfiles([profiles[0].guid]); yield removeAddresses([addresses[0].guid]);
yield waitForProfiles(); yield waitForAddresses();
is(selProfiles.length, 0, "Profile is removed"); is(selAddresses.length, 0, "Address is removed");
win.close(); win.close();
}); });

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

@ -1,13 +1,13 @@
/* exported MANAGE_PROFILES_DIALOG_URL, EDIT_PROFILE_DIALOG_URL, /* exported MANAGE_PROFILES_DIALOG_URL, EDIT_PROFILE_DIALOG_URL,
TEST_PROFILE_1, TEST_PROFILE_2, TEST_PROFILE_3, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3,
getProfiles, saveProfile, removeProfiles */ getAddresses, saveAddress, removeAddresses */
"use strict"; "use strict";
const MANAGE_PROFILES_DIALOG_URL = "chrome://formautofill/content/manageProfiles.xhtml"; const MANAGE_PROFILES_DIALOG_URL = "chrome://formautofill/content/manageProfiles.xhtml";
const EDIT_PROFILE_DIALOG_URL = "chrome://formautofill/content/editProfile.xhtml"; const EDIT_PROFILE_DIALOG_URL = "chrome://formautofill/content/editProfile.xhtml";
const TEST_PROFILE_1 = { const TEST_ADDRESS_1 = {
"given-name": "John", "given-name": "John",
"additional-name": "R.", "additional-name": "R.",
"family-name": "Smith", "family-name": "Smith",
@ -21,32 +21,32 @@ const TEST_PROFILE_1 = {
email: "timbl@w3.org", email: "timbl@w3.org",
}; };
const TEST_PROFILE_2 = { const TEST_ADDRESS_2 = {
"street-address": "Some Address", "street-address": "Some Address",
country: "US", country: "US",
}; };
const TEST_PROFILE_3 = { const TEST_ADDRESS_3 = {
"street-address": "Other Address", "street-address": "Other Address",
"postal-code": "12345", "postal-code": "12345",
}; };
function getProfiles() { function getAddresses() {
return new Promise(resolve => { return new Promise(resolve => {
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) { Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult); Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
resolve(result.data); resolve(result.data);
}); });
Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", {}); Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", {});
}); });
} }
function saveProfile(profile) { function saveAddress(address) {
Services.cpmm.sendAsyncMessage("FormAutofill:SaveProfile", {profile}); Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", {address});
return TestUtils.topicObserved("formautofill-storage-changed"); return TestUtils.topicObserved("formautofill-storage-changed");
} }
function removeProfiles(guids) { function removeAddresses(guids) {
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveProfiles", {guids}); Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses", {guids});
return TestUtils.topicObserved("formautofill-storage-changed"); return TestUtils.topicObserved("formautofill-storage-changed");
} }

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

@ -21,33 +21,33 @@ function checkMenuEntries(expectedValues) {
} }
} }
function addProfile(profile) { function addAddress(address) {
return new Promise(resolve => { return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddProfile", {profile}); formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddAddress", {address});
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileAdded", function onAdded(data) { formFillChromeScript.addMessageListener("FormAutofillTest:AddressAdded", function onAdded(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileAdded", onAdded); formFillChromeScript.removeMessageListener("FormAutofillTest:AddressAdded", onAdded);
resolve(); resolve();
}); });
}); });
} }
function removeProfile(guid) { function removeAddress(guid) {
return new Promise(resolve => { return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveProfile", {guid}); formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveAddress", {guid});
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileRemoved", function onDeleted(data) { formFillChromeScript.addMessageListener("FormAutofillTest:AddressRemoved", function onDeleted(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileRemoved", onDeleted); formFillChromeScript.removeMessageListener("FormAutofillTest:AddressRemoved", onDeleted);
resolve(); resolve();
}); });
}); });
} }
function updateProfile(guid, profile) { function updateAddress(guid, address) {
return new Promise(resolve => { return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateProfile", {profile, guid}); formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateAddress", {address, guid});
formFillChromeScript.addMessageListener("FormAutofillTest:ProfileUpdated", function onUpdated(data) { formFillChromeScript.addMessageListener("FormAutofillTest:AddressUpdated", function onUpdated(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:ProfileUpdated", onUpdated); formFillChromeScript.removeMessageListener("FormAutofillTest:AddressUpdated", onUpdated);
resolve(); resolve();
}); });

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

@ -8,19 +8,19 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
var ParentUtils = { var ParentUtils = {
cleanUpProfile() { cleanUpAddress() {
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) { Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult); Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
let profiles = result.data; let addresses = result.data;
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveProfiles", Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses",
{guids: profiles.map(profile => profile.guid)}); {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.cpmm.sendAsyncMessage(chromeMsg, msgData);
Services.obs.addObserver(function observer(subject, topic, data) { Services.obs.addObserver(function observer(subject, topic, data) {
if (data != type) { if (data != type) {
@ -39,23 +39,23 @@ var ParentUtils = {
cleanup() { cleanup() {
Services.obs.removeObserver(this, "formautofill-storage-changed"); Services.obs.removeObserver(this, "formautofill-storage-changed");
this.cleanUpProfile(); this.cleanUpAddress();
}, },
}; };
ParentUtils.cleanUpProfile(); ParentUtils.cleanUpAddress();
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed"); Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
addMessageListener("FormAutofillTest:AddProfile", (msg) => { addMessageListener("FormAutofillTest:AddAddress", (msg) => {
ParentUtils.updateProfile("add", "FormAutofill:SaveProfile", msg, "FormAutofillTest:ProfileAdded"); ParentUtils.updateAddress("add", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressAdded");
}); });
addMessageListener("FormAutofillTest:RemoveProfile", (msg) => { addMessageListener("FormAutofillTest:RemoveAddress", (msg) => {
ParentUtils.updateProfile("remove", "FormAutofill:Removefile", msg, "FormAutofillTest:ProfileRemoved"); ParentUtils.updateAddress("remove", "FormAutofill:RemoveAddress", msg, "FormAutofillTest:AddressRemoved");
}); });
addMessageListener("FormAutofillTest:UpdateProfile", (msg) => { addMessageListener("FormAutofillTest:UpdateAddress", (msg) => {
ParentUtils.updateProfile("update", "FormAutofill:SaveProfile", msg, "FormAutofillTest:ProfileUpdated"); ParentUtils.updateAddress("update", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressUpdated");
}); });
addMessageListener("cleanup", () => { addMessageListener("cleanup", () => {

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

@ -10,7 +10,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head> </head>
<body> <body>
Form autofill test: simple form profile autofill Form autofill test: simple form address autofill
<script> <script>
/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */ /* 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 = []; let promises = [];
for (let prop in profile) { for (let prop in address) {
let element = document.getElementById(prop); let element = document.getElementById(prop);
if (document.activeElement == element) { if (document.activeElement == element) {
promises.push(checkAutoCompleteInputFilled(element, profile[prop])); promises.push(checkAutoCompleteInputFilled(element, address[prop]));
} else { } else {
promises.push(checkInputFilled(element, profile[prop])); promises.push(checkInputFilled(element, address[prop]));
} }
} }
doKey("return"); doKey("return");
return Promise.all(promises); return Promise.all(promises);
} }
function* setupProfileStorage() { function* setupAddressStorage() {
yield addProfile(MOCK_STORAGE[0]); yield addAddress(MOCK_STORAGE[0]);
yield addProfile(MOCK_STORAGE[1]); yield addAddress(MOCK_STORAGE[1]);
} }
function* setupFormHistory() { function* setupFormHistory() {
@ -99,33 +99,33 @@ add_task(function* history_only_menu_checking() {
checkMenuEntries(["1-234-567-890"]); 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() { add_task(function* check_menu_when_both_existed() {
yield setupProfileStorage(); yield setupAddressStorage();
setInput("#organization", ""); setInput("#organization", "");
doKey("down"); doKey("down");
yield expectPopup(); yield expectPopup();
checkMenuEntries(MOCK_STORAGE.map(profile => checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: profile.organization, secondary: profile["street-address"]}) JSON.stringify({primary: address.organization, secondary: address["street-address"]})
)); ));
setInput("#street-address", ""); setInput("#street-address", "");
doKey("down"); doKey("down");
yield expectPopup(); yield expectPopup();
checkMenuEntries(MOCK_STORAGE.map(profile => checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: profile["street-address"], secondary: profile.organization}) JSON.stringify({primary: address["street-address"], secondary: address.organization})
)); ));
setInput("#tel", ""); setInput("#tel", "");
doKey("down"); doKey("down");
yield expectPopup(); yield expectPopup();
checkMenuEntries(MOCK_STORAGE.map(profile => checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: profile.tel, secondary: profile["street-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() { add_task(function* check_fallback_for_mismatched_field() {
setInput("#country", ""); setInput("#country", "");
doKey("down"); doKey("down");
@ -133,19 +133,19 @@ add_task(function* check_fallback_for_mismatched_field() {
checkMenuEntries(["US"]); checkMenuEntries(["US"]);
}); });
// Autofill the profile from dropdown menu. // Autofill the address from dropdown menu.
add_task(function* check_fields_after_form_autofill() { add_task(function* check_fields_after_form_autofill() {
setInput("#organization", "Moz"); setInput("#organization", "Moz");
doKey("down"); doKey("down");
yield expectPopup(); yield expectPopup();
checkMenuEntries(MOCK_STORAGE.map(profile => checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: profile.organization, secondary: profile["street-address"]}) JSON.stringify({primary: address.organization, secondary: address["street-address"]})
).slice(1)); ).slice(1));
doKey("down"); doKey("down");
yield checkFormFilled(MOCK_STORAGE[1]); 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() { add_task(function* check_fallback_after_form_autofill() {
setInput("#tel", ""); setInput("#tel", "");
doKey("down"); doKey("down");

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

@ -9,7 +9,7 @@ Cu.import("resource://formautofill/ProfileStorage.jsm");
const TEST_STORE_FILE_NAME = "test-profile.json"; const TEST_STORE_FILE_NAME = "test-profile.json";
const TEST_PROFILE_1 = { const TEST_ADDRESS_1 = {
"given-name": "Timothy", "given-name": "Timothy",
"additional-name": "John", "additional-name": "John",
"family-name": "Berners-Lee", "family-name": "Berners-Lee",
@ -23,36 +23,36 @@ const TEST_PROFILE_1 = {
email: "timbl@w3.org", email: "timbl@w3.org",
}; };
const TEST_PROFILE_2 = { const TEST_ADDRESS_2 = {
"street-address": "Some Address", "street-address": "Some Address",
country: "US", country: "US",
}; };
const TEST_PROFILE_3 = { const TEST_ADDRESS_3 = {
"street-address": "Other Address", "street-address": "Other Address",
"postal-code": "12345", "postal-code": "12345",
}; };
const TEST_PROFILE_WITH_INVALID_FIELD = { const TEST_ADDRESS_WITH_INVALID_FIELD = {
"street-address": "Another Address", "street-address": "Another Address",
invalidField: "INVALID", invalidField: "INVALID",
}; };
let prepareTestProfiles = Task.async(function* (path) { let prepareTestRecords = Task.async(function* (path) {
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let onChanged = TestUtils.topicObserved("formautofill-storage-changed", let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "add"); (subject, data) => data == "add");
profileStorage.add(TEST_PROFILE_1); profileStorage.add(TEST_ADDRESS_1);
yield onChanged; yield onChanged;
profileStorage.add(TEST_PROFILE_2); profileStorage.add(TEST_ADDRESS_2);
yield profileStorage._saveImmediately(); yield profileStorage._saveImmediately();
}); });
let do_check_profile_matches = (profileWithMeta, profile) => { let do_check_record_matches = (recordWithMeta, record) => {
for (let key in profile) { for (let key in record) {
do_check_eq(profileWithMeta[key], profile[key]); do_check_eq(recordWithMeta[key], record[key]);
} }
}; };
@ -62,7 +62,7 @@ add_task(function* test_initialize() {
yield profileStorage.initialize(); yield profileStorage.initialize();
do_check_eq(profileStorage._store.data.version, 1); 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; let data = profileStorage._store.data;
@ -76,150 +76,150 @@ add_task(function* test_initialize() {
add_task(function* test_getAll() { add_task(function* test_getAll() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); 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_record_matches(addresses[0], TEST_ADDRESS_1);
do_check_profile_matches(profiles[1], TEST_PROFILE_2); do_check_record_matches(addresses[1], TEST_ADDRESS_2);
// Modifying output shouldn't affect the storage. // Modifying output shouldn't affect the storage.
profiles[0].organization = "test"; addresses[0].organization = "test";
do_check_profile_matches(profileStorage.getAll()[0], TEST_PROFILE_1); do_check_record_matches(profileStorage.getAll()[0], TEST_ADDRESS_1);
}); });
add_task(function* test_get() { add_task(function* test_get() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profiles = profileStorage.getAll(); let addresses = profileStorage.getAll();
let guid = profiles[0].guid; let guid = addresses[0].guid;
let profile = profileStorage.get(guid); let address = profileStorage.get(guid);
do_check_profile_matches(profile, TEST_PROFILE_1); do_check_record_matches(address, TEST_ADDRESS_1);
// Modifying output shouldn't affect the storage. // Modifying output shouldn't affect the storage.
profile.organization = "test"; address.organization = "test";
do_check_profile_matches(profileStorage.get(guid), TEST_PROFILE_1); do_check_record_matches(profileStorage.get(guid), TEST_ADDRESS_1);
Assert.throws(() => profileStorage.get("INVALID_GUID"), Assert.throws(() => profileStorage.get("INVALID_GUID"),
/No matching profile\./); /No matching record\./);
}); });
add_task(function* test_getByFilter() { add_task(function* test_getByFilter() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let filter = {info: {fieldName: "street-address"}, searchString: "Some"}; let filter = {info: {fieldName: "street-address"}, searchString: "Some"};
let profiles = profileStorage.getByFilter(filter); let addresses = profileStorage.getByFilter(filter);
do_check_eq(profiles.length, 1); do_check_eq(addresses.length, 1);
do_check_profile_matches(profiles[0], TEST_PROFILE_2); do_check_record_matches(addresses[0], TEST_ADDRESS_2);
filter = {info: {fieldName: "country"}, searchString: "u"}; filter = {info: {fieldName: "country"}, searchString: "u"};
profiles = profileStorage.getByFilter(filter); addresses = profileStorage.getByFilter(filter);
do_check_eq(profiles.length, 2); do_check_eq(addresses.length, 2);
do_check_profile_matches(profiles[0], TEST_PROFILE_1); do_check_record_matches(addresses[0], TEST_ADDRESS_1);
do_check_profile_matches(profiles[1], TEST_PROFILE_2); do_check_record_matches(addresses[1], TEST_ADDRESS_2);
filter = {info: {fieldName: "street-address"}, searchString: "test"}; filter = {info: {fieldName: "street-address"}, searchString: "test"};
profiles = profileStorage.getByFilter(filter); addresses = profileStorage.getByFilter(filter);
do_check_eq(profiles.length, 0); do_check_eq(addresses.length, 0);
filter = {info: {fieldName: "street-address"}, searchString: ""}; filter = {info: {fieldName: "street-address"}, searchString: ""};
profiles = profileStorage.getByFilter(filter); addresses = profileStorage.getByFilter(filter);
do_check_eq(profiles.length, 2); do_check_eq(addresses.length, 2);
// Check if the filtering logic is free from searching special chars. // Check if the filtering logic is free from searching special chars.
filter = {info: {fieldName: "street-address"}, searchString: ".*"}; filter = {info: {fieldName: "street-address"}, searchString: ".*"};
profiles = profileStorage.getByFilter(filter); addresses = profileStorage.getByFilter(filter);
do_check_eq(profiles.length, 0); do_check_eq(addresses.length, 0);
}); });
add_task(function* test_add() { add_task(function* test_add() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); 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_record_matches(addresses[0], TEST_ADDRESS_1);
do_check_profile_matches(profiles[1], TEST_PROFILE_2); do_check_record_matches(addresses[1], TEST_ADDRESS_2);
do_check_neq(profiles[0].guid, undefined); do_check_neq(addresses[0].guid, undefined);
do_check_neq(profiles[0].timeCreated, undefined); do_check_neq(addresses[0].timeCreated, undefined);
do_check_eq(profiles[0].timeLastModified, profiles[0].timeCreated); do_check_eq(addresses[0].timeLastModified, addresses[0].timeCreated);
do_check_eq(profiles[0].timeLastUsed, 0); do_check_eq(addresses[0].timeLastUsed, 0);
do_check_eq(profiles[0].timesUsed, 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\./); /"invalidField" is not a valid field\./);
}); });
add_task(function* test_update() { add_task(function* test_update() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profiles = profileStorage.getAll(); let addresses = profileStorage.getAll();
let guid = profiles[1].guid; let guid = addresses[1].guid;
let timeLastModified = profiles[1].timeLastModified; let timeLastModified = addresses[1].timeLastModified;
let onChanged = TestUtils.topicObserved("formautofill-storage-changed", let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "update"); (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 onChanged;
yield profileStorage._saveImmediately(); yield profileStorage._saveImmediately();
profileStorage = new ProfileStorage(path); profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profile = profileStorage.get(guid); let address = profileStorage.get(guid);
do_check_eq(profile.country, undefined); do_check_eq(address.country, undefined);
do_check_neq(profile.timeLastModified, timeLastModified); do_check_neq(address.timeLastModified, timeLastModified);
do_check_profile_matches(profile, TEST_PROFILE_3); do_check_record_matches(address, TEST_ADDRESS_3);
Assert.throws( Assert.throws(
() => profileStorage.update("INVALID_GUID", TEST_PROFILE_3), () => profileStorage.update("INVALID_GUID", TEST_ADDRESS_3),
/No matching profile\./ /No matching record\./
); );
Assert.throws( Assert.throws(
() => profileStorage.update(guid, TEST_PROFILE_WITH_INVALID_FIELD), () => profileStorage.update(guid, TEST_ADDRESS_WITH_INVALID_FIELD),
/"invalidField" is not a valid field\./ /"invalidField" is not a valid field\./
); );
}); });
add_task(function* test_notifyUsed() { add_task(function* test_notifyUsed() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profiles = profileStorage.getAll(); let addresses = profileStorage.getAll();
let guid = profiles[1].guid; let guid = addresses[1].guid;
let timeLastUsed = profiles[1].timeLastUsed; let timeLastUsed = addresses[1].timeLastUsed;
let timesUsed = profiles[1].timesUsed; let timesUsed = addresses[1].timesUsed;
let onChanged = TestUtils.topicObserved("formautofill-storage-changed", let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "notifyUsed"); (subject, data) => data == "notifyUsed");
@ -231,29 +231,29 @@ add_task(function* test_notifyUsed() {
profileStorage = new ProfileStorage(path); profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profile = profileStorage.get(guid); let address = profileStorage.get(guid);
do_check_eq(profile.timesUsed, timesUsed + 1); do_check_eq(address.timesUsed, timesUsed + 1);
do_check_neq(profile.timeLastUsed, timeLastUsed); do_check_neq(address.timeLastUsed, timeLastUsed);
Assert.throws(() => profileStorage.notifyUsed("INVALID_GUID"), Assert.throws(() => profileStorage.notifyUsed("INVALID_GUID"),
/No matching profile\./); /No matching record\./);
}); });
add_task(function* test_remove() { add_task(function* test_remove() {
let path = getTempFile(TEST_STORE_FILE_NAME).path; let path = getTempFile(TEST_STORE_FILE_NAME).path;
yield prepareTestProfiles(path); yield prepareTestRecords(path);
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
let profiles = profileStorage.getAll(); let addresses = profileStorage.getAll();
let guid = profiles[1].guid; let guid = addresses[1].guid;
let onChanged = TestUtils.topicObserved("formautofill-storage-changed", let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
(subject, data) => data == "remove"); (subject, data) => data == "remove");
do_check_eq(profiles.length, 2); do_check_eq(addresses.length, 2);
profileStorage.remove(guid); profileStorage.remove(guid);
yield onChanged; yield onChanged;
@ -262,9 +262,9 @@ add_task(function* test_remove() {
profileStorage = new ProfileStorage(path); profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); 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 = [ const COMPUTE_TESTCASES = [
// Empty // Empty
{ {
description: "Empty profile", description: "Empty address",
profile: { address: {
}, },
expectedResult: { expectedResult: {
}, },
@ -22,7 +22,7 @@ const COMPUTE_TESTCASES = [
// Name // Name
{ {
description: "Has split names", description: "Has split names",
profile: { address: {
"given-name": "Timothy", "given-name": "Timothy",
"additional-name": "John", "additional-name": "John",
"family-name": "Berners-Lee", "family-name": "Berners-Lee",
@ -38,7 +38,7 @@ const COMPUTE_TESTCASES = [
// Address // Address
{ {
description: "\"street-address\" with single line", description: "\"street-address\" with single line",
profile: { address: {
"street-address": "single line", "street-address": "single line",
}, },
expectedResult: { expectedResult: {
@ -48,7 +48,7 @@ const COMPUTE_TESTCASES = [
}, },
{ {
description: "\"street-address\" with multiple lines", description: "\"street-address\" with multiple lines",
profile: { address: {
"street-address": "line1\nline2\nline3", "street-address": "line1\nline2\nline3",
}, },
expectedResult: { expectedResult: {
@ -60,7 +60,7 @@ const COMPUTE_TESTCASES = [
}, },
{ {
description: "\"street-address\" with multiple lines but line2 is omitted", description: "\"street-address\" with multiple lines but line2 is omitted",
profile: { address: {
"street-address": "line1\n\nline3", "street-address": "line1\n\nline3",
}, },
expectedResult: { expectedResult: {
@ -72,7 +72,7 @@ const COMPUTE_TESTCASES = [
}, },
{ {
description: "\"street-address\" with 4 lines", description: "\"street-address\" with 4 lines",
profile: { address: {
"street-address": "line1\nline2\nline3\nline4", "street-address": "line1\nline2\nline3\nline4",
}, },
expectedResult: { expectedResult: {
@ -87,8 +87,8 @@ const COMPUTE_TESTCASES = [
const NORMALIZE_TESTCASES = [ const NORMALIZE_TESTCASES = [
// Empty // Empty
{ {
description: "Empty profile", description: "Empty address",
profile: { address: {
}, },
expectedResult: { expectedResult: {
}, },
@ -97,7 +97,7 @@ const NORMALIZE_TESTCASES = [
// Name // Name
{ {
description: "Has \"name\", and the split names are omitted", description: "Has \"name\", and the split names are omitted",
profile: { address: {
"name": "Timothy John Berners-Lee", "name": "Timothy John Berners-Lee",
}, },
expectedResult: { expectedResult: {
@ -108,7 +108,7 @@ const NORMALIZE_TESTCASES = [
}, },
{ {
description: "Has both \"name\" and split names", description: "Has both \"name\" and split names",
profile: { address: {
"name": "John Doe", "name": "John Doe",
"given-name": "Timothy", "given-name": "Timothy",
"additional-name": "John", "additional-name": "John",
@ -122,7 +122,7 @@ const NORMALIZE_TESTCASES = [
}, },
{ {
description: "Has \"name\", and some of split names are omitted", description: "Has \"name\", and some of split names are omitted",
profile: { address: {
"name": "John Doe", "name": "John Doe",
"given-name": "Timothy", "given-name": "Timothy",
}, },
@ -136,7 +136,7 @@ const NORMALIZE_TESTCASES = [
// Address // Address
{ {
description: "Has \"address-line1~3\" and \"street-address\" is omitted", description: "Has \"address-line1~3\" and \"street-address\" is omitted",
profile: { address: {
"address-line1": "line1", "address-line1": "line1",
"address-line2": "line2", "address-line2": "line2",
"address-line3": "line3", "address-line3": "line3",
@ -147,7 +147,7 @@ const NORMALIZE_TESTCASES = [
}, },
{ {
description: "Has both \"address-line1~3\" and \"street-address\"", description: "Has both \"address-line1~3\" and \"street-address\"",
profile: { address: {
"street-address": "street address", "street-address": "street address",
"address-line1": "line1", "address-line1": "line1",
"address-line2": "line2", "address-line2": "line2",
@ -159,7 +159,7 @@ const NORMALIZE_TESTCASES = [
}, },
{ {
description: "Has \"address-line2~3\" and single-line \"street-address\"", description: "Has \"address-line2~3\" and single-line \"street-address\"",
profile: { address: {
"street-address": "street address", "street-address": "street address",
"address-line2": "line2", "address-line2": "line2",
"address-line3": "line3", "address-line3": "line3",
@ -170,7 +170,7 @@ const NORMALIZE_TESTCASES = [
}, },
{ {
description: "Has \"address-line2~3\" and multiple-line \"street-address\"", description: "Has \"address-line2~3\" and multiple-line \"street-address\"",
profile: { address: {
"street-address": "street address\nstreet address line 2", "street-address": "street address\nstreet address line 2",
"address-line2": "line2", "address-line2": "line2",
"address-line3": "line3", "address-line3": "line3",
@ -181,9 +181,9 @@ const NORMALIZE_TESTCASES = [
}, },
]; ];
let do_check_profile_matches = (expectedProfile, profile) => { let do_check_record_matches = (expectedRecord, record) => {
for (let key in expectedProfile) { for (let key in expectedRecord) {
do_check_eq(expectedProfile[key], profile[key] || ""); do_check_eq(expectedRecord[key], record[key] || "");
} }
}; };
@ -193,36 +193,36 @@ add_task(function* test_computeFields() {
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
COMPUTE_TESTCASES.forEach(testcase => profileStorage.add(testcase.profile)); COMPUTE_TESTCASES.forEach(testcase => profileStorage.add(testcase.address));
yield profileStorage._saveImmediately(); yield profileStorage._saveImmediately();
profileStorage = new ProfileStorage(path); profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); 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_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 path = getTempFile(TEST_STORE_FILE_NAME).path;
let profileStorage = new ProfileStorage(path); let profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); yield profileStorage.initialize();
NORMALIZE_TESTCASES.forEach(testcase => profileStorage.add(testcase.profile)); NORMALIZE_TESTCASES.forEach(testcase => profileStorage.add(testcase.address));
yield profileStorage._saveImmediately(); yield profileStorage._saveImmediately();
profileStorage = new ProfileStorage(path); profileStorage = new ProfileStorage(path);
yield profileStorage.initialize(); 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_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]);
} }
}); });