tor-browser

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

ExtensionTestUtils.js (5316B)


      1 const { ExtensionTestCommon } = SpecialPowers.ChromeUtils.importESModule(
      2  "resource://testing-common/ExtensionTestCommon.sys.mjs"
      3 );
      4 
      5 var ExtensionTestUtils = {
      6  // Shortcut to more easily access WebExtensionPolicy.backgroundServiceWorkerEnabled
      7  // from mochitest-plain tests.
      8  getBackgroundServiceWorkerEnabled() {
      9    return ExtensionTestCommon.getBackgroundServiceWorkerEnabled();
     10  },
     11 
     12  // A test helper used to check if the pref "extension.backgroundServiceWorker.forceInTestExtension"
     13  // is set to true.
     14  isInBackgroundServiceWorkerTests() {
     15    return ExtensionTestCommon.isInBackgroundServiceWorkerTests();
     16  },
     17 
     18  get testAssertions() {
     19    return ExtensionTestCommon.testAssertions;
     20  },
     21 };
     22 
     23 ExtensionTestUtils.loadExtension = function (ext) {
     24  // Cleanup functions need to be registered differently depending on
     25  // whether we're in browser chrome or plain mochitests.
     26  var registerCleanup;
     27  /* global registerCleanupFunction */
     28  if (typeof registerCleanupFunction != "undefined") {
     29    registerCleanup = registerCleanupFunction;
     30  } else {
     31    registerCleanup = SimpleTest.registerCleanupFunction.bind(SimpleTest);
     32  }
     33 
     34  var testResolve;
     35  var testDone = new Promise(resolve => {
     36    testResolve = resolve;
     37  });
     38 
     39  var messageHandler = new Map();
     40  var messageAwaiter = new Map();
     41 
     42  var messageQueue = new Set();
     43 
     44  registerCleanup(() => {
     45    if (messageQueue.size) {
     46      let names = Array.from(messageQueue, ([msg]) => msg);
     47      SimpleTest.is(JSON.stringify(names), "[]", "message queue is empty");
     48    }
     49    if (messageAwaiter.size) {
     50      let names = Array.from(messageAwaiter.keys());
     51      SimpleTest.is(
     52        JSON.stringify(names),
     53        "[]",
     54        "no tasks awaiting on messages"
     55      );
     56    }
     57  });
     58 
     59  function checkMessages() {
     60    for (let message of messageQueue) {
     61      let [msg, ...args] = message;
     62 
     63      let listener = messageAwaiter.get(msg);
     64      if (listener) {
     65        messageQueue.delete(message);
     66        messageAwaiter.delete(msg);
     67 
     68        listener.resolve(...args);
     69        return;
     70      }
     71    }
     72  }
     73 
     74  function checkDuplicateListeners(msg) {
     75    if (messageHandler.has(msg) || messageAwaiter.has(msg)) {
     76      throw new Error("only one message handler allowed");
     77    }
     78  }
     79 
     80  function testHandler(kind, pass, msg, ...args) {
     81    if (kind == "test-eq") {
     82      let [expected, actual] = args;
     83      SimpleTest.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`);
     84    } else if (kind == "test-log") {
     85      SimpleTest.info(msg);
     86    } else if (kind == "test-result") {
     87      SimpleTest.ok(pass, msg);
     88    }
     89  }
     90 
     91  var handler = {
     92    async testResult(kind, pass, msg, ...args) {
     93      if (kind == "test-done") {
     94        SimpleTest.ok(pass, msg);
     95        await testResolve(msg);
     96      }
     97      testHandler(kind, pass, msg, ...args);
     98    },
     99 
    100    testMessage(msg, ...args) {
    101      var msgHandler = messageHandler.get(msg);
    102      if (msgHandler) {
    103        msgHandler(...args);
    104      } else {
    105        messageQueue.add([msg, ...args]);
    106        checkMessages();
    107      }
    108    },
    109  };
    110 
    111  // Mimic serialization of functions as done in `Extension.generateXPI` and
    112  // `Extension.generateZipFile` because functions are dropped when `ext` object
    113  // is sent to the main process via the message manager.
    114  ext = Object.assign({}, ext);
    115  if (ext.files) {
    116    ext.files = Object.assign({}, ext.files);
    117    for (let filename of Object.keys(ext.files)) {
    118      let file = ext.files[filename];
    119      if (typeof file === "function" || Array.isArray(file)) {
    120        ext.files[filename] = ExtensionTestCommon.serializeScript(file);
    121      }
    122    }
    123  }
    124  if ("background" in ext) {
    125    ext.background = ExtensionTestCommon.serializeScript(ext.background);
    126  }
    127 
    128  var extension = SpecialPowers.loadExtension(ext, handler);
    129 
    130  registerCleanup(async () => {
    131    if (extension.state == "pending" || extension.state == "running") {
    132      SimpleTest.ok(false, "Extension left running at test shutdown");
    133      await extension.unload();
    134    } else if (extension.state == "unloading") {
    135      SimpleTest.ok(false, "Extension not fully unloaded at test shutdown");
    136    }
    137  });
    138 
    139  extension.awaitMessage = msg => {
    140    return new Promise(resolve => {
    141      checkDuplicateListeners(msg);
    142 
    143      messageAwaiter.set(msg, { resolve });
    144      checkMessages();
    145    });
    146  };
    147 
    148  extension.onMessage = (msg, callback) => {
    149    checkDuplicateListeners(msg);
    150    messageHandler.set(msg, callback);
    151  };
    152 
    153  extension.awaitFinish = msg => {
    154    return testDone.then(actual => {
    155      if (msg) {
    156        SimpleTest.is(actual, msg, "test result correct");
    157      }
    158      return actual;
    159    });
    160  };
    161 
    162  SimpleTest.info(`Extension loaded`);
    163  return extension;
    164 };
    165 
    166 ExtensionTestUtils.failOnSchemaWarnings = (warningsAsErrors = true) => {
    167  let prefName = "extensions.webextensions.warnings-as-errors";
    168  let prefPromise = SpecialPowers.setBoolPref(prefName, warningsAsErrors);
    169  if (!warningsAsErrors) {
    170    let registerCleanup;
    171    if (typeof registerCleanupFunction != "undefined") {
    172      registerCleanup = registerCleanupFunction;
    173    } else {
    174      registerCleanup = SimpleTest.registerCleanupFunction.bind(SimpleTest);
    175    }
    176    registerCleanup(() => SpecialPowers.setBoolPref(prefName, true));
    177  }
    178  // In mochitests, setBoolPref is async.
    179  return prefPromise.then(() => {});
    180 };