tor-browser

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

MockAlertsService.js (6797B)


      1 "use strict";
      2 
      3 /* exported MockAlertsService */
      4 
      5 function mockServicesChromeScript() {
      6  /* eslint-env mozilla/chrome-script */
      7 
      8  const MOCK_ALERTS_CID = Components.ID(
      9    "{48068bc2-40ab-4904-8afd-4cdfb3a385f3}"
     10  );
     11  const SYSTEM_CID = Components.ID("{a0ccaaf8-09da-44d8-b250-9ac3e93c8117}");
     12  const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
     13 
     14  const { setTimeout } = ChromeUtils.importESModule(
     15    "resource://gre/modules/Timer.sys.mjs"
     16  );
     17  const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
     18 
     19  let activeNotifications = Object.create(null);
     20 
     21  let throwHistory = false;
     22  let history = [];
     23 
     24  const mockAlertsService = {
     25    showAlert(alert, listener) {
     26      activeNotifications[alert.name] = {
     27        listener,
     28        cookie: alert.cookie,
     29        title: alert.title,
     30      };
     31 
     32      // fake async alert show event
     33      if (listener) {
     34        setTimeout(() => {
     35          if (this.mockFailure) {
     36            listener.observe(null, "alertfinished", alert.cookie);
     37            return;
     38          }
     39 
     40          listener.observe(null, "alertshow", alert.cookie);
     41          if (this.autoClick) {
     42            let subject;
     43            if (typeof this.autoClick === "string") {
     44              subject = alert.actions.filter(
     45                ac => ac.action === this.autoClick
     46              )[0];
     47            }
     48            listener.observe(subject, "alertclickcallback", alert.cookie);
     49          }
     50        }, 100);
     51      }
     52    },
     53 
     54    closeAlert(name) {
     55      let alertNotification = activeNotifications[name];
     56      if (alertNotification) {
     57        if (alertNotification.listener) {
     58          alertNotification.listener.observe(
     59            null,
     60            "alertfinished",
     61            alertNotification.cookie
     62          );
     63        }
     64        delete activeNotifications[name];
     65      }
     66    },
     67 
     68    getHistory() {
     69      if (throwHistory) {
     70        throw new Error("no history, sorry");
     71      }
     72      return history;
     73    },
     74 
     75    QueryInterface: ChromeUtils.generateQI(["nsIAlertsService"]),
     76 
     77    createInstance(iid) {
     78      return this.QueryInterface(iid);
     79    },
     80 
     81    // Some existing mochitests expect the mock to click the notification.
     82    // The state here is specific to each caller as register() uses
     83    // SpecialPowers.loadChromeScript that ensures evaluating on each call
     84    // without caching objects.
     85    autoClick: false,
     86  };
     87 
     88  registrar.registerFactory(
     89    MOCK_ALERTS_CID,
     90    "alerts service",
     91    ALERTS_SERVICE_CONTRACT_ID,
     92    mockAlertsService
     93  );
     94 
     95  function clickNotifications(doClose) {
     96    // Until we need to close a specific notification, just click them all.
     97    for (let [name, notification] of Object.entries(activeNotifications)) {
     98      let { listener, cookie } = notification;
     99      listener.observe(null, "alertclickcallback", cookie);
    100      if (doClose) {
    101        mockAlertsService.closeAlert(name);
    102      }
    103    }
    104  }
    105 
    106  function closeAllNotifications() {
    107    for (let alertName of Object.keys(activeNotifications)) {
    108      mockAlertsService.closeAlert(alertName);
    109    }
    110  }
    111 
    112  const { addMessageListener, sendAsyncMessage } = this;
    113 
    114  addMessageListener("mock-alert-service:unregister", () => {
    115    closeAllNotifications();
    116    activeNotifications = null;
    117    registrar.unregisterFactory(MOCK_ALERTS_CID, mockAlertsService);
    118    // Revive the system one
    119    registrar.registerFactory(SYSTEM_CID, "", ALERTS_SERVICE_CONTRACT_ID, null);
    120    sendAsyncMessage("mock-alert-service:unregistered");
    121  });
    122 
    123  addMessageListener(
    124    "mock-alert-service:click-notifications",
    125    clickNotifications
    126  );
    127 
    128  addMessageListener(
    129    "mock-alert-service:close-notifications",
    130    closeAllNotifications
    131  );
    132 
    133  addMessageListener("mock-alert-service:close-notification", alertName =>
    134    mockAlertsService.closeAlert(alertName)
    135  );
    136 
    137  addMessageListener("mock-alert-service:enable-autoclick", action => {
    138    mockAlertsService.autoClick = action || true;
    139  });
    140 
    141  addMessageListener("mock-alert-service:mock-failure", action => {
    142    mockAlertsService.mockFailure = action || true;
    143  });
    144 
    145  addMessageListener("mock-alert-service:get-notification-ids", () =>
    146    Object.keys(activeNotifications)
    147  );
    148 
    149  addMessageListener("mock-alert-service:set-history", value => {
    150    history = value;
    151  });
    152 
    153  addMessageListener("mock-alert-service:set-throw-history", value => {
    154    throwHistory = value;
    155  });
    156 
    157  sendAsyncMessage("mock-alert-service:registered");
    158 }
    159 
    160 const MockAlertsService = {
    161  async register() {
    162    if (this._chromeScript) {
    163      throw new Error("MockAlertsService already registered");
    164    }
    165    this._chromeScript = SpecialPowers.loadChromeScript(
    166      mockServicesChromeScript
    167    );
    168    // Make sure every registration will unregister automatically at test end
    169    SimpleTest.registerCleanupFunction(async () => {
    170      await MockAlertsService.unregister();
    171    });
    172    await this._chromeScript.promiseOneMessage("mock-alert-service:registered");
    173  },
    174  async unregister() {
    175    if (!this._chromeScript) {
    176      throw new Error("MockAlertsService not registered");
    177    }
    178    this._chromeScript.sendAsyncMessage("mock-alert-service:unregister");
    179    return this._chromeScript
    180      .promiseOneMessage("mock-alert-service:unregistered")
    181      .then(() => {
    182        this._chromeScript.destroy();
    183        this._chromeScript = null;
    184      });
    185  },
    186  async clickNotifications() {
    187    // Most implementations of the nsIAlertsService automatically close upon click.
    188    await this._chromeScript.sendQuery(
    189      "mock-alert-service:click-notifications",
    190      true
    191    );
    192  },
    193  async clickNotificationsWithoutClose() {
    194    // The implementation on macOS does not automatically close the notification.
    195    await this._chromeScript.sendQuery(
    196      "mock-alert-service:click-notifications",
    197      false
    198    );
    199  },
    200  async closeNotifications() {
    201    await this._chromeScript.sendQuery(
    202      "mock-alert-service:close-notifications"
    203    );
    204  },
    205  async closeNotification(alertName) {
    206    await this._chromeScript.sendQuery(
    207      "mock-alert-service:close-notification",
    208      alertName
    209    );
    210  },
    211  async enableAutoClick(action) {
    212    await this._chromeScript.sendQuery(
    213      "mock-alert-service:enable-autoclick",
    214      action
    215    );
    216  },
    217  async mockFailure(action) {
    218    await this._chromeScript.sendQuery(
    219      "mock-alert-service:mock-failure",
    220      action
    221    );
    222  },
    223  async getNotificationIds() {
    224    return await this._chromeScript.sendQuery(
    225      "mock-alert-service:get-notification-ids"
    226    );
    227  },
    228  async setHistory(ids) {
    229    return await this._chromeScript.sendQuery(
    230      "mock-alert-service:set-history",
    231      ids
    232    );
    233  },
    234  async setThrowHistory(throws) {
    235    return await this._chromeScript.sendQuery(
    236      "mock-alert-service:set-throw-history",
    237      throws
    238    );
    239  },
    240 };