tor-browser

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

unit-entry.js (15885B)


      1 import {
      2  EventEmitter,
      3  FakePrefs,
      4  FakensIPrefService,
      5  GlobalOverrider,
      6  FakeConsoleAPI,
      7  FakeLogger,
      8  FakeNimbusFeatures,
      9 } from "test/unit/utils";
     10 import Adapter from "enzyme-adapter-react-16";
     11 import { chaiAssertions } from "test/schemas/pings";
     12 import enzyme from "enzyme";
     13 
     14 enzyme.configure({ adapter: new Adapter() });
     15 
     16 // Cause React warnings to make tests that trigger them fail
     17 const origConsoleError = console.error;
     18 console.error = function (msg, ...args) {
     19  origConsoleError.apply(console, [msg, ...args]);
     20 
     21  if (
     22    /(Invalid prop|Failed prop type|Check the render method|React Intl)/.test(
     23      msg
     24    )
     25  ) {
     26    throw new Error(msg);
     27  }
     28 };
     29 
     30 const req = require.context(".", true, /\.test\.jsx?$/);
     31 const files = req.keys();
     32 
     33 // This exposes sinon assertions to chai.assert
     34 sinon.assert.expose(assert, { prefix: "" });
     35 
     36 chai.use(chaiAssertions);
     37 
     38 const overrider = new GlobalOverrider();
     39 
     40 const RemoteSettings = name => ({
     41  get: () => {
     42    if (name === "attachment") {
     43      return Promise.resolve([{ attachment: {} }]);
     44    }
     45    return Promise.resolve([]);
     46  },
     47  on: () => {},
     48  off: () => {},
     49 });
     50 RemoteSettings.pollChanges = () => {};
     51 
     52 class JSWindowActorParent {
     53  sendAsyncMessage(name, data) {
     54    return { name, data };
     55  }
     56 }
     57 
     58 class JSWindowActorChild {
     59  sendAsyncMessage(name, data) {
     60    return { name, data };
     61  }
     62 
     63  sendQuery(name, data) {
     64    return Promise.resolve({ name, data });
     65  }
     66 
     67  get contentWindow() {
     68    return {
     69      Promise,
     70    };
     71  }
     72 }
     73 
     74 class NewTabContentPing {
     75  recordEvent() {}
     76  scheduleSubmission() {}
     77  uninit() {}
     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  BrowserUtils: {
    127    sendToDeviceEmailsSupported() {
    128      return true;
    129    },
    130  },
    131  UpdateUtils: { getUpdateChannel() {} },
    132  BasePromiseWorker: class {
    133    constructor() {
    134      this.ExceptionHandlers = [];
    135    }
    136    post() {}
    137  },
    138  browserSearchRegion: "US",
    139  BrowserWindowTracker: { getTopWindow() {} },
    140  ChromeUtils: {
    141    defineLazyGetter(object, name, f) {
    142      updateGlobalOrObject(object)[name] = f();
    143    },
    144    defineESModuleGetters: updateGlobalOrObject,
    145    generateQI() {
    146      return {};
    147    },
    148    importESModule() {
    149      return global;
    150    },
    151  },
    152  ClientEnvironment: {
    153    get userId() {
    154      return "foo123";
    155    },
    156  },
    157  Components: {
    158    Constructor(classId) {
    159      switch (classId) {
    160        case "@mozilla.org/referrer-info;1":
    161          return function (referrerPolicy, sendReferrer, originalReferrer) {
    162            this.referrerPolicy = referrerPolicy;
    163            this.sendReferrer = sendReferrer;
    164            this.originalReferrer = originalReferrer;
    165          };
    166      }
    167      return function () {};
    168    },
    169    isSuccessCode: () => true,
    170  },
    171  ConsoleAPI: FakeConsoleAPI,
    172  // NB: These are functions/constructors
    173  // eslint-disable-next-line object-shorthand
    174  ContentSearchUIController: function () {},
    175  // eslint-disable-next-line object-shorthand
    176  ContentSearchHandoffUIController: function () {},
    177  ContextId: {
    178    request: () => "ContextId",
    179  },
    180  Cc: {
    181    "@mozilla.org/browser/nav-bookmarks-service;1": {
    182      addObserver() {},
    183      getService() {
    184        return this;
    185      },
    186      removeObserver() {},
    187      SOURCES: {},
    188      TYPE_BOOKMARK: {},
    189    },
    190    "@mozilla.org/browser/nav-history-service;1": {
    191      addObserver() {},
    192      executeQuery() {},
    193      getNewQuery() {},
    194      getNewQueryOptions() {},
    195      getService() {
    196        return this;
    197      },
    198      insert() {},
    199      markPageAsTyped() {},
    200      removeObserver() {},
    201      pageFrecencyThreshold() {},
    202    },
    203    "@mozilla.org/io/string-input-stream;1": {
    204      createInstance() {
    205        return {};
    206      },
    207    },
    208    "@mozilla.org/updates/update-checker;1": { createInstance() {} },
    209    "@mozilla.org/widget/useridleservice;1": {
    210      getService() {
    211        return {
    212          idleTime: 0,
    213          addIdleObserver() {},
    214          removeIdleObserver() {},
    215        };
    216      },
    217    },
    218    "@mozilla.org/streamConverters;1": {
    219      getService() {
    220        return this;
    221      },
    222    },
    223    "@mozilla.org/network/stream-loader;1": {
    224      createInstance() {
    225        return {};
    226      },
    227    },
    228    "@mozilla.org/network/protocol;1?name=http": {
    229      getService() {
    230        return this;
    231      },
    232    },
    233  },
    234  Ci: {
    235    nsICryptoHash: {},
    236    nsIReferrerInfo: { UNSAFE_URL: 5 },
    237    nsITimer: { TYPE_ONE_SHOT: 1 },
    238    nsIWebProgressListener: { LOCATION_CHANGE_SAME_DOCUMENT: 1 },
    239    nsIDOMWindow: Object,
    240    nsITrackingDBService: {
    241      TRACKERS_ID: 1,
    242      TRACKING_COOKIES_ID: 2,
    243      CRYPTOMINERS_ID: 3,
    244      FINGERPRINTERS_ID: 4,
    245      SOCIAL_ID: 5,
    246    },
    247    nsICookieBannerService: {
    248      MODE_DISABLED: 0,
    249      MODE_REJECT: 1,
    250      MODE_REJECT_OR_ACCEPT: 2,
    251      MODE_UNSET: 3,
    252    },
    253    nsIProtocolProxyChannelFilter: {},
    254  },
    255  Cu: {
    256    importGlobalProperties() {},
    257    now: () => window.performance.now(),
    258    cloneInto: o => JSON.parse(JSON.stringify(o)),
    259  },
    260  console: {
    261    ...console,
    262    error() {},
    263  },
    264  dump() {},
    265  EveryWindow: {
    266    registerCallback: (_id, _init, _uninit) => {},
    267    unregisterCallback: _id => {},
    268  },
    269  setTimeout: window.setTimeout.bind(window),
    270  clearTimeout: window.clearTimeout.bind(window),
    271  fetch() {},
    272  // eslint-disable-next-line object-shorthand
    273  Image: function () {}, // NB: This is a function/constructor
    274  IOUtils: {
    275    writeJSON() {
    276      return Promise.resolve(0);
    277    },
    278    readJSON() {
    279      return Promise.resolve({});
    280    },
    281    read() {
    282      return Promise.resolve(new Uint8Array());
    283    },
    284    makeDirectory() {
    285      return Promise.resolve(0);
    286    },
    287    write() {
    288      return Promise.resolve(0);
    289    },
    290    exists() {
    291      return Promise.resolve(0);
    292    },
    293    remove() {
    294      return Promise.resolve(0);
    295    },
    296    stat() {
    297      return Promise.resolve(0);
    298    },
    299  },
    300  NewTabUtils: {
    301    activityStreamProvider: {
    302      getTopFrecentSites: () => [],
    303      executePlacesQuery: async (sql, options) => ({ sql, options }),
    304    },
    305    shortHostname() {},
    306  },
    307  OS: {
    308    File: {
    309      writeAtomic() {},
    310      makeDir() {},
    311      stat() {},
    312      Error: {},
    313      read() {},
    314      exists() {},
    315      remove() {},
    316      removeEmptyDir() {},
    317    },
    318    Path: {
    319      join() {
    320        return "/";
    321      },
    322    },
    323    Constants: {
    324      Path: {
    325        localProfileDir: "/",
    326      },
    327    },
    328  },
    329  PathUtils: {
    330    join(...parts) {
    331      return parts[parts.length - 1];
    332    },
    333    joinRelative(...parts) {
    334      return parts[parts.length - 1];
    335    },
    336    getProfileDir() {
    337      return Promise.resolve("/");
    338    },
    339    getLocalProfileDir() {
    340      return Promise.resolve("/");
    341    },
    342  },
    343  PlacesUtils: {
    344    get bookmarks() {
    345      return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-bookmarks-service;1"];
    346    },
    347    get history() {
    348      return TEST_GLOBAL.Cc["@mozilla.org/browser/nav-history-service;1"];
    349    },
    350    observers: {
    351      addListener() {},
    352      removeListener() {},
    353    },
    354  },
    355  Preferences: FakePrefs,
    356  PrivateBrowsingUtils: {
    357    isBrowserPrivate: () => false,
    358    isWindowPrivate: () => false,
    359    permanentPrivateBrowsing: false,
    360  },
    361  DownloadsViewUI: {
    362    getDisplayName: () => "filename.ext",
    363    getSizeWithUnits: () => "1.5 MB",
    364  },
    365  FileUtils: {
    366    // eslint-disable-next-line object-shorthand
    367    File: function () {}, // NB: This is a function/constructor
    368  },
    369  Region: {
    370    home: "US",
    371    REGION_TOPIC: "browser-region-updated",
    372  },
    373  Services: {
    374    dirsvc: {
    375      get: () => ({ parent: { parent: { path: "appPath" } } }),
    376    },
    377    env: {
    378      set: () => undefined,
    379    },
    380    locale: {
    381      get appLocaleAsBCP47() {
    382        return "en-US";
    383      },
    384      negotiateLanguages() {},
    385    },
    386    urlFormatter: { formatURL: str => str, formatURLPref: str => str },
    387    mm: {
    388      addMessageListener: (_msg, _cb) => this.receiveMessage(),
    389      removeMessageListener() {},
    390    },
    391    obs: {
    392      addObserver() {},
    393      removeObserver() {},
    394      notifyObservers() {},
    395    },
    396    uuid: {
    397      generateUUID() {
    398        return "{foo-123-foo}";
    399      },
    400    },
    401    console: { logStringMessage: () => {} },
    402    prefs: new FakensIPrefService(),
    403    tm: {
    404      dispatchToMainThread: cb => cb(),
    405      idleDispatchToMainThread: cb => cb(),
    406    },
    407    eTLD: {
    408      getBaseDomain({ spec }) {
    409        return spec.match(/\/([^/]+)/)[1];
    410      },
    411      getBaseDomainFromHost(host) {
    412        return host.match(/.*?(\w+\.\w+)$/)[1];
    413      },
    414      getPublicSuffix() {},
    415    },
    416    io: {
    417      newURI: spec => ({
    418        mutate: () => ({
    419          setRef: ref => ({
    420            finalize: () => ({
    421              ref,
    422              spec,
    423              schemeIs: scheme => spec.startsWith(scheme),
    424            }),
    425          }),
    426        }),
    427        spec,
    428      }),
    429    },
    430    search: {
    431      init() {
    432        return Promise.resolve();
    433      },
    434      getVisibleEngines: () =>
    435        Promise.resolve([{ identifier: "google" }, { identifier: "bing" }]),
    436      defaultEngine: {
    437        identifier: "google",
    438        aliases: ["@google"],
    439      },
    440      defaultPrivateEngine: {
    441        identifier: "bing",
    442        aliases: ["@bing"],
    443      },
    444      getEngineByAlias: async () => null,
    445    },
    446    scriptSecurityManager: {
    447      createNullPrincipal() {},
    448      getSystemPrincipal() {},
    449    },
    450    vc: {
    451      compare(a, b) {
    452        // Rather than re-write Services.vc.compare completely, do
    453        // a simple comparison of the major version.
    454        // This means this function will give the wrong output for differences
    455        // in minor versions, but should be sufficient for unit tests.
    456        let majorA = parseInt(a, 10);
    457        let majorB = parseInt(b, 10);
    458        if (majorA === majorB) {
    459          return 0;
    460        }
    461        return majorA > majorB ? 1 : -1;
    462      },
    463    },
    464    wm: {
    465      getMostRecentWindow: () => window,
    466      getMostRecentBrowserWindow: () => window,
    467      getEnumerator: () => [],
    468    },
    469    ww: { registerNotification() {}, unregisterNotification() {} },
    470    appinfo: { appBuildID: "20180710100040", version: "69.0a1" },
    471    scriptloader: { loadSubScript: () => {} },
    472    startup: {
    473      getStartupInfo() {
    474        return {
    475          process: {
    476            getTime() {
    477              return 1588010448000;
    478            },
    479          },
    480        };
    481      },
    482    },
    483  },
    484  XPCOMUtils: {
    485    defineLazyGlobalGetters: updateGlobalOrObject,
    486    defineLazyServiceGetter: updateGlobalOrObject,
    487    defineLazyServiceGetters: updateGlobalOrObject,
    488    defineLazyPreferenceGetter(object, name) {
    489      updateGlobalOrObject(object)[name] = "";
    490    },
    491    generateQI() {
    492      return {};
    493    },
    494  },
    495  EventEmitter,
    496  ShellService: {
    497    doesAppNeedPin: () => false,
    498    isDefaultBrowser: () => true,
    499  },
    500  FilterExpressions: {
    501    eval() {
    502      return Promise.resolve(false);
    503    },
    504  },
    505  RemoteSettings,
    506  Localization: class {
    507    async formatMessages(stringsIds) {
    508      return Promise.resolve(
    509        stringsIds.map(({ id, args }) => ({ value: { string_id: id, args } }))
    510      );
    511    }
    512    async formatValue(stringId) {
    513      return Promise.resolve(stringId);
    514    }
    515  },
    516  FxAccountsConfig: {
    517    promiseConnectAccountURI(id) {
    518      return Promise.resolve(id);
    519    },
    520  },
    521  FX_MONITOR_OAUTH_CLIENT_ID: "fake_client_id",
    522  ExperimentAPI: {},
    523  NimbusFeatures: FakeNimbusFeatures([
    524    "glean",
    525    "newtab",
    526    "newtabTrainhop",
    527    "pocketNewtab",
    528    "newtabSmartShortcuts",
    529    "newtabInferredPersonalization",
    530    "newtabWidgets",
    531    "newtabOhttpImages",
    532    "cookieBannerHandling",
    533  ]),
    534  TelemetryEnvironment: {
    535    setExperimentActive() {},
    536    currentEnvironment: {
    537      profile: {
    538        creationDate: 16587,
    539      },
    540      settings: {},
    541    },
    542  },
    543  Sampling: {
    544    ratioSample(_seed, _ratios) {
    545      return Promise.resolve(0);
    546    },
    547  },
    548  BrowserHandler: {
    549    get kiosk() {
    550      return false;
    551    },
    552  },
    553  TelemetrySession: {
    554    getMetadata(reason) {
    555      return {
    556        reason,
    557        sessionId: "fake_session_id",
    558      };
    559    },
    560  },
    561  PageThumbs: {
    562    addExpirationFilter() {},
    563    removeExpirationFilter() {},
    564  },
    565  Logger: FakeLogger,
    566  LinksCache: class {},
    567  FaviconFeed: class {},
    568 
    569  getFxAccountsSingleton() {},
    570  AboutNewTab: {},
    571  Glean: {
    572    activityStream: {
    573      eventClick: {
    574        record() {},
    575      },
    576      endSession: {
    577        record() {},
    578      },
    579    },
    580    newtab: {
    581      opened: {
    582        record() {},
    583      },
    584      closed: {
    585        record() {},
    586      },
    587      locale: {
    588        set() {},
    589      },
    590      newtabCategory: {
    591        set() {},
    592      },
    593      homepageCategory: {
    594        set() {},
    595      },
    596      blockedSponsors: {
    597        set() {},
    598      },
    599      sovAllocation: {
    600        set() {},
    601      },
    602    },
    603    newtabSearch: {
    604      enabled: {
    605        set() {},
    606      },
    607    },
    608    newtabHandoffPreference: {
    609      enabled: {
    610        set() {},
    611      },
    612    },
    613    pocket: {
    614      enabled: {
    615        set() {},
    616      },
    617      impression: {
    618        record() {},
    619      },
    620      isSignedIn: {
    621        set() {},
    622      },
    623      sponsoredStoriesEnabled: {
    624        set() {},
    625      },
    626      click: {
    627        record() {},
    628      },
    629      save: {
    630        record() {},
    631      },
    632      topicClick: {
    633        record() {},
    634      },
    635      shim: {
    636        set() {},
    637      },
    638    },
    639    topsites: {
    640      enabled: {
    641        set() {},
    642      },
    643      sponsoredEnabled: {
    644        set() {},
    645      },
    646      impression: {
    647        record() {},
    648      },
    649      click: {
    650        record() {},
    651      },
    652      rows: {
    653        set() {},
    654      },
    655      showPrivacyClick: {
    656        record() {},
    657      },
    658      dismiss: {
    659        record() {},
    660      },
    661      prefChanged: {
    662        record() {},
    663      },
    664      sponsoredTilesConfigured: {
    665        set() {},
    666      },
    667      sponsoredTilesReceived: {
    668        set() {},
    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    spoc: {
    703      submit() {},
    704    },
    705  },
    706  userAgent: "",
    707  Utils: {
    708    SERVER_URL: "bogus://foo",
    709  },
    710  NewTabContentPing,
    711  ProxyService: {
    712    registerChannelFilter() {},
    713    unregisterChannelFilter() {},
    714  },
    715 };
    716 overrider.set(TEST_GLOBAL);
    717 
    718 describe("activity-stream", () => {
    719  after(() => overrider.restore());
    720  files.forEach(file => req(file));
    721 });