fune/browser/extensions/formautofill/test/unit/head.js
Kris Maglione bf1736ab8b Bug 1484236: Override cert DB for form autofill xpcshell tests. r=rhelmer CLOSED TREE
Differential Revision: https://phabricator.services.mozilla.com/D4173

--HG--
extra : amend_source : da98e07581f2b96fd7a968dfdc110830c3d61342
2018-08-23 16:16:11 -07:00

225 lines
8.1 KiB
JavaScript

/**
* Provides infrastructure for automated formautofill components tests.
*/
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/ObjectUtils.jsm");
ChromeUtils.import("resource://gre/modules/FormLikeFactory.jsm");
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
ChromeUtils.import("resource://testing-common/FileTestUtils.jsm");
ChromeUtils.import("resource://testing-common/MockDocument.jsm");
ChromeUtils.import("resource://testing-common/TestUtils.jsm");
ChromeUtils.defineModuleGetter(this, "DownloadPaths",
"resource://gre/modules/DownloadPaths.jsm");
ChromeUtils.defineModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm");
do_get_profile();
// ================================================
// Load mocking/stubbing library, sinon
// docs: http://sinonjs.org/releases/v2.3.2/
ChromeUtils.import("resource://gre/modules/Timer.jsm");
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js", this);
/* globals sinon */
// ================================================
const EXTENSION_ID = "formautofill@mozilla.org";
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
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.import("resource://formautofill/FormAutofillStorage.jsm", {});
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(profileStorage[collectionName].add(record));
await onChanged;
}
await profileStorage._saveImmediately();
return profileStorage;
}
function verifySectionFieldDetails(sections, expectedResults) {
Assert.equal(sections.length, expectedResults.length, "Expected section count.");
sections.forEach((sectionInfo, sectionIndex) => {
let expectedSectionInfo = expectedResults[sectionIndex];
info("FieldName Prediction Results: " + sectionInfo.map(i => i.fieldName));
info("FieldName Expected Results: " + expectedSectionInfo.map(i => i.fieldName));
Assert.equal(sectionInfo.length, expectedSectionInfo.length, "Expected field count.");
sectionInfo.forEach((field, fieldIndex) => {
let expectedField = expectedSectionInfo[fieldIndex];
delete field._reason;
delete field.elementWeakRef;
Assert.deepEqual(field, expectedField);
});
});
}
async function runHeuristicsTest(patterns, fixturePathPrefix) {
add_task(async function setup() {
ChromeUtils.import("resource://formautofill/FormAutofillHeuristics.jsm");
ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
});
patterns.forEach(testPattern => {
add_task(async function() {
info("Starting test fixture: " + testPattern.fixturePath);
let file = do_get_file(fixturePathPrefix + testPattern.fixturePath);
let doc = MockDocument.createTestDocumentFromFile("http://localhost:8080/test/", file);
let forms = [];
for (let field of FormAutofillUtils.autofillFieldSelector(doc)) {
let formLike = FormLikeFactory.createFromField(field);
if (!forms.some(form => form.rootElement === formLike.rootElement)) {
forms.push(formLike);
}
}
Assert.equal(forms.length, testPattern.expectedResult.length, "Expected form count.");
forms.forEach((form, formIndex) => {
let sections = FormAutofillHeuristics.getFormInfo(form);
verifySectionFieldDetails(
sections.map(section => section.fieldDetails),
testPattern.expectedResult[formIndex],
);
});
});
});
}
/**
* 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_task(async function head_initialize() {
Services.prefs.setStringPref("extensions.formautofill.available", "on");
Services.prefs.setBoolPref("extensions.formautofill.creditCards.available", true);
Services.prefs.setBoolPref("extensions.formautofill.heuristics.enabled", true);
Services.prefs.setBoolPref("extensions.formautofill.section.enabled", true);
Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
// Clean up after every test.
registerCleanupFunction(function head_cleanup() {
Services.prefs.clearUserPref("extensions.formautofill.available");
Services.prefs.clearUserPref("extensions.formautofill.creditCards.available");
Services.prefs.clearUserPref("extensions.formautofill.heuristics.enabled");
Services.prefs.clearUserPref("extensions.formautofill.section.enabled");
Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
});
await loadExtension();
});