tor-browser

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

unit-entry.js (16117B)


      1 import {
      2  FakePrefs,
      3  FakensIPrefService,
      4  GlobalOverrider,
      5  FakeConsoleAPI,
      6  FakeLogger,
      7  FakeNimbusFeatures,
      8 } from "tests/unit/utils";
      9 import Adapter from "enzyme-adapter-react-16";
     10 import chaiJsonSchema from "chai-json-schema";
     11 import enzyme from "enzyme";
     12 import FxMSCommonSchema from "../../content-src/schemas/FxMSCommon.schema.json";
     13 import {
     14  MESSAGE_TYPE_LIST,
     15  MESSAGE_TYPE_HASH,
     16 } from "modules/ActorConstants.mjs";
     17 import { MESSAGING_EXPERIMENTS_DEFAULT_FEATURES } from "modules/MessagingExperimentConstants.sys.mjs";
     18 
     19 enzyme.configure({ adapter: new Adapter() });
     20 
     21 // Cause React warnings to make tests that trigger them fail
     22 const origConsoleError = console.error;
     23 console.error = function (msg, ...args) {
     24  origConsoleError.apply(console, [msg, ...args]);
     25 
     26  if (
     27    /(Invalid prop|Failed prop type|Check the render method|React Intl)/.test(
     28      msg
     29    )
     30  ) {
     31    throw new Error(msg);
     32  }
     33 };
     34 
     35 const req = require.context(".", true, /\.test\.jsx?$/);
     36 const files = req.keys();
     37 
     38 // This exposes sinon assertions to chai.assert
     39 sinon.assert.expose(assert, { prefix: "" });
     40 
     41 chai.use(chaiJsonSchema);
     42 chai.tv4.addSchema("file:///FxMSCommon.schema.json", FxMSCommonSchema);
     43 
     44 const overrider = new GlobalOverrider();
     45 
     46 const RemoteSettings = name => ({
     47  get: () => {
     48    if (name === "attachment") {
     49      return Promise.resolve([{ attachment: {} }]);
     50    }
     51    return Promise.resolve([]);
     52  },
     53  on: () => {},
     54  off: () => {},
     55 });
     56 RemoteSettings.pollChanges = () => {};
     57 
     58 class JSWindowActorParent {
     59  sendAsyncMessage(name, data) {
     60    return { name, data };
     61  }
     62 }
     63 
     64 class JSWindowActorChild {
     65  sendAsyncMessage(name, data) {
     66    return { name, data };
     67  }
     68 
     69  sendQuery(name, data) {
     70    return Promise.resolve({ name, data });
     71  }
     72 
     73  get contentWindow() {
     74    return {
     75      Promise,
     76    };
     77  }
     78 }
     79 
     80 // Detect plain object passed to lazy getter APIs, and set its prototype to
     81 // global object, and return the global object for further modification.
     82 // Returns the object if it's not plain object.
     83 //
     84 // This is a workaround to make the existing testharness and testcase keep
     85 // working even after lazy getters are moved to plain `lazy` object.
     86 const cachedPlainObject = new Set();
     87 function updateGlobalOrObject(object) {
     88  // Given this function modifies the prototype, and the following
     89  // condition doesn't meet on the second call, cache the result.
     90  if (cachedPlainObject.has(object)) {
     91    return global;
     92  }
     93 
     94  if (Object.getPrototypeOf(object).constructor.name !== "Object") {
     95    return object;
     96  }
     97 
     98  cachedPlainObject.add(object);
     99  Object.setPrototypeOf(object, global);
    100  return global;
    101 }
    102 
    103 const TEST_GLOBAL = {
    104  JSWindowActorParent,
    105  JSWindowActorChild,
    106  AboutReaderParent: {
    107    addMessageListener: (_messageName, _listener) => {},
    108    removeMessageListener: (_messageName, _listener) => {},
    109  },
    110  AboutWelcomeTelemetry: class {
    111    submitGleanPingForPing() {}
    112  },
    113  AddonManager: {
    114    getActiveAddons() {
    115      return Promise.resolve({ addons: [], fullData: false });
    116    },
    117  },
    118  AppConstants: {
    119    MOZILLA_OFFICIAL: true,
    120    MOZ_APP_VERSION: "69.0a1",
    121    isPlatformAndVersionAtMost() {
    122      return false;
    123    },
    124    platform: "win",
    125  },
    126  ASRouterPreferences: {
    127    console: new FakeConsoleAPI({
    128      maxLogLevel: "off", // set this to "debug" or "all" to get more ASRouter logging in tests
    129      prefix: "ASRouter",
    130    }),
    131  },
    132  AWScreenUtils: {
    133    evaluateTargetingAndRemoveScreens() {
    134      return true;
    135    },
    136    async removeScreens() {
    137      return true;
    138    },
    139    evaluateScreenTargeting() {
    140      return true;
    141    },
    142  },
    143  BrowserUtils: {
    144    sendToDeviceEmailsSupported() {
    145      return true;
    146    },
    147  },
    148  UpdateUtils: { getUpdateChannel() {} },
    149  BasePromiseWorker: class {
    150    constructor() {
    151      this.ExceptionHandlers = [];
    152    }
    153    post() {}
    154  },
    155  browserSearchRegion: "US",
    156  BrowserWindowTracker: { getTopWindow() {} },
    157  ChromeUtils: {
    158    defineLazyGetter(object, name, f) {
    159      updateGlobalOrObject(object)[name] = f();
    160    },
    161    defineESModuleGetters: updateGlobalOrObject,
    162    generateQI() {
    163      return {};
    164    },
    165    importESModule() {
    166      return global;
    167    },
    168  },
    169  ClientEnvironment: {
    170    get userId() {
    171      return "foo123";
    172    },
    173  },
    174  Components: {
    175    Constructor(classId) {
    176      switch (classId) {
    177        case "@mozilla.org/referrer-info;1":
    178          return function (referrerPolicy, sendReferrer, originalReferrer) {
    179            this.referrerPolicy = referrerPolicy;
    180            this.sendReferrer = sendReferrer;
    181            this.originalReferrer = originalReferrer;
    182          };
    183      }
    184      return function () {};
    185    },
    186    isSuccessCode: () => true,
    187  },
    188  ConsoleAPI: FakeConsoleAPI,
    189  // NB: These are functions/constructors
    190  // eslint-disable-next-line object-shorthand
    191  ContentSearchUIController: function () {},
    192  // eslint-disable-next-line object-shorthand
    193  ContentSearchHandoffUIController: function () {},
    194  Cc: {
    195    "@mozilla.org/browser/nav-bookmarks-service;1": {
    196      addObserver() {},
    197      getService() {
    198        return this;
    199      },
    200      removeObserver() {},
    201      SOURCES: {},
    202      TYPE_BOOKMARK: {},
    203    },
    204    "@mozilla.org/browser/nav-history-service;1": {
    205      addObserver() {},
    206      executeQuery() {},
    207      getNewQuery() {},
    208      getNewQueryOptions() {},
    209      getService() {
    210        return this;
    211      },
    212      insert() {},
    213      markPageAsTyped() {},
    214      removeObserver() {},
    215      pageFrecencyThreshold() {},
    216    },
    217    "@mozilla.org/io/string-input-stream;1": {
    218      createInstance() {
    219        return {};
    220      },
    221    },
    222    "@mozilla.org/updates/update-checker;1": { createInstance() {} },
    223    "@mozilla.org/widget/useridleservice;1": {
    224      getService() {
    225        return {
    226          idleTime: 0,
    227          addIdleObserver() {},
    228          removeIdleObserver() {},
    229        };
    230      },
    231    },
    232    "@mozilla.org/streamConverters;1": {
    233      getService() {
    234        return this;
    235      },
    236    },
    237    "@mozilla.org/network/stream-loader;1": {
    238      createInstance() {
    239        return {};
    240      },
    241    },
    242  },
    243  Ci: {
    244    nsICryptoHash: {},
    245    nsIReferrerInfo: { UNSAFE_URL: 5 },
    246    nsITimer: { TYPE_ONE_SHOT: 1 },
    247    nsIWebProgressListener: { LOCATION_CHANGE_SAME_DOCUMENT: 1 },
    248    nsIDOMWindow: Object,
    249    nsITrackingDBService: {
    250      TRACKERS_ID: 1,
    251      TRACKING_COOKIES_ID: 2,
    252      CRYPTOMINERS_ID: 3,
    253      FINGERPRINTERS_ID: 4,
    254      SOCIAL_ID: 5,
    255    },
    256    nsICookieBannerService: {
    257      MODE_DISABLED: 0,
    258      MODE_REJECT: 1,
    259      MODE_REJECT_OR_ACCEPT: 2,
    260      MODE_UNSET: 3,
    261    },
    262  },
    263  Cu: {
    264    importGlobalProperties() {},
    265    now: () => window.performance.now(),
    266    cloneInto: o => JSON.parse(JSON.stringify(o)),
    267    isInAutomation: true,
    268  },
    269  console: {
    270    ...console,
    271    error() {},
    272  },
    273  dump() {},
    274  EveryWindow: {
    275    registerCallback: (_id, _init, _uninit) => {},
    276    unregisterCallback: _id => {},
    277  },
    278  setTimeout: window.setTimeout.bind(window),
    279  clearTimeout: window.clearTimeout.bind(window),
    280  fetch() {},
    281  // eslint-disable-next-line object-shorthand
    282  Image: function () {}, // NB: This is a function/constructor
    283  IOUtils: {
    284    writeJSON() {
    285      return Promise.resolve(0);
    286    },
    287    readJSON() {
    288      return Promise.resolve({});
    289    },
    290    read() {
    291      return Promise.resolve(new Uint8Array());
    292    },
    293    makeDirectory() {
    294      return Promise.resolve(0);
    295    },
    296    write() {
    297      return Promise.resolve(0);
    298    },
    299    exists() {
    300      return Promise.resolve(0);
    301    },
    302    remove() {
    303      return Promise.resolve(0);
    304    },
    305    stat() {
    306      return Promise.resolve(0);
    307    },
    308  },
    309  NewTabUtils: {
    310    activityStreamProvider: {
    311      getTopFrecentSites: () => [],
    312      executePlacesQuery: async (sql, options) => ({ sql, options }),
    313    },
    314  },
    315  OS: {
    316    File: {
    317      writeAtomic() {},
    318      makeDir() {},
    319      stat() {},
    320      Error: {},
    321      read() {},
    322      exists() {},
    323      remove() {},
    324      removeEmptyDir() {},
    325    },
    326    Path: {
    327      join() {
    328        return "/";
    329      },
    330    },
    331    Constants: {
    332      Path: {
    333        localProfileDir: "/",
    334      },
    335    },
    336  },
    337  PathUtils: {
    338    join(...parts) {
    339      return parts[parts.length - 1];
    340    },
    341    joinRelative(...parts) {
    342      return parts[parts.length - 1];
    343    },
    344    getProfileDir() {
    345      return Promise.resolve("/");
    346    },
    347    getLocalProfileDir() {
    348      return Promise.resolve("/");
    349    },
    350    toFileURI(path) {
    351      return `file://${path}`;
    352    },
    353  },
    354  PlacesUtils: {
    355    get bookmarks() {
    356      return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-bookmarks-service;1"];
    357    },
    358    get history() {
    359      return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-history-service;1"];
    360    },
    361    observers: {
    362      addListener() {},
    363      removeListener() {},
    364    },
    365  },
    366  Preferences: FakePrefs,
    367  PrivateBrowsingUtils: {
    368    isBrowserPrivate: () => false,
    369    isWindowPrivate: () => false,
    370    permanentPrivateBrowsing: false,
    371  },
    372  DownloadsViewUI: {
    373    getDisplayName: () => "filename.ext",
    374    getSizeWithUnits: () => "1.5 MB",
    375  },
    376  FileUtils: {
    377    // eslint-disable-next-line object-shorthand
    378    File: function () {}, // NB: This is a function/constructor
    379  },
    380  Region: {
    381    home: "US",
    382    REGION_TOPIC: "browser-region-updated",
    383  },
    384  Services: {
    385    sysinfo: {
    386      getProperty() {
    387        return false;
    388      },
    389    },
    390    dirsvc: {
    391      get: () => ({ parent: { parent: { path: "appPath" } } }),
    392    },
    393    env: {
    394      get: () => undefined,
    395      set: () => undefined,
    396      exists: () => false,
    397    },
    398    locale: {
    399      get appLocaleAsBCP47() {
    400        return "en-US";
    401      },
    402      negotiateLanguages() {},
    403    },
    404    urlFormatter: { formatURL: str => str, formatURLPref: str => str },
    405    mm: {
    406      addMessageListener: (_msg, _cb) => this.receiveMessage(),
    407      removeMessageListener() {},
    408    },
    409    obs: {
    410      addObserver() {},
    411      removeObserver() {},
    412      notifyObservers() {},
    413    },
    414    uuid: {
    415      generateUUID() {
    416        return "{foo-123-foo}";
    417      },
    418    },
    419    console: { logStringMessage: () => {} },
    420    prefs: new FakensIPrefService(),
    421    tm: {
    422      dispatchToMainThread: cb => cb(),
    423      idleDispatchToMainThread: cb => cb(),
    424    },
    425    eTLD: {
    426      getBaseDomain({ spec }) {
    427        return spec.match(/\/([^/]+)/)[1];
    428      },
    429      getBaseDomainFromHost(host) {
    430        return host.match(/.*?(\w+\.\w+)$/)[1];
    431      },
    432      getPublicSuffix() {},
    433    },
    434    io: {
    435      newURI: spec => ({
    436        mutate: () => ({
    437          setRef: ref => ({
    438            finalize: () => ({
    439              ref,
    440              spec,
    441            }),
    442          }),
    443        }),
    444        spec,
    445      }),
    446    },
    447    search: {
    448      init() {
    449        return Promise.resolve();
    450      },
    451      getVisibleEngines: () =>
    452        Promise.resolve([{ identifier: "google" }, { identifier: "bing" }]),
    453      defaultEngine: {
    454        identifier: "google",
    455        aliases: ["@google"],
    456      },
    457      defaultPrivateEngine: {
    458        identifier: "bing",
    459        aliases: ["@bing"],
    460      },
    461      getEngineByAlias: async () => null,
    462    },
    463    scriptSecurityManager: {
    464      createNullPrincipal() {},
    465      getSystemPrincipal() {},
    466    },
    467    wm: {
    468      getMostRecentWindow: () => window,
    469      getMostRecentBrowserWindow: () => window,
    470      getEnumerator: () => [],
    471    },
    472    ww: { registerNotification() {}, unregisterNotification() {} },
    473    appinfo: { appBuildID: "20180710100040", version: "69.0a1" },
    474    scriptloader: { loadSubScript: () => {} },
    475    startup: {
    476      getStartupInfo() {
    477        return {
    478          process: {
    479            getTime() {
    480              return 1588010448000;
    481            },
    482          },
    483        };
    484      },
    485    },
    486  },
    487  XPCOMUtils: {
    488    declareLazy: declaration => {
    489      Object.entries(declaration).forEach(([key, value]) => {
    490        if (typeof value === "function") {
    491          updateGlobalOrObject(global)[key] = value();
    492        } else if (typeof value === "object" && value.pref) {
    493          updateGlobalOrObject(global)[key] = value.default;
    494        }
    495      });
    496      return global;
    497    },
    498    defineLazyGlobalGetters: updateGlobalOrObject,
    499    defineLazyServiceGetter: updateGlobalOrObject,
    500    defineLazyServiceGetters: updateGlobalOrObject,
    501    defineLazyPreferenceGetter(object, name, _pref, defaultValue = "") {
    502      updateGlobalOrObject(object)[name] = defaultValue;
    503    },
    504    generateQI() {
    505      return {};
    506    },
    507  },
    508  ShellService: {
    509    doesAppNeedPin: () => false,
    510    isDefaultBrowser: () => true,
    511  },
    512  FilterExpressions: {
    513    eval() {
    514      return Promise.resolve(false);
    515    },
    516  },
    517  RemoteSettings,
    518  Localization: class {
    519    async formatMessages(stringsIds) {
    520      return Promise.resolve(
    521        stringsIds.map(({ id, args }) => ({ value: { string_id: id, args } }))
    522      );
    523    }
    524    async formatValue(stringId) {
    525      return Promise.resolve(stringId);
    526    }
    527  },
    528  FxAccountsConfig: {
    529    promiseConnectAccountURI(id) {
    530      return Promise.resolve(id);
    531    },
    532  },
    533  FX_MONITOR_OAUTH_CLIENT_ID: "fake_client_id",
    534  ExperimentAPI: {},
    535  FeatureCalloutBroker: {
    536    showFeatureCallout() {},
    537  },
    538  NimbusFeatures: FakeNimbusFeatures([
    539    ...MESSAGING_EXPERIMENTS_DEFAULT_FEATURES,
    540    "glean",
    541    "newtab",
    542    "pocketNewtab",
    543    "cookieBannerHandling",
    544  ]),
    545  TelemetryEnvironment: {
    546    setExperimentActive() {},
    547    currentEnvironment: {
    548      profile: {
    549        creationDate: 16587,
    550      },
    551      settings: {},
    552    },
    553  },
    554  Sampling: {
    555    ratioSample(_seed, _ratios) {
    556      return Promise.resolve(0);
    557    },
    558  },
    559  BrowserHandler: {
    560    get kiosk() {
    561      return false;
    562    },
    563  },
    564  TelemetrySession: {
    565    getMetadata(reason) {
    566      return {
    567        reason,
    568        sessionId: "fake_session_id",
    569      };
    570    },
    571  },
    572  PageThumbs: {
    573    addExpirationFilter() {},
    574    removeExpirationFilter() {},
    575  },
    576  Logger: FakeLogger,
    577  getFxAccountsSingleton() {},
    578  AboutNewTab: {},
    579  Glean: {
    580    messagingExperiments: {
    581      reachCfr: {
    582        record() {},
    583      },
    584      reachFxmsMessage15: {
    585        record() {},
    586      },
    587    },
    588    messagingSystem: {
    589      messageRequestTime: {
    590        start() {},
    591        stopAndAccumulate() {},
    592      },
    593    },
    594    newtab: {
    595      opened: {
    596        record() {},
    597      },
    598      closed: {
    599        record() {},
    600      },
    601      locale: {
    602        set() {},
    603      },
    604      newtabCategory: {
    605        set() {},
    606      },
    607      homepageCategory: {
    608        set() {},
    609      },
    610      blockedSponsors: {
    611        set() {},
    612      },
    613      sovAllocation: {
    614        set() {},
    615      },
    616    },
    617    newtabSearch: {
    618      enabled: {
    619        set() {},
    620      },
    621    },
    622    pocket: {
    623      enabled: {
    624        set() {},
    625      },
    626      impression: {
    627        record() {},
    628      },
    629      isSignedIn: {
    630        set() {},
    631      },
    632      sponsoredStoriesEnabled: {
    633        set() {},
    634      },
    635      click: {
    636        record() {},
    637      },
    638      save: {
    639        record() {},
    640      },
    641      topicClick: {
    642        record() {},
    643      },
    644    },
    645    topsites: {
    646      enabled: {
    647        set() {},
    648      },
    649      sponsoredEnabled: {
    650        set() {},
    651      },
    652      impression: {
    653        record() {},
    654      },
    655      click: {
    656        record() {},
    657      },
    658      rows: {
    659        set() {},
    660      },
    661      showPrivacyClick: {
    662        record() {},
    663      },
    664      dismiss: {
    665        record() {},
    666      },
    667      prefChanged: {
    668        record() {},
    669      },
    670    },
    671    topSites: {
    672      pingType: {
    673        set() {},
    674      },
    675      position: {
    676        set() {},
    677      },
    678      source: {
    679        set() {},
    680      },
    681      tileId: {
    682        set() {},
    683      },
    684      reportingUrl: {
    685        set() {},
    686      },
    687      advertiser: {
    688        set() {},
    689      },
    690      contextId: {
    691        set() {},
    692      },
    693    },
    694  },
    695  GleanPings: {
    696    newtab: {
    697      submit() {},
    698    },
    699    topSites: {
    700      submit() {},
    701    },
    702  },
    703  Utils: {
    704    SERVER_URL: "bogus://foo",
    705  },
    706 
    707  MESSAGE_TYPE_LIST,
    708  MESSAGE_TYPE_HASH,
    709 };
    710 overrider.set(TEST_GLOBAL);
    711 
    712 describe("asrouter", () => {
    713  after(() => overrider.restore());
    714  console.log(
    715    "Loading files from unit-entry.js (msg should show once - bug 1967579)"
    716  );
    717  files.forEach(file => req(file));
    718 });