summaryrefslogtreecommitdiffstats
path: root/browser/extensions/formautofill/test/unit/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/formautofill/test/unit/head.js')
-rw-r--r--browser/extensions/formautofill/test/unit/head.js357
1 files changed, 357 insertions, 0 deletions
diff --git a/browser/extensions/formautofill/test/unit/head.js b/browser/extensions/formautofill/test/unit/head.js
new file mode 100644
index 0000000000..e5353833ef
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -0,0 +1,357 @@
+/**
+ * Provides infrastructure for automated formautofill components tests.
+ */
+
+"use strict";
+
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+var { ObjectUtils } = ChromeUtils.import(
+ "resource://gre/modules/ObjectUtils.jsm"
+);
+var { FormLikeFactory } = ChromeUtils.importESModule(
+ "resource://gre/modules/FormLikeFactory.sys.mjs"
+);
+var { FormAutofillHandler } = ChromeUtils.importESModule(
+ "resource://gre/modules/shared/FormAutofillHandler.sys.mjs"
+);
+var { AddonTestUtils, MockAsyncShutdown } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+var { ExtensionTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
+);
+var { FileTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/FileTestUtils.sys.mjs"
+);
+var { MockDocument } = ChromeUtils.importESModule(
+ "resource://testing-common/MockDocument.sys.mjs"
+);
+var { sinon } = ChromeUtils.importESModule(
+ "resource://testing-common/Sinon.sys.mjs"
+);
+var { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
+ AddonManagerPrivate: "resource://gre/modules/AddonManager.sys.mjs",
+ ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
+ FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
+});
+
+{
+ // We're going to register a mock file source
+ // with region names based on en-US. This is
+ // necessary for tests that expect to match
+ // on region code display names.
+ const fs = [
+ {
+ path: "toolkit/intl/regionNames.ftl",
+ source: `
+region-name-us = United States
+region-name-nz = New Zealand
+region-name-au = Australia
+region-name-ca = Canada
+region-name-tw = Taiwan
+ `,
+ },
+ ];
+
+ let locales = Services.locale.packagedLocales;
+ const mockSource = L10nFileSource.createMock(
+ "mock",
+ "app",
+ locales,
+ "resource://mock_path",
+ fs
+ );
+ L10nRegistry.getInstance().registerSources([mockSource]);
+}
+
+do_get_profile();
+
+const EXTENSION_ID = "formautofill@mozilla.org";
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+
+function SetPref(name, value) {
+ switch (typeof value) {
+ case "string":
+ Services.prefs.setCharPref(name, value);
+ break;
+ case "number":
+ Services.prefs.setIntPref(name, value);
+ break;
+ case "boolean":
+ Services.prefs.setBoolPref(name, value);
+ break;
+ default:
+ throw new Error("Unknown type");
+ }
+}
+
+// Return the current date rounded in the manner that sync does.
+function getDateForSync() {
+ return Math.round(Date.now() / 10) / 100;
+}
+
+async function loadExtension() {
+ AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "1.9.2"
+ );
+ await AddonTestUtils.promiseStartupManager();
+
+ let extensionPath = Services.dirsvc.get("GreD", Ci.nsIFile);
+ extensionPath.append("browser");
+ extensionPath.append("features");
+ extensionPath.append(EXTENSION_ID);
+
+ if (!extensionPath.exists()) {
+ extensionPath.leafName = `${EXTENSION_ID}.xpi`;
+ }
+
+ let startupPromise = new Promise(resolve => {
+ const { apiManager } = ExtensionParent;
+ function onReady(event, extension) {
+ if (extension.id == EXTENSION_ID) {
+ apiManager.off("ready", onReady);
+ resolve();
+ }
+ }
+
+ apiManager.on("ready", onReady);
+ });
+
+ await AddonManager.installTemporaryAddon(extensionPath);
+ await startupPromise;
+}
+
+// Returns a reference to a temporary file that is guaranteed not to exist and
+// is cleaned up later. See FileTestUtils.getTempFile for details.
+function getTempFile(leafName) {
+ return FileTestUtils.getTempFile(leafName);
+}
+
+async function initProfileStorage(
+ fileName,
+ records,
+ collectionName = "addresses"
+) {
+ let { FormAutofillStorage } = ChromeUtils.importESModule(
+ "resource://autofill/FormAutofillStorage.sys.mjs"
+ );
+ let path = getTempFile(fileName).path;
+ let profileStorage = new FormAutofillStorage(path);
+ await profileStorage.initialize();
+
+ // AddonTestUtils inserts its own directory provider that manages TmpD.
+ // It removes that directory at shutdown, which races with shutdown
+ // handing in JSONFile/DeferredTask (which is used by FormAutofillStorage).
+ // Avoid the race by explicitly finalizing any formautofill JSONFile
+ // instances created manually by individual tests when the test finishes.
+ registerCleanupFunction(function finalizeAutofillStorage() {
+ return profileStorage._finalize();
+ });
+
+ if (!records || !Array.isArray(records)) {
+ return profileStorage;
+ }
+
+ let onChanged = TestUtils.topicObserved(
+ "formautofill-storage-changed",
+ (subject, data) =>
+ data == "add" && subject.wrappedJSObject.collectionName == collectionName
+ );
+ for (let record of records) {
+ Assert.ok(await profileStorage[collectionName].add(record));
+ await onChanged;
+ }
+ await profileStorage._saveImmediately();
+ return profileStorage;
+}
+
+function verifySectionAutofillResult(sections, expectedSectionsInfo) {
+ sections.forEach((section, index) => {
+ const expectedSection = expectedSectionsInfo[index];
+
+ const fieldDetails = section.fieldDetails;
+ const expectedFieldDetails = expectedSection.fields;
+
+ info(`verify autofill section[${index}]`);
+
+ fieldDetails.forEach((field, fieldIndex) => {
+ const expeceted = expectedFieldDetails[fieldIndex];
+
+ Assert.equal(
+ expeceted.autofill,
+ field.element.value,
+ `Autofilled value for element(id=${field.element.id}, field name=${field.fieldName}) should be equal`
+ );
+ });
+ });
+}
+
+function verifySectionFieldDetails(sections, expectedSectionsInfo) {
+ sections.forEach((section, index) => {
+ const expectedSection = expectedSectionsInfo[index];
+
+ const fieldDetails = section.fieldDetails;
+ const expectedFieldDetails = expectedSection.fields;
+
+ info(`section[${index}] ${expectedSection.description ?? ""}:`);
+ info(`FieldName Prediction Results: ${fieldDetails.map(i => i.fieldName)}`);
+ info(
+ `FieldName Expected Results: ${expectedFieldDetails.map(
+ detail => detail.fieldName
+ )}`
+ );
+ Assert.equal(
+ fieldDetails.length,
+ expectedFieldDetails.length,
+ `Expected field count.`
+ );
+
+ fieldDetails.forEach((field, fieldIndex) => {
+ const expectedFieldDetail = expectedFieldDetails[fieldIndex];
+
+ const expected = {
+ ...{
+ reason: "autocomplete",
+ section: "",
+ contactType: "",
+ addressType: "",
+ },
+ ...expectedSection.default,
+ ...expectedFieldDetail,
+ };
+
+ const keys = new Set([...Object.keys(field), ...Object.keys(expected)]);
+ ["autofill", "elementWeakRef", "confidence", "part"].forEach(k =>
+ keys.delete(k)
+ );
+
+ for (const key of keys) {
+ const expectedValue = expected[key];
+ const actualValue = field[key];
+ Assert.equal(
+ expectedValue,
+ actualValue,
+ `${key} should be equal, expect ${expectedValue}, got ${actualValue}`
+ );
+ }
+ });
+
+ Assert.equal(
+ section.isValidSection(),
+ !expectedSection.invalid,
+ `Should be an ${expectedSection.invalid ? "invalid" : "valid"} section`
+ );
+ });
+}
+
+var FormAutofillHeuristics, LabelUtils;
+var AddressDataLoader, FormAutofillUtils;
+
+function autofillFieldSelector(doc) {
+ return doc.querySelectorAll("input, select");
+}
+
+/**
+ * Returns the Sync change counter for a profile storage record. Synced records
+ * store additional metadata for tracking changes and resolving merge conflicts.
+ * Deleting a synced record replaces the record with a tombstone.
+ *
+ * @param {AutofillRecords} records
+ * The `AutofillRecords` instance to query.
+ * @param {string} guid
+ * The GUID of the record or tombstone.
+ * @returns {number}
+ * The change counter, or -1 if the record doesn't exist or hasn't
+ * been synced yet.
+ */
+function getSyncChangeCounter(records, guid) {
+ let record = records._findByGUID(guid, { includeDeleted: true });
+ if (!record) {
+ return -1;
+ }
+ let sync = records._getSyncMetaData(record);
+ if (!sync) {
+ return -1;
+ }
+ return sync.changeCounter;
+}
+
+/**
+ * Performs a partial deep equality check to determine if an object contains
+ * the given fields.
+ *
+ * @param {object} object
+ * The object to check. Unlike `ObjectUtils.deepEqual`, properties in
+ * `object` that are not in `fields` will be ignored.
+ * @param {object} fields
+ * The fields to match.
+ * @returns {boolean}
+ * Does `object` contain `fields` with matching values?
+ */
+function objectMatches(object, fields) {
+ let actual = {};
+ for (let key in fields) {
+ if (!object.hasOwnProperty(key)) {
+ return false;
+ }
+ actual[key] = object[key];
+ }
+ return ObjectUtils.deepEqual(actual, fields);
+}
+
+add_setup(async function head_initialize() {
+ Services.prefs.setBoolPref("extensions.experiments.enabled", true);
+ Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
+
+ Services.prefs.setCharPref(
+ "extensions.formautofill.addresses.supported",
+ "on"
+ );
+ Services.prefs.setCharPref(
+ "extensions.formautofill.creditCards.supported",
+ "on"
+ );
+ Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", true);
+ Services.prefs.setBoolPref(
+ "extensions.formautofill.creditCards.enabled",
+ true
+ );
+
+ // Clean up after every test.
+ registerCleanupFunction(function head_cleanup() {
+ Services.prefs.clearUserPref("extensions.experiments.enabled");
+ Services.prefs.clearUserPref(
+ "extensions.formautofill.creditCards.supported"
+ );
+ Services.prefs.clearUserPref("extensions.formautofill.addresses.supported");
+ Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
+ Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
+ Services.prefs.clearUserPref("extensions.formautofill.addresses.enabled");
+ Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
+ });
+
+ await loadExtension();
+});
+
+let OSKeyStoreTestUtils;
+add_setup(async function os_key_store_setup() {
+ ({ OSKeyStoreTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/OSKeyStoreTestUtils.sys.mjs"
+ ));
+ OSKeyStoreTestUtils.setup();
+ registerCleanupFunction(async function cleanup() {
+ await OSKeyStoreTestUtils.cleanup();
+ });
+});