tor-browser

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

browser_beforeinput_by_execCommand_in_contentscript.js (5700B)


      1 "use strict";
      2 
      3 async function installAndStartExtension() {
      4  function contentScript() {
      5    window.addEventListener("keydown", aEvent => {
      6      console.log("keydown event is fired");
      7      if (aEvent.defaultPrevented) {
      8        return;
      9      }
     10      let selection = window.getSelection();
     11      if (selection.isCollapsed) {
     12        return;
     13      }
     14      if (aEvent.ctrlKey && aEvent.key === "k") {
     15        document.execCommand("createLink", false, "http://example.com/");
     16        aEvent.preventDefault();
     17      }
     18    });
     19  }
     20 
     21  let extension = ExtensionTestUtils.loadExtension({
     22    manifest: {
     23      content_scripts: [
     24        {
     25          js: ["content_script.js"],
     26          matches: ["<all_urls>"],
     27          run_at: "document_start",
     28        },
     29      ],
     30    },
     31    files: {
     32      "content_script.js": contentScript,
     33    },
     34  });
     35 
     36  await extension.startup();
     37 
     38  return extension;
     39 }
     40 
     41 add_task(async function () {
     42  const extension = await installAndStartExtension();
     43  const tab = await BrowserTestUtils.openNewForegroundTab(
     44    gBrowser,
     45    "http://example.com/browser/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html",
     46    true
     47  );
     48 
     49  /**
     50   * Document.execCommand() shouldn't cause `beforeinput`, but it may be used
     51   * by addons for emulating user input and make the input undoable on builtin
     52   * editors.  Therefore, if and only if it's called by addons, `beforeinput`
     53   * should be fired.
     54   */
     55  function runTest() {
     56    const editor = content.document.querySelector("[contenteditable]");
     57    editor.focus();
     58    content.document.getSelection().selectAllChildren(editor);
     59    let beforeinput;
     60    editor.addEventListener("beforeinput", aEvent => {
     61      beforeinput = aEvent;
     62    });
     63    const description = 'Test execCommand("createLink")';
     64    editor.addEventListener("input", aEvent => {
     65      if (!beforeinput) {
     66        sendAsyncMessage("Test:BeforeInputInContentEditable", {
     67          succeeded: false,
     68          message: `${description}: No beforeinput event is fired`,
     69        });
     70        return;
     71      }
     72      sendAsyncMessage("Test:BeforeInputInContentEditable", {
     73        succeeded:
     74          editor.innerHTML === '<a href="http://example.com/">abcdef</a>',
     75        message: `${description}: editor.innerHTML=${editor.innerHTML}`,
     76      });
     77    });
     78  }
     79 
     80  try {
     81    tab.linkedBrowser.messageManager.loadFrameScript(
     82      "data:,(" + runTest.toString() + ")();",
     83      false
     84    );
     85 
     86    let testResult = new Promise(resolve => {
     87      let mm = tab.linkedBrowser.messageManager;
     88      mm.addMessageListener(
     89        "Test:BeforeInputInContentEditable",
     90        function onFinish(aMsg) {
     91          mm.removeMessageListener(
     92            "Test:BeforeInputInContentEditable",
     93            onFinish
     94          );
     95          is(aMsg.data.succeeded, true, aMsg.data.message);
     96          resolve();
     97        }
     98      );
     99    });
    100    info("Sending Ctrl+K...");
    101    await BrowserTestUtils.synthesizeKey(
    102      "k",
    103      { ctrlKey: true },
    104      tab.linkedBrowser
    105    );
    106    info("Waiting test result...");
    107    await testResult;
    108  } finally {
    109    BrowserTestUtils.removeTab(tab);
    110    await extension.unload();
    111  }
    112 });
    113 
    114 add_task(async function () {
    115  const extension = await installAndStartExtension();
    116  const tab = await BrowserTestUtils.openNewForegroundTab(
    117    gBrowser,
    118    "http://example.com/browser/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html",
    119    true
    120  );
    121 
    122  /**
    123   * Document.execCommand() from addons should be treated as a user input.
    124   * Therefore, it should not block first nested Document.execCommand() call
    125   * in a "beforeinput" event listener in the web app.
    126   */
    127  function runTest() {
    128    const editor = content.document.querySelectorAll("[contenteditable]")[1];
    129    editor.focus();
    130    content.document.getSelection().selectAllChildren(editor);
    131    const beforeInputs = [];
    132    editor.parentNode.addEventListener(
    133      "beforeinput",
    134      aEvent => {
    135        beforeInputs.push(aEvent);
    136      },
    137      { capture: true }
    138    );
    139    const description =
    140      'Test web app calls execCommand("insertText") on "beforeinput"';
    141    editor.addEventListener("input", aEvent => {
    142      if (!beforeInputs.length) {
    143        sendAsyncMessage("Test:BeforeInputInContentEditable", {
    144          succeeded: false,
    145          message: `${description}: No beforeinput event is fired`,
    146        });
    147        return;
    148      }
    149      if (beforeInputs.length > 1) {
    150        sendAsyncMessage("Test:BeforeInputInContentEditable", {
    151          succeeded: false,
    152          message: `${description}: Too many beforeinput events are fired`,
    153        });
    154        return;
    155      }
    156      sendAsyncMessage("Test:BeforeInputInContentEditable", {
    157        succeeded: editor.innerHTML.replace("<br>", "") === "ABCDEF",
    158        message: `${description}: editor.innerHTML=${editor.innerHTML}`,
    159      });
    160    });
    161  }
    162 
    163  try {
    164    tab.linkedBrowser.messageManager.loadFrameScript(
    165      "data:,(" + runTest.toString() + ")();",
    166      false
    167    );
    168 
    169    let testResult = new Promise(resolve => {
    170      let mm = tab.linkedBrowser.messageManager;
    171      mm.addMessageListener(
    172        "Test:BeforeInputInContentEditable",
    173        function onFinish(aMsg) {
    174          mm.removeMessageListener(
    175            "Test:BeforeInputInContentEditable",
    176            onFinish
    177          );
    178          is(aMsg.data.succeeded, true, aMsg.data.message);
    179          resolve();
    180        }
    181      );
    182    });
    183    info("Sending Ctrl+K...");
    184    await BrowserTestUtils.synthesizeKey(
    185      "k",
    186      { ctrlKey: true },
    187      tab.linkedBrowser
    188    );
    189    info("Waiting test result...");
    190    await testResult;
    191  } finally {
    192    BrowserTestUtils.removeTab(tab);
    193    await extension.unload();
    194  }
    195 });