tor-browser

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

delete.tentative.html (31161B)


      1 <!doctype html>
      2 <html>
      3 <head>
      4 <meta charset=utf-8>
      5 <meta name="flags" content="may">
      6 <meta name="timeout" content="long">
      7 <title>Testing normalizing white-space sequence after execCommand("delete", false, "")</title>
      8 <script src=../../include/implementation.js></script>
      9 <script>var testsJsLibraryOnly = true</script>
     10 <script src="../../include/tests.js"></script>
     11 <script src="/resources/testharness.js"></script>
     12 <script src="/resources/testharnessreport.js"></script>
     13 </head>
     14 <body>
     15 <script>
     16 "use strict";
     17 
     18 setup({explicit_done: true});
     19 
     20 function runTests() {
     21  // README:
     22  // These tests based on the behavior of Chrome 83.  This test does NOT define
     23  // nor suggest any standard behavior (actually, some expected results might
     24  // look odd), but this test must help you to understand how other browsers
     25  // use different logic to normalize white-space sequence.
     26 
     27  document.body.innerHTML = "<div contenteditable></div>";
     28  let editor = document.querySelector("div[contenteditable]");
     29  editor.focus();
     30  let selection = document.getSelection();
     31 
     32  function toPlaintext(str) {
     33    return str.replace(/&nbsp;/g, "\u00A0");
     34  }
     35  function escape(str) {
     36    return str.replace(/\u00A0/ig, "&nbsp;");
     37  }
     38 
     39  // Test simple removing in a text node.
     40  //  - initialText: Set to data of text node (only &nbsp; entity is handled)
     41  //  - expectedText: Set to data of the text node after `execCommand("delete")`
     42  //  - white-spaceRange: Set first item to start offset of white-space sequence,
     43  //                     set second item to number of white-spaces.
     44  for (const currentTest of [
     45    { initialText: "a&nbsp;", expectedText: "a", whiteSpaceRange: [1, 1] },
     46    { initialText: "a&nbsp;&nbsp;", expectedText: "a&nbsp;", whiteSpaceRange: [1, 2] },
     47    { initialText: "a &nbsp;",      expectedText: "a&nbsp;", whiteSpaceRange: [1, 2] },
     48    { initialText: "a&nbsp;&nbsp;&nbsp;", expectedText: "a&nbsp;&nbsp;", whiteSpaceRange: [1, 3] },
     49    { initialText: "a&nbsp; &nbsp;",      expectedText: "a&nbsp;&nbsp;", whiteSpaceRange: [1, 3] },
     50    { initialText: "a &nbsp;&nbsp;",      expectedText: "a&nbsp;&nbsp;", whiteSpaceRange: [1, 3] },
     51    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "a&nbsp; &nbsp;", whiteSpaceRange: [1, 4] },
     52    { initialText: "a&nbsp;&nbsp; &nbsp;",      expectedText: "a&nbsp; &nbsp;", whiteSpaceRange: [1, 4] },
     53    { initialText: "a&nbsp; &nbsp;&nbsp;",      expectedText: "a&nbsp; &nbsp;", whiteSpaceRange: [1, 4] },
     54    { initialText: "a &nbsp; &nbsp;",           expectedText: "a&nbsp; &nbsp;", whiteSpaceRange: [1, 4] },
     55    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "a&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 5] },
     56    { initialText: "a&nbsp; &nbsp; &nbsp;",           expectedText: "a&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 5] },
     57    { initialText: "a&nbsp;&nbsp;&nbsp; &nbsp;",      expectedText: "a&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 5] },
     58    { initialText: "a&nbsp;&nbsp; &nbsp;&nbsp;",      expectedText: "a&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 5] },
     59    { initialText: "a&nbsp; &nbsp;&nbsp;&nbsp;",      expectedText: "a&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 5] },
     60    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [1, 10] },
     61    { initialText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;",                     expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [1, 10] },
     62    { initialText: "a &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;",                          expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [1, 10] },
     63    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 11] },
     64    { initialText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;",                          expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;", whiteSpaceRange: [1, 11] },
     65    { initialText: "a&nbsp;b", expectedText: "ab", whiteSpaceRange: [1, 1] },
     66    { initialText: "a b",      expectedText: "ab", whiteSpaceRange: [1, 1] },
     67    { initialText: "a&nbsp;&nbsp;b", expectedText: "a b", whiteSpaceRange: [1, 2] },
     68    { initialText: "a&nbsp; b",      expectedText: "a b", whiteSpaceRange: [1, 2] },
     69    { initialText: "a &nbsp;b",      expectedText: "a b", whiteSpaceRange: [1, 2] },
     70    { initialText: "a&nbsp;&nbsp;&nbsp;b", expectedText: "a&nbsp; b", whiteSpaceRange: [1, 3] },
     71    { initialText: "a&nbsp; &nbsp;b",      expectedText: "a&nbsp; b", whiteSpaceRange: [1, 3] },
     72    { initialText: "a &nbsp; b",           expectedText: "a&nbsp; b", whiteSpaceRange: [1, 3] },
     73    { initialText: "a &nbsp;&nbsp;b",      expectedText: "a&nbsp; b", whiteSpaceRange: [1, 3] },
     74    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "a&nbsp; &nbsp;b", whiteSpaceRange: [1, 4] },
     75    { initialText: "a&nbsp; &nbsp; b",           expectedText: "a&nbsp; &nbsp;b", whiteSpaceRange: [1, 4] },
     76    { initialText: "a &nbsp; &nbsp;b",           expectedText: "a&nbsp; &nbsp;b", whiteSpaceRange: [1, 4] },
     77    { initialText: "a&nbsp;&nbsp; &nbsp;b",      expectedText: "a&nbsp; &nbsp;b", whiteSpaceRange: [1, 4] },
     78    { initialText: "a&nbsp; &nbsp;&nbsp;b",      expectedText: "a&nbsp; &nbsp;b", whiteSpaceRange: [1, 4] },
     79    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     80    { initialText: "a&nbsp; &nbsp; &nbsp;b",           expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     81    { initialText: "a &nbsp; &nbsp; b",                expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     82    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp; b",      expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     83    { initialText: "a&nbsp;&nbsp;&nbsp; &nbsp;b",      expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     84    { initialText: "a&nbsp;&nbsp; &nbsp;&nbsp;b",      expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     85    { initialText: "a&nbsp; &nbsp;&nbsp;&nbsp;b",      expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     86    { initialText: "a &nbsp;&nbsp;&nbsp;&nbsp;b",      expectedText: "a&nbsp; &nbsp; b", whiteSpaceRange: [1, 5] },
     87    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [1, 10] },
     88    { initialText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b",                          expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [1, 10] },
     89    { initialText: "a &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b",                          expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [1, 10] },
     90    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [1, 11] },
     91    { initialText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b",                          expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [1, 11] },
     92    { initialText: "a &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b",                               expectedText: "a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [1, 11] },
     93    { initialText: "&nbsp;b", expectedText: "b", whiteSpaceRange: [0, 1] },
     94    { initialText: "&nbsp;&nbsp;b", expectedText: "&nbsp;b", whiteSpaceRange: [0, 2] },
     95    { initialText: "&nbsp; b",      expectedText: "&nbsp;b", whiteSpaceRange: [0, 2] },
     96    { initialText: "&nbsp;&nbsp;&nbsp;b", expectedText: "&nbsp; b", whiteSpaceRange: [0, 3] },
     97    { initialText: "&nbsp; &nbsp;b",      expectedText: "&nbsp; b", whiteSpaceRange: [0, 3] },
     98    { initialText: "&nbsp;&nbsp; b",      expectedText: "&nbsp; b", whiteSpaceRange: [0, 3] },
     99    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "&nbsp; &nbsp;b", whiteSpaceRange: [0, 4] },
    100    { initialText: "&nbsp; &nbsp; b",           expectedText: "&nbsp; &nbsp;b", whiteSpaceRange: [0, 4] },
    101    { initialText: "&nbsp;&nbsp;&nbsp; b",      expectedText: "&nbsp; &nbsp;b", whiteSpaceRange: [0, 4] },
    102    { initialText: "&nbsp;&nbsp; &nbsp;b",      expectedText: "&nbsp; &nbsp;b", whiteSpaceRange: [0, 4] },
    103    { initialText: "&nbsp; &nbsp;&nbsp;b",      expectedText: "&nbsp; &nbsp;b", whiteSpaceRange: [0, 4] },
    104    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "&nbsp; &nbsp; b", whiteSpaceRange: [0, 5] },
    105    { initialText: "&nbsp; &nbsp; &nbsp;b",           expectedText: "&nbsp; &nbsp; b", whiteSpaceRange: [0, 5] },
    106    { initialText: "&nbsp;&nbsp;&nbsp; &nbsp;b",      expectedText: "&nbsp; &nbsp; b", whiteSpaceRange: [0, 5] },
    107    { initialText: "&nbsp;&nbsp; &nbsp;&nbsp;b",      expectedText: "&nbsp; &nbsp; b", whiteSpaceRange: [0, 5] },
    108    { initialText: "&nbsp; &nbsp;&nbsp;&nbsp;b",      expectedText: "&nbsp; &nbsp; b", whiteSpaceRange: [0, 5] },
    109    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [0, 10] },
    110    { initialText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b",                          expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [0, 10] },
    111    { initialText: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b",                     expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b", whiteSpaceRange: [0, 10] },
    112    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [0, 11] },
    113    { initialText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b",                          expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [0, 11] },
    114    { initialText: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b",                          expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b", whiteSpaceRange: [0, 11] },
    115    { initialText: "&nbsp;", expectedText: "", whiteSpaceRange: [0, 1] },
    116    { initialText: "&nbsp;&nbsp;", expectedText: "&nbsp;", whiteSpaceRange: [0, 2] },
    117    { initialText: "&nbsp;&nbsp;&nbsp;", expectedText: "&nbsp;&nbsp;", whiteSpaceRange: [0, 3] },
    118    { initialText: "&nbsp; &nbsp;",      expectedText: "&nbsp;&nbsp;", whiteSpaceRange: [0, 3] },
    119    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "&nbsp; &nbsp;", whiteSpaceRange: [0, 4] },
    120    { initialText: "&nbsp;&nbsp; &nbsp;",      expectedText: "&nbsp; &nbsp;", whiteSpaceRange: [0, 4] },
    121    { initialText: "&nbsp; &nbsp;&nbsp;",      expectedText: "&nbsp; &nbsp;", whiteSpaceRange: [0, 4] },
    122    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 5] },
    123    { initialText: "&nbsp; &nbsp; &nbsp;",           expectedText: "&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 5] },
    124    { initialText: "&nbsp;&nbsp;&nbsp; &nbsp;",      expectedText: "&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 5] },
    125    { initialText: "&nbsp;&nbsp; &nbsp;&nbsp;",      expectedText: "&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 5] },
    126    { initialText: "&nbsp; &nbsp;&nbsp;&nbsp;",      expectedText: "&nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 5] },
    127    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [0, 10] },
    128    { initialText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;",                     expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [0, 10] },
    129    { initialText: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;",                     expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;", whiteSpaceRange: [0, 10] },
    130    { initialText: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 11] },
    131    { initialText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;",                          expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 11] },
    132    { initialText: "&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;",                     expectedText: "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;", whiteSpaceRange: [0, 11] },
    133  ]) {
    134    for (let i = currentTest.whiteSpaceRange[0]; i < currentTest.whiteSpaceRange[0] + currentTest.whiteSpaceRange[1]; i++) {
    135      currentTest.getInitialText = function (aCaretPos) {
    136        return escape(`${toPlaintext(this.initialText).slice(0, aCaretPos)}[]${toPlaintext(this.initialText).slice(aCaretPos)}`);
    137      }
    138      test(function () {
    139        editor.innerHTML = "";
    140        editor.appendChild(document.createTextNode(toPlaintext(currentTest.initialText)));
    141        selection.collapse(editor.firstChild, i + 1);
    142        document.execCommand("delete", false, "");
    143        if (currentTest.expectedText.length) {
    144          assert_equals(escape(editor.childNodes.item(0).data), currentTest.expectedText, "Modified text is wrong");
    145          assert_equals(selection.focusNode, editor.childNodes.item(0), "Selection focus node is wrong");
    146          assert_equals(selection.focusOffset, i, "Selection focus offset is wrong");
    147          assert_equals(selection.anchorNode, editor.childNodes.item(0), "Selection anchor node is wrong");
    148          assert_equals(selection.anchorOffset, i, "Selection anchor offset is wrong");
    149        } else {
    150          assert_equals(escape(editor.textContent), "", "Modified text is wrong");
    151          assert_equals(selection.focusNode, editor, "Selection focus node is wrong");
    152          assert_equals(selection.focusOffset, 0, "Selection focus offset is wrong");
    153          assert_equals(selection.anchorNode, editor, "Selection anchor node is wrong");
    154          assert_equals(selection.anchorOffset, 0, "Selection anchor offset is wrong");
    155        }
    156      }, `execCommand("delete", false, ""): "${currentTest.getInitialText(i + 1)}" (length of whiteSpace sequence: ${currentTest.whiteSpaceRange[1]})`);
    157    }
    158  }
    159 
    160  // Test white space sequence split to multiple text node.
    161  //  - initialText: Set to data of text nodes.  This must have "|" at least one.
    162  //                 Then, the text will be split at every "|".
    163  //                 Same as above test, only &nbsp; is handled at setting.
    164  //                 "[]" means that caret position.
    165  //  - expectedText: Set to data of all text nodes as an array.
    166  //                  Same as above test, only &nbsp; is handled before comparing.
    167  for (const currentTest of [
    168    { initialText: "a&nbsp; &nbsp;|[]&nbsp; &nbsp;b", expectedText: ["a&nbsp; []", "&nbsp; &nbsp;b"] },
    169    { initialText: "a&nbsp; &nbsp;[]|&nbsp; &nbsp;b", expectedText: ["a&nbsp; []", "&nbsp; &nbsp;b"] },
    170    { initialText: "a&nbsp; &nbsp;|[] &nbsp; b",      expectedText: ["a&nbsp; []", "&nbsp; &nbsp;b"] },
    171    { initialText: "a&nbsp; &nbsp;[]| &nbsp; b",      expectedText: ["a&nbsp; []", "&nbsp; &nbsp;b"] },
    172    { initialText: "a &nbsp; |[]&nbsp; &nbsp;b", expectedText: ["a &nbsp;[]", "&nbsp; &nbsp;b"] },
    173    { initialText: "a &nbsp; []|&nbsp; &nbsp;b", expectedText: ["a &nbsp;[]", "&nbsp; &nbsp;b"] },
    174    { initialText: "a&nbsp; &nbsp;|&nbsp;[] &nbsp;b", expectedText: ["a&nbsp; &nbsp;[]", "&nbsp; b"] },
    175    { initialText: "a&nbsp; &nbsp;| []&nbsp; b",      expectedText: ["a&nbsp; &nbsp;[]", "&nbsp; b"] },
    176    { initialText: "a &nbsp; |&nbsp;[] &nbsp;b", expectedText: ["a &nbsp; []", "&nbsp; b"] },
    177    { initialText: "a &nbsp; | []&nbsp; b", expectedText: ["a &nbsp;[]", "&nbsp; b"] },
    178 
    179    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;[]&nbsp;&nbsp;b", expectedText: ["a&nbsp;&nbsp;&nbsp;&nbsp;", "&nbsp;[] &nbsp;b"] },
    180    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;[]&nbsp;&nbsp;&nbsp;b", expectedText: ["a&nbsp;&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp;b"] },
    181    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;|[]&nbsp;&nbsp;&nbsp;&nbsp;b", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; b"] },
    182    { initialText: "a&nbsp;b[]&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;c",       expectedText: ["a&nbsp;[] &nbsp;", "&nbsp;&nbsp;&nbsp;&nbsp;c"] },
    183    { initialText: "a&nbsp;&nbsp;b[]&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp; []&nbsp;&nbsp;", "&nbsp;&nbsp;&nbsp;&nbsp;c"] },
    184    { initialText: "a&nbsp;&nbsp;&nbsp;b[]|&nbsp;&nbsp;&nbsp;&nbsp;c",       expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    185    { initialText: "a&nbsp;&nbsp;&nbsp;b|[]&nbsp;&nbsp;&nbsp;&nbsp;c",       expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    186    { initialText: "a&nbsp;&nbsp;&nbsp;b[]|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; &nbsp;c"] },
    187    { initialText: "a&nbsp;&nbsp;&nbsp;b|[]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; &nbsp;c"] },
    188    { initialText: "a&nbsp;&nbsp;&nbsp;|b[]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; &nbsp;c"] },
    189    { initialText: "a&nbsp;&nbsp;&nbsp;[]|b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;[]", "b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c"] },
    190    { initialText: "a&nbsp;&nbsp;&nbsp;|&nbsp;b[]&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;", "&nbsp;[] &nbsp; &nbsp;c"] },
    191 
    192    { initialText: "a&nbsp;&nbsp;&nbsp;|&nbsp;|[]&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    193    { initialText: "a&nbsp;&nbsp;&nbsp;| |[]&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    194    { initialText: "a&nbsp;&nbsp;&nbsp;| []|&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    195    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;[]| |&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp;", "&nbsp;&nbsp;&nbsp;c"] },
    196    { initialText: "a&nbsp;&nbsp;&nbsp;[]&nbsp;| |&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp; []&nbsp;", " ", "&nbsp;&nbsp;&nbsp;c"] },
    197    { initialText: "a&nbsp;&nbsp;&nbsp;[]&nbsp;&nbsp;|&nbsp;|&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp; []&nbsp;&nbsp;", "&nbsp;", "&nbsp;&nbsp;&nbsp;c"] },
    198    { initialText: "a&nbsp;&nbsp;&nbsp;[]&nbsp;&nbsp;| |&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp; []&nbsp;&nbsp;", " ", "&nbsp;&nbsp;&nbsp;c"] },
    199    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;||&nbsp;[]&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp;c"] },
    200    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;||[]&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    201    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;|[]|&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    202    { initialText: "a&nbsp;&nbsp;&nbsp;&nbsp;[]||&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp;&nbsp;&nbsp;[]", "&nbsp; &nbsp; c"] },
    203    { initialText: "a&nbsp;&nbsp;&nbsp;[]&nbsp;||&nbsp;&nbsp;&nbsp;&nbsp;c", expectedText: ["a&nbsp; []&nbsp;", "", "&nbsp;&nbsp;&nbsp;&nbsp;c"] },
    204  ]) {
    205    test(function () {
    206      editor.innerHTML = "";
    207      let caret = { container: null, offset: -1 };
    208      for (let text of toPlaintext(currentTest.initialText).split("|")) {
    209        let caretOffset = text.indexOf("[]");
    210        if (caretOffset >= 0) {
    211          text = text.slice(0, caretOffset) + text.slice(caretOffset + 2);
    212        }
    213        let textNode = document.createTextNode(text);
    214        editor.appendChild(textNode);
    215        if (caretOffset >= 0) {
    216          caret = { container: textNode, offset: caretOffset };
    217        }
    218      }
    219      selection.collapse(caret.container, caret.offset);
    220      document.execCommand("delete", false, "");
    221      let child = editor.firstChild;
    222      for (let expectedText of currentTest.expectedText) {
    223        expectedText = toPlaintext(expectedText);
    224        let caretOffset = expectedText.indexOf("[]");
    225        if (caretOffset >= 0) {
    226          expectedText = expectedText.slice(0, caretOffset) + expectedText.slice(caretOffset + 2);
    227        }
    228        if (!child || child.nodeName !== "#text") {
    229          assert_equals("", escape(expectedText), "Expected text node is not there");
    230          if (caretOffset >= 0) {
    231            assert_equals(-1, caretOffset, "Selection should be contained in this node");
    232          }
    233        } else {
    234          assert_equals(escape(child.data), escape(expectedText), "Modified text is wrong");
    235          if (caretOffset >= 0) {
    236            assert_equals(selection.focusNode, child, "Selection focus node is wrong");
    237            assert_equals(selection.focusOffset, caretOffset, "Selection focus offset is wrong");
    238            assert_equals(selection.anchorNode, child, "Selection anchor node is wrong");
    239            assert_equals(selection.anchorOffset, caretOffset, "Selection anchor offset is wrong");
    240          }
    241        }
    242        child = child.nextSibling;
    243      }
    244      if (child && child.nodeName === "#text") {
    245        assert_equals(escape(child.data), "", "Unexpected text node is there");
    246      }
    247    }, `execCommand("delete", false, ""): "${currentTest.initialText}"`);
    248  }
    249 
    250  // Test white spaces around inline element boundary
    251  //  - initialHTML: Set to innerHTML of the <div>  ("[{" and "]}" set selection to the range)
    252  //  - expectedText: Set to innerHTML of the <div> after `execCommand("delete")`
    253  for (const currentTest of [
    254    { initialHTML: "<span>abc <span>&nbsp;[]def</span></span>", expectedHTML: "<span>abc <span>def</span></span>" },
    255    { initialHTML: "<span>abc <span>[]&nbsp;def</span></span>", expectedHTML: "<span>abc<span>&nbsp;def</span></span>" },
    256    { initialHTML: "<span>abc []<span>&nbsp;def</span></span>", expectedHTML: "<span>abc<span>&nbsp;def</span></span>" },
    257    { initialHTML: "<span>abc&nbsp;<span>&nbsp;[]def</span></span>", expectedHTML: "<span>abc&nbsp;<span>def</span></span>" },
    258    { initialHTML: "<span>abc&nbsp;<span>[]&nbsp;def</span></span>", expectedHTML: "<span>abc<span>&nbsp;def</span></span>" },
    259    { initialHTML: "<span>abc&nbsp;[]<span>&nbsp;def</span></span>", expectedHTML: "<span>abc<span>&nbsp;def</span></span>" },
    260    { initialHTML: "<span>abc&nbsp; <span>&nbsp;[]def</span></span>", expectedHTML: "<span>abc&nbsp; <span>def</span></span>" },
    261    { initialHTML: "<span>abc&nbsp; <span>[]&nbsp;def</span></span>", expectedHTML: "<span>abc&nbsp;<span>&nbsp;def</span></span>" },
    262    { initialHTML: "<span>abc&nbsp; []<span>&nbsp;def</span></span>", expectedHTML: "<span>abc&nbsp;<span>&nbsp;def</span></span>" },
    263    { initialHTML: "<span>abc &nbsp;<span>&nbsp;[]def</span></span>", expectedHTML: "<span>abc &nbsp;<span>def</span></span>" },
    264    { initialHTML: "<span>abc &nbsp;<span>[]&nbsp;def</span></span>", expectedHTML: "<span>abc <span>&nbsp;def</span></span>" },
    265    { initialHTML: "<span>abc &nbsp;[]<span>&nbsp;def</span></span>", expectedHTML: "<span>abc <span>&nbsp;def</span></span>" },
    266 
    267    { initialHTML: "<span>abc </span><span>&nbsp;[]def</span>", expectedHTML: "<span>abc </span><span>def</span>" },
    268    { initialHTML: "<span>abc </span><span>[]&nbsp;def</span>", expectedHTML: "<span>abc</span><span>&nbsp;def</span>" },
    269    { initialHTML: "<span>abc []</span><span>&nbsp;def</span>", expectedHTML: "<span>abc</span><span>&nbsp;def</span>" },
    270    { initialHTML: "<span>abc&nbsp;</span><span>&nbsp;[]def</span>", expectedHTML: "<span>abc&nbsp;</span><span>def</span>" },
    271    { initialHTML: "<span>abc&nbsp;</span><span>[]&nbsp;def</span>", expectedHTML: "<span>abc</span><span>&nbsp;def</span>" },
    272    { initialHTML: "<span>abc&nbsp;[]</span><span>&nbsp;def</span>", expectedHTML: "<span>abc</span><span>&nbsp;def</span>" },
    273    { initialHTML: "<span>abc&nbsp; </span><span>&nbsp;[]def</span>", expectedHTML: "<span>abc&nbsp; </span><span>def</span>" },
    274    { initialHTML: "<span>abc&nbsp; </span><span>[]&nbsp;def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp;def</span>" },
    275    { initialHTML: "<span>abc&nbsp; []</span><span>&nbsp;def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp;def</span>" },
    276    { initialHTML: "<span>abc &nbsp;</span><span>&nbsp;[]def</span>", expectedHTML: "<span>abc &nbsp;</span><span>def</span>" },
    277    { initialHTML: "<span>abc &nbsp;</span><span>[]&nbsp;def</span>", expectedHTML: "<span>abc </span><span>&nbsp;def</span>" },
    278    { initialHTML: "<span>abc &nbsp;[]</span><span>&nbsp;def</span>", expectedHTML: "<span>abc </span><span>&nbsp;def</span>" },
    279    { initialHTML: "<span>abc&nbsp;</span><span>&nbsp; []def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp;def</span>" },
    280    { initialHTML: "<span>abc&nbsp;</span><span>&nbsp; &nbsp;[]def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    281    { initialHTML: "<span>abc&nbsp;</span><span>&nbsp; []&nbsp;def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    282    { initialHTML: "<span>abc&nbsp;</span><span>&nbsp;[] &nbsp;def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    283    { initialHTML: "<span>abc&nbsp;</span><span> &nbsp; []def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    284    { initialHTML: "<span>abc&nbsp;</span><span> &nbsp;[] def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    285    { initialHTML: "<span>abc&nbsp;</span><span> []&nbsp; def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; def</span>" },
    286    { initialHTML: "<span>abc&nbsp;</span><span>[] &nbsp; def</span>", expectedHTML: "<span>abc</span><span>&nbsp; &nbsp;def</span>" },
    287    { initialHTML: "<span>abc&nbsp;[]</span><span> &nbsp; def</span>", expectedHTML: "<span>abc</span><span>&nbsp; &nbsp;def</span>" },
    288    { initialHTML: "<span>abc &nbsp;[]</span><span> &nbsp; def</span>", expectedHTML: "<span>abc </span><span>&nbsp; &nbsp;def</span>" },
    289    { initialHTML: "<span>abc&nbsp;&nbsp;[]</span><span> &nbsp; def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; &nbsp;def</span>" },
    290    { initialHTML: "<span>abc&nbsp;&nbsp;[]</span><span>&nbsp; &nbsp;def</span>", expectedHTML: "<span>abc&nbsp;</span><span>&nbsp; &nbsp;def</span>" },
    291 
    292    { initialHTML: "<span><span>abc </span>&nbsp;[]def</span>", expectedHTML: "<span><span>abc </span>def</span>" },
    293    { initialHTML: "<span><span>abc </span>[]&nbsp;def</span>", expectedHTML: "<span><span>abc</span>&nbsp;def</span>" },
    294    { initialHTML: "<span><span>abc []</span>&nbsp;def</span>", expectedHTML: "<span><span>abc</span>&nbsp;def</span>" },
    295    { initialHTML: "<span><span>abc&nbsp;</span>&nbsp;[]def</span>", expectedHTML: "<span><span>abc&nbsp;</span>def</span>" },
    296    { initialHTML: "<span><span>abc&nbsp;</span>[]&nbsp;def</span>", expectedHTML: "<span><span>abc</span>&nbsp;def</span>" },
    297    { initialHTML: "<span><span>abc&nbsp;[]</span>&nbsp;def</span>", expectedHTML: "<span><span>abc</span>&nbsp;def</span>" },
    298    { initialHTML: "<span><span>abc&nbsp; </span>&nbsp;[]def</span>", expectedHTML: "<span><span>abc&nbsp; </span>def</span>" },
    299    { initialHTML: "<span><span>abc&nbsp; </span>[]&nbsp;def</span>", expectedHTML: "<span><span>abc&nbsp;</span>&nbsp;def</span>" },
    300    { initialHTML: "<span><span>abc&nbsp; []</span>&nbsp;def</span>", expectedHTML: "<span><span>abc&nbsp;</span>&nbsp;def</span>" },
    301    { initialHTML: "<span><span>abc &nbsp;</span>&nbsp;[]def</span>", expectedHTML: "<span><span>abc &nbsp;</span>def</span>" },
    302    { initialHTML: "<span><span>abc &nbsp;</span>[]&nbsp;def</span>", expectedHTML: "<span><span>abc </span>&nbsp;def</span>" },
    303    { initialHTML: "<span><span>abc &nbsp;[]</span>&nbsp;def</span>", expectedHTML: "<span><span>abc </span>&nbsp;def</span>" },
    304 
    305    { initialHTML: "<span><span>abc &nbsp;</span></span><span>&nbsp;[]def</span>", expectedHTML: "<span><span>abc &nbsp;</span></span><span>def</span>" },
    306    { initialHTML: "<span><span>abc &nbsp;</span></span><span>[]&nbsp;def</span>", expectedHTML: "<span><span>abc </span></span><span>&nbsp;def</span>" },
    307    { initialHTML: "<span><span>abc &nbsp;[]</span></span><span>&nbsp;def</span>", expectedHTML: "<span><span>abc </span></span><span>&nbsp;def</span>" },
    308 
    309 
    310    { initialHTML: "a<span style=white-space:pre;>b[]   </span>c", expectedHTML: "a<span style=\"white-space:pre;\">   </span>c" },
    311    { initialHTML: "a<span style=white-space:pre;>b []  </span>c", expectedHTML: "a<span style=\"white-space:pre;\">b  </span>c" },
    312    { initialHTML: "a<span style=white-space:pre;>b  [] </span>c", expectedHTML: "a<span style=\"white-space:pre;\">b  </span>c" },
    313    { initialHTML: "a<span style=white-space:pre;>b   []</span>c", expectedHTML: "a<span style=\"white-space:pre;\">b  </span>c" },
    314    { initialHTML: "a<span style=white-space:pre;>b  [] </span>", expectedHTML: "a<span style=\"white-space:pre;\">b  </span>" },
    315    { initialHTML: "a<span style=white-space:pre;> </span>[]b", expectedHTML: "ab" },
    316    { initialHTML: "a&nbsp;&nbsp;&nbsp;<span style=white-space:pre;>[]   </span>", expectedHTML: "a&nbsp;&nbsp;<span style=\"white-space:pre;\">   </span>" },
    317    { initialHTML: "a&nbsp;&nbsp;&nbsp;[]<span style=white-space:pre;>   </span>", expectedHTML: "a&nbsp;&nbsp;<span style=\"white-space:pre;\">   </span>" },
    318    { initialHTML: "a&nbsp;&nbsp;[]&nbsp;<span style=white-space:pre;>   </span>", expectedHTML: "a&nbsp;&nbsp;<span style=\"white-space:pre;\">   </span>" },
    319    { initialHTML: "a&nbsp;[]&nbsp;&nbsp;<span style=white-space:pre;>b  </span>", expectedHTML: "a&nbsp;&nbsp;<span style=\"white-space:pre;\">b  </span>" },
    320    { initialHTML: "a&nbsp;&nbsp;&nbsp;&nbsp;<span style=white-space:pre;>[]   </span>", expectedHTML: "a&nbsp;&nbsp;&nbsp;<span style=\"white-space:pre;\">   </span>" },
    321    { initialHTML: "a&nbsp;&nbsp;&nbsp;&nbsp;[]<span style=white-space:pre;>   </span>", expectedHTML: "a&nbsp;&nbsp;&nbsp;<span style=\"white-space:pre;\">   </span>" },
    322    { initialHTML: "a&nbsp;&nbsp;&nbsp;[]&nbsp;<span style=white-space:pre;>   </span>", expectedHTML: "a&nbsp; &nbsp;<span style=\"white-space:pre;\">   </span>" },
    323    { initialHTML: "a&nbsp;&nbsp;[]&nbsp;<span style=white-space:pre;>b  </span>", expectedHTML: "a&nbsp;&nbsp;<span style=\"white-space:pre;\">b  </span>" },
    324    { initialHTML: "<span style=white-space:pre;>  [] </span>&nbsp;&nbsp;&nbsp;a", expectedHTML: "<span style=\"white-space:pre;\">  </span>&nbsp;&nbsp;&nbsp;a" },
    325    { initialHTML: "<span style=white-space:pre;>   []</span>&nbsp;&nbsp;&nbsp;a", expectedHTML: "<span style=\"white-space:pre;\">  </span>&nbsp; &nbsp;a" },
    326    { initialHTML: "<span style=white-space:pre;>   </span>[]&nbsp;&nbsp;&nbsp;a", expectedHTML: "<span style=\"white-space:pre;\">  </span>&nbsp; &nbsp;a" },
    327    { initialHTML: "<span style=white-space:pre;>   </span>&nbsp;[]&nbsp;&nbsp;&nbsp;a", expectedHTML: "<span style=\"white-space:pre;\">   </span>&nbsp; &nbsp;a" },
    328  ]) {
    329    test(function () {
    330      let points = setupDiv(editor, currentTest.initialHTML);
    331      selection.setBaseAndExtent(points[0], points[1], points[2], points[3]);
    332      document.execCommand("delete", false, "");
    333      assert_equals(editor.innerHTML, currentTest.expectedHTML);
    334    }, `execCommand("delete", false, ""): "${currentTest.initialHTML}"`);
    335  }
    336 
    337  done();
    338 }
    339 
    340 window.addEventListener("load", runTests, {once: true});
    341 </script>
    342 </body>
    343 </html>