tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

head.js (10938B)


      1 /**
      2 * Provides infrastructure for automated formautofill components tests.
      3 */
      4 
      5 "use strict";
      6 
      7 var { XPCOMUtils } = ChromeUtils.importESModule(
      8  "resource://gre/modules/XPCOMUtils.sys.mjs"
      9 );
     10 var { ObjectUtils } = ChromeUtils.importESModule(
     11  "resource://gre/modules/ObjectUtils.sys.mjs"
     12 );
     13 var { FormLikeFactory } = ChromeUtils.importESModule(
     14  "resource://gre/modules/FormLikeFactory.sys.mjs"
     15 );
     16 var { FormAutofillHandler } = ChromeUtils.importESModule(
     17  "resource://gre/modules/shared/FormAutofillHandler.sys.mjs"
     18 );
     19 var { FormAutofillHeuristics } = ChromeUtils.importESModule(
     20  "resource://gre/modules/shared/FormAutofillHeuristics.sys.mjs"
     21 );
     22 var { AddonTestUtils, MockAsyncShutdown } = ChromeUtils.importESModule(
     23  "resource://testing-common/AddonTestUtils.sys.mjs"
     24 );
     25 var { ExtensionTestUtils } = ChromeUtils.importESModule(
     26  "resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
     27 );
     28 var { FileTestUtils } = ChromeUtils.importESModule(
     29  "resource://testing-common/FileTestUtils.sys.mjs"
     30 );
     31 var { MockDocument } = ChromeUtils.importESModule(
     32  "resource://testing-common/MockDocument.sys.mjs"
     33 );
     34 var { sinon } = ChromeUtils.importESModule(
     35  "resource://testing-common/Sinon.sys.mjs"
     36 );
     37 var { TestUtils } = ChromeUtils.importESModule(
     38  "resource://testing-common/TestUtils.sys.mjs"
     39 );
     40 
     41 ChromeUtils.defineESModuleGetters(this, {
     42  AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
     43  AddonManagerPrivate: "resource://gre/modules/AddonManager.sys.mjs",
     44  ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
     45  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
     46 });
     47 
     48 {
     49  // We're going to register a mock file source
     50  // with region names based on en-US. This is
     51  // necessary for tests that expect to match
     52  // on region code display names.
     53  const fs = [
     54    {
     55      path: "toolkit/intl/regionNames.ftl",
     56      source: `
     57 region-name-us = United States
     58 region-name-nz = New Zealand
     59 region-name-au = Australia
     60 region-name-ca = Canada
     61 region-name-tw = Taiwan
     62    `,
     63    },
     64  ];
     65 
     66  let locales = Services.locale.packagedLocales;
     67  const mockSource = L10nFileSource.createMock(
     68    "mock",
     69    "app",
     70    locales,
     71    "resource://mock_path",
     72    fs
     73  );
     74  L10nRegistry.getInstance().registerSources([mockSource]);
     75 }
     76 
     77 do_get_profile();
     78 
     79 const EXTENSION_ID = "formautofill@mozilla.org";
     80 
     81 AddonTestUtils.init(this);
     82 AddonTestUtils.overrideCertDB();
     83 
     84 function SetPref(name, value) {
     85  switch (typeof value) {
     86    case "string":
     87      Services.prefs.setCharPref(name, value);
     88      break;
     89    case "number":
     90      Services.prefs.setIntPref(name, value);
     91      break;
     92    case "boolean":
     93      Services.prefs.setBoolPref(name, value);
     94      break;
     95    default:
     96      throw new Error("Unknown type");
     97  }
     98 }
     99 
    100 // Return the current date rounded in the manner that sync does.
    101 function getDateForSync() {
    102  return Math.round(Date.now() / 10) / 100;
    103 }
    104 
    105 // Returns a reference to a temporary file that is guaranteed not to exist and
    106 // is cleaned up later. See FileTestUtils.getTempFile for details.
    107 function getTempFile(leafName) {
    108  return FileTestUtils.getTempFile(leafName);
    109 }
    110 
    111 async function initProfileStorage(
    112  fileName,
    113  records,
    114  collectionName = "addresses"
    115 ) {
    116  let { FormAutofillStorage } = ChromeUtils.importESModule(
    117    "resource://autofill/FormAutofillStorage.sys.mjs"
    118  );
    119  let path = getTempFile(fileName).path;
    120  let profileStorage = new FormAutofillStorage(path);
    121  await profileStorage.initialize();
    122 
    123  // AddonTestUtils inserts its own directory provider that manages TmpD.
    124  // It removes that directory at shutdown, which races with shutdown
    125  // handing in JSONFile/DeferredTask (which is used by FormAutofillStorage).
    126  // Avoid the race by explicitly finalizing any formautofill JSONFile
    127  // instances created manually by individual tests when the test finishes.
    128  registerCleanupFunction(function finalizeAutofillStorage() {
    129    return profileStorage._finalize();
    130  });
    131 
    132  if (!records || !Array.isArray(records)) {
    133    return profileStorage;
    134  }
    135 
    136  let onChanged = TestUtils.topicObserved(
    137    "formautofill-storage-changed",
    138    (subject, data) =>
    139      data == "add" && subject.wrappedJSObject.collectionName == collectionName
    140  );
    141  for (let record of records) {
    142    Assert.ok(await profileStorage[collectionName].add(record));
    143    await onChanged;
    144  }
    145  await profileStorage._saveImmediately();
    146  return profileStorage;
    147 }
    148 
    149 function verifySectionAutofillResult(sections, expectedSectionsInfo) {
    150  sections.forEach((section, index) => {
    151    const expectedSection = expectedSectionsInfo[index];
    152 
    153    const fieldDetails = section.fieldDetails;
    154    const expectedFieldDetails = expectedSection.fields;
    155 
    156    info(`verify autofill section[${index}]`);
    157 
    158    fieldDetails.forEach((field, fieldIndex) => {
    159      const expeceted = expectedFieldDetails[fieldIndex];
    160 
    161      Assert.equal(
    162        expeceted.autofill,
    163        field.element.value,
    164        `Autofilled value for element(id=${field.element.id}, field name=${field.fieldName}) should be equal`
    165      );
    166    });
    167  });
    168 }
    169 
    170 function verifySectionFieldDetails(sections, expectedSectionsInfo) {
    171  sections.forEach((section, index) => {
    172    const expectedSection = expectedSectionsInfo[index];
    173 
    174    const fieldDetails = section.fieldDetails;
    175    const expectedFieldDetails = expectedSection.fields;
    176 
    177    info(`section[${index}] ${expectedSection.description ?? ""}:`);
    178    info(`FieldName Prediction Results: ${fieldDetails.map(i => i.fieldName)}`);
    179    info(
    180      `FieldName Expected Results:   ${expectedFieldDetails.map(
    181        detail => detail.fieldName
    182      )}`
    183    );
    184    Assert.equal(
    185      fieldDetails.length,
    186      expectedFieldDetails.length,
    187      `Expected field count.`
    188    );
    189 
    190    fieldDetails.forEach((field, fieldIndex) => {
    191      const expectedFieldDetail = expectedFieldDetails[fieldIndex];
    192 
    193      const expected = {
    194        ...{
    195          reason: "autocomplete",
    196          section: "",
    197          contactType: "",
    198          addressType: "",
    199        },
    200        ...expectedSection.default,
    201        ...expectedFieldDetail,
    202      };
    203 
    204      const keys = new Set([...Object.keys(field), ...Object.keys(expected)]);
    205      ["autofill", "elementWeakRef", "confidence", "part"].forEach(k =>
    206        keys.delete(k)
    207      );
    208 
    209      for (const key of keys) {
    210        const expectedValue = expected[key];
    211        const actualValue = field[key];
    212        Assert.equal(
    213          expectedValue,
    214          actualValue,
    215          `${key} should be equal, expect ${expectedValue}, got ${actualValue}`
    216        );
    217      }
    218    });
    219 
    220    Assert.equal(
    221      section.isValidSection(),
    222      !expectedSection.invalid,
    223      `Should be an ${expectedSection.invalid ? "invalid" : "valid"} section`
    224    );
    225  });
    226 }
    227 
    228 var LabelUtils;
    229 var AddressMetaDataLoader, FormAutofillUtils;
    230 
    231 function autofillFieldSelector(doc) {
    232  return doc.querySelectorAll("input, select");
    233 }
    234 
    235 /**
    236 * Returns the Sync change counter for a profile storage record. Synced records
    237 * store additional metadata for tracking changes and resolving merge conflicts.
    238 * Deleting a synced record replaces the record with a tombstone.
    239 *
    240 * @param   {AutofillRecords} records
    241 *          The `AutofillRecords` instance to query.
    242 * @param   {string} guid
    243 *          The GUID of the record or tombstone.
    244 * @returns {number}
    245 *          The change counter, or -1 if the record doesn't exist or hasn't
    246 *          been synced yet.
    247 */
    248 function getSyncChangeCounter(records, guid) {
    249  let record = records._findByGUID(guid, { includeDeleted: true });
    250  if (!record) {
    251    return -1;
    252  }
    253  let sync = records._getSyncMetaData(record);
    254  if (!sync) {
    255    return -1;
    256  }
    257  return sync.changeCounter;
    258 }
    259 
    260 /**
    261 * Performs a partial deep equality check to determine if an object contains
    262 * the given fields. To ensure the object doesn't contain a property, set the
    263 * property of the `fields` object to `undefined`
    264 *
    265 * @param   {object} object
    266 *          The object to check. Unlike `ObjectUtils.deepEqual`, properties in
    267 *          `object` that are not in `fields` will be ignored.
    268 * @param   {object} fields
    269 *          The fields to match.
    270 * @returns {boolean}
    271 *          Does `object` contain `fields` with matching values?
    272 */
    273 function objectMatches(object, fields) {
    274  let actual = {};
    275  for (const key in fields) {
    276    if (!object.hasOwnProperty(key)) {
    277      if (fields[key] != undefined) {
    278        return false;
    279      }
    280    }
    281    actual[key] = object[key];
    282  }
    283  return ObjectUtils.deepEqual(actual, fields);
    284 }
    285 
    286 add_setup(async function head_initialize() {
    287  Services.prefs.setBoolPref("extensions.experiments.enabled", true);
    288  Services.prefs.setBoolPref("dom.forms.autocomplete.formautofill", true);
    289 
    290  Services.prefs.setCharPref(
    291    "extensions.formautofill.addresses.supported",
    292    "on"
    293  );
    294  Services.prefs.setCharPref(
    295    "extensions.formautofill.creditCards.supported",
    296    "on"
    297  );
    298  Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", true);
    299  Services.prefs.setBoolPref(
    300    "extensions.formautofill.creditCards.enabled",
    301    true
    302  );
    303 
    304  // Enable SCOPE_APPLICATION for builtin testing.  Default in tests is only SCOPE_PROFILE.
    305  const scopes = AddonManager.SCOPE_PROFILE | AddonManager.SCOPE_APPLICATION;
    306  Services.prefs.setIntPref("extensions.enabledScopes", scopes);
    307 
    308  // Clean up after every test.
    309  registerCleanupFunction(function head_cleanup() {
    310    Services.prefs.clearUserPref("extensions.experiments.enabled");
    311    Services.prefs.clearUserPref(
    312      "extensions.formautofill.creditCards.supported"
    313    );
    314    Services.prefs.clearUserPref("extensions.formautofill.addresses.supported");
    315    Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
    316    Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
    317    Services.prefs.clearUserPref("extensions.formautofill.addresses.enabled");
    318    Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
    319    Services.prefs.clearUserPref("extensions.enabledScopes");
    320  });
    321 
    322  AddonTestUtils.createAppInfo(
    323    "xpcshell@tests.mozilla.org",
    324    "XPCShell",
    325    "1",
    326    "1.9.2"
    327  );
    328 
    329  // Ensure formautofill builtin is installed.
    330  const builtinsConfig = await fetch(
    331    "chrome://browser/content/built_in_addons.json"
    332  ).then(res => res.json());
    333 
    334  await AddonTestUtils.overrideBuiltIns({
    335    system: [],
    336    builtins: builtinsConfig.builtins.filter(
    337      entry => entry.addon_id === EXTENSION_ID
    338    ),
    339  });
    340 
    341  await AddonTestUtils.promiseRestartManager();
    342 
    343  const addon = await AddonManager.getAddonByID(EXTENSION_ID);
    344  ok(addon, "Expect formautofill addon to be found");
    345 });
    346 
    347 let OSKeyStoreTestUtils;
    348 add_setup(async function os_key_store_setup() {
    349  ({ OSKeyStoreTestUtils } = ChromeUtils.importESModule(
    350    "resource://testing-common/OSKeyStoreTestUtils.sys.mjs"
    351  ));
    352  OSKeyStoreTestUtils.setup();
    353  registerCleanupFunction(async function cleanup() {
    354    await OSKeyStoreTestUtils.cleanup();
    355  });
    356 });