tor-browser

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

test_nsIHTMLEditor_removeInlineProperty.html (24923B)


      1 <!DOCTYPE>
      2 <html>
      3 <head>
      4  <title>Test for nsIHTMLEditor.removeInlineProperty()</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
      7 </head>
      8 <body>
      9 <div id="display">
     10 </div>
     11 <div id="content" contenteditable></div>
     12 <pre id="test">
     13 </pre>
     14 
     15 <script class="testbody" type="application/javascript">
     16 "use strict";
     17 
     18 SimpleTest.waitForExplicitFinish();
     19 
     20 SimpleTest.waitForFocus(() => {
     21  let editor = document.getElementById("content");
     22  let selection = window.getSelection();
     23  let description, condition;
     24  let beforeInputEvents = [];
     25  let inputEvents = [];
     26  let selectionRanges = [];
     27  function onBeforeInput(aEvent) {
     28    beforeInputEvents.push(aEvent);
     29    selectionRanges = [];
     30    for (let i = 0; i < selection.rangeCount; i++) {
     31      let range = selection.getRangeAt(i);
     32      selectionRanges.push({startContainer: range.startContainer, startOffset: range.startOffset,
     33                            endContainer: range.endContainer, endOffset: range.endOffset});
     34    }
     35  }
     36  function onInput(aEvent) {
     37    inputEvents.push(aEvent);
     38  }
     39  editor.addEventListener("beforeinput", onBeforeInput);
     40  editor.addEventListener("input", onInput);
     41 
     42  function checkInputEvent(aEvent, aInputType, aDescription) {
     43    if (aEvent.type !== "input" && aEvent.type !== "beforeinput") {
     44      return;
     45    }
     46    ok(aEvent instanceof InputEvent, `${aDescription}"${aEvent.type}" event should be dispatched with InputEvent interface`);
     47    // If it were cancelable whose inputType is empty string, web apps would
     48    // block any Firefox specific modification whose inputType are not declared
     49    // by the spec.
     50    let expectedCancelable = aEvent.type === "beforeinput" && aInputType !== "";
     51    is(aEvent.cancelable, expectedCancelable,
     52       `${aDescription}"${aEvent.type}" event should ${expectedCancelable ? "be" : "be never"} cancelable`);
     53    is(aEvent.bubbles, true, `${aDescription}"${aEvent.type}" event should always bubble`);
     54    is(aEvent.inputType, aInputType, `${aDescription}inputType of "${aEvent.type}" event should be ${aInputType}`);
     55    is(aEvent.data, null, `${aDescription}data of "${aEvent.type}" event should be null`);
     56    is(aEvent.dataTransfer, null, `${aDescription}dataTransfer of "${aEvent.type}" event should be null`);
     57    let targetRanges = aEvent.getTargetRanges();
     58    if (aEvent.type === "beforeinput") {
     59      is(targetRanges.length, selectionRanges.length,
     60         `${aDescription}getTargetRanges() of "${aEvent.type}" event should return selection ranges`);
     61      if (targetRanges.length === selectionRanges.length) {
     62        for (let i = 0; i < selectionRanges.length; i++) {
     63          is(targetRanges[i].startContainer, selectionRanges[i].startContainer,
     64             `${aDescription}startContainer of getTargetRanges()[${i}] of "beforeinput" event does not match`);
     65          is(targetRanges[i].startOffset, selectionRanges[i].startOffset,
     66             `${aDescription}startOffset of getTargetRanges()[${i}] of "beforeinput" event does not match`);
     67          is(targetRanges[i].endContainer, selectionRanges[i].endContainer,
     68             `${aDescription}endContainer of getTargetRanges()[${i}] of "beforeinput" event does not match`);
     69          is(targetRanges[i].endOffset, selectionRanges[i].endOffset,
     70             `${aDescription}endOffset of getTargetRanges()[${i}] of "beforeinput" event does not match`);
     71        }
     72      }
     73    } else {
     74      is(targetRanges.length, 0, `${aDescription}getTargetRanges() of "${aEvent.type}" event should return empty array`);
     75    }
     76  }
     77 
     78  function selectFromTextSiblings(aNode) {
     79    condition = "selecting the node from end of previous text to start of next text node";
     80    selection.setBaseAndExtent(aNode.previousSibling, aNode.previousSibling.length,
     81                               aNode.nextSibling, 0);
     82  }
     83  function selectNode(aNode) {
     84    condition = "selecting the node";
     85    let range = document.createRange();
     86    range.selectNode(aNode);
     87    selection.removeAllRanges();
     88    selection.addRange(range);
     89  }
     90  function selectAllChildren(aNode) {
     91    condition = "selecting all children of the node";
     92    selection.selectAllChildren(aNode);
     93  }
     94  function selectChildContents(aNode) {
     95    condition = "selecting all contents of its child";
     96    let range = document.createRange();
     97    range.selectNodeContents(aNode.firstChild);
     98    selection.removeAllRanges();
     99    selection.addRange(range);
    100  }
    101 
    102  description = "When there is a <b> element and ";
    103  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    104    editor.innerHTML = "<p>test: <b>here</b> is bolden text</p>";
    105    editor.focus();
    106    beforeInputEvents = [];
    107    inputEvents = [];
    108    prepare(editor.firstChild.firstChild.nextSibling);
    109    getHTMLEditor().removeInlineProperty("b", "");
    110    is(editor.innerHTML, "<p>test: here is bolden text</p>",
    111      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should remove the <b> element');
    112    is(beforeInputEvents.length, 1,
    113      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    114    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    115    is(inputEvents.length, 1,
    116      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    117    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    118  }
    119 
    120  description = "When there is a <b> element which has style attribute and ";
    121  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    122    editor.innerHTML = '<p>test: <b style="font-style: italic">here</b> is bolden text</p>';
    123    editor.focus();
    124    beforeInputEvents = [];
    125    inputEvents = [];
    126    prepare(editor.firstChild.firstChild.nextSibling);
    127    getHTMLEditor().removeInlineProperty("b", "");
    128    is(editor.innerHTML, '<p>test: <span style="font-style: italic">here</span> is bolden text</p>',
    129      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should replace the <b> element with <span> element to keep the style');
    130    is(beforeInputEvents.length, 1,
    131      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    132    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    133    is(inputEvents.length, 1,
    134      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    135    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    136  }
    137 
    138  description = "When there is a <b> element which has class attribute and ";
    139  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    140    editor.innerHTML = '<p>test: <b class="foo">here</b> is bolden text</p>';
    141    editor.focus();
    142    beforeInputEvents = [];
    143    inputEvents = [];
    144    prepare(editor.firstChild.firstChild.nextSibling);
    145    getHTMLEditor().removeInlineProperty("b", "");
    146    is(editor.innerHTML, '<p>test: <span class="foo">here</span> is bolden text</p>',
    147      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should replace the <b> element with <span> element to keep the class');
    148    is(beforeInputEvents.length, 1,
    149      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    150    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    151    is(inputEvents.length, 1,
    152      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    153    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    154  }
    155 
    156  description = "When there is a <b> element which has an <i> element and ";
    157  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    158    editor.innerHTML = "<p>test: <b><i>here</i></b> is bolden and italic text</p>";
    159    editor.focus();
    160    beforeInputEvents = [];
    161    inputEvents = [];
    162    prepare(editor.firstChild.firstChild.nextSibling);
    163    getHTMLEditor().removeInlineProperty("b", "");
    164    is(editor.innerHTML, "<p>test: <i>here</i> is bolden and italic text</p>",
    165      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should remove only the <b> element');
    166    is(beforeInputEvents.length, 1,
    167      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    168    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    169    is(inputEvents.length, 1,
    170      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    171    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    172  }
    173 
    174  description = "When there is a <b> element which has an <i> element and ";
    175  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    176    editor.innerHTML = "<p>test: <b><i>here</i></b> is bolden and italic text</p>";
    177    editor.focus();
    178    beforeInputEvents = [];
    179    inputEvents = [];
    180    prepare(editor.firstChild.firstChild.nextSibling);
    181    getHTMLEditor().removeInlineProperty("i", "");
    182    is(editor.innerHTML, "<p>test: <b>here</b> is bolden and italic text</p>",
    183      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should remove only the <i> element');
    184    is(beforeInputEvents.length, 1,
    185      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause a "beforeinput" event');
    186    checkInputEvent(beforeInputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    187    is(inputEvents.length, 1,
    188      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause an "input" event');
    189    checkInputEvent(inputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    190  }
    191 
    192  description = "When there is an <i> element in a <b> element and ";
    193  for (let prepare of [selectNode, selectAllChildren, selectChildContents]) {
    194    editor.innerHTML = "<p>test: <b><i>here</i></b> is bolden and italic text</p>";
    195    editor.focus();
    196    beforeInputEvents = [];
    197    inputEvents = [];
    198    prepare(editor.firstChild.firstChild.nextSibling.firstChild);
    199    getHTMLEditor().removeInlineProperty("b", "");
    200    is(editor.innerHTML, "<p>test: <i>here</i> is bolden and italic text</p>",
    201      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should remove only the <b> element');
    202    is(beforeInputEvents.length, 1,
    203      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    204    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    205    is(inputEvents.length, 1,
    206      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    207    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    208  }
    209 
    210  description = "When there is an <i> element in a <b> element and ";
    211  for (let prepare of [selectNode, selectAllChildren, selectChildContents]) {
    212    editor.innerHTML = "<p>test: <b><i>here</i></b> is bolden and italic text</p>";
    213    editor.focus();
    214    beforeInputEvents = [];
    215    inputEvents = [];
    216    prepare(editor.firstChild.firstChild.nextSibling.firstChild);
    217    getHTMLEditor().removeInlineProperty("i", "");
    218    is(editor.innerHTML, "<p>test: <b>here</b> is bolden and italic text</p>",
    219      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should remove only the <i> element');
    220    is(beforeInputEvents.length, 1,
    221      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause a "beforeinput" event');
    222    checkInputEvent(beforeInputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    223    is(inputEvents.length, 1,
    224      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause an "input" event');
    225    checkInputEvent(inputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    226  }
    227 
    228  description = "When there is an <i> element between text nodes in a <b> element and ";
    229  for (let prepare of [selectNode, selectAllChildren, selectChildContents]) {
    230    editor.innerHTML = "<p>test: <b>h<i>e</i>re</b> is bolden and italic text</p>";
    231    editor.focus();
    232    beforeInputEvents = [];
    233    inputEvents = [];
    234    prepare(editor.firstChild.firstChild.nextSibling.firstChild.nextSibling);
    235    getHTMLEditor().removeInlineProperty("i", "");
    236    is(editor.innerHTML, "<p>test: <b>here</b> is bolden and italic text</p>",
    237      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should remove only the <i> element');
    238    is(beforeInputEvents.length, 1,
    239      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause a "beforeinput" event');
    240    checkInputEvent(beforeInputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    241    is(inputEvents.length, 1,
    242      description + condition + ': nsIHTMLEditor.removeInlineProperty("i", "") should cause an "input" event');
    243    checkInputEvent(inputEvents[0], "formatItalic", description + condition + ': nsIHTMLEditor.removeInlineProperty("i", ""): ');
    244  }
    245 
    246  description = "When there is an <i> element between text nodes in a <b> element and ";
    247  for (let prepare of [selectNode, selectAllChildren, selectChildContents]) {
    248    editor.innerHTML = "<p>test: <b>h<i>e</i>re</b> is bolden and italic text</p>";
    249    editor.focus();
    250    beforeInputEvents = [];
    251    inputEvents = [];
    252    prepare(editor.firstChild.firstChild.nextSibling.firstChild.nextSibling);
    253    getHTMLEditor().removeInlineProperty("b", "");
    254    is(editor.innerHTML, "<p>test: <b>h</b><i>e</i><b>re</b> is bolden and italic text</p>",
    255      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should split the <b> element');
    256    is(beforeInputEvents.length, 1,
    257      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause a "beforeinput" event');
    258    checkInputEvent(beforeInputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    259    is(inputEvents.length, 1,
    260      description + condition + ': nsIHTMLEditor.removeInlineProperty("b", "") should cause an "input" event');
    261    checkInputEvent(inputEvents[0], "formatBold", description + condition + ': nsIHTMLEditor.removeInlineProperty("b", ""): ');
    262  }
    263 
    264  description = "When there is an <a> element whose href attribute is not empty and ";
    265  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    266    editor.innerHTML = '<p>test: <a href="about:blank">here</a> is a link</p>';
    267    editor.focus();
    268    beforeInputEvents = [];
    269    inputEvents = [];
    270    prepare(editor.firstChild.firstChild.nextSibling);
    271    getHTMLEditor().removeInlineProperty("href", "");
    272    is(editor.innerHTML, "<p>test: here is a link</p>",
    273      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should remove the <a> element');
    274    is(beforeInputEvents.length, 1,
    275      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause a "beforeinput" event');
    276    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    277    is(inputEvents.length, 1,
    278      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause an "input" event');
    279    checkInputEvent(inputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    280  }
    281 
    282  // XXX In the case of "name", removeInlineProperty() does not the <a> element when name attribute is empty.
    283  description = "When there is an <a> element whose href attribute is empty and ";
    284  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    285    editor.innerHTML = '<p>test: <a href="">here</a> is a link</p>';
    286    editor.focus();
    287    beforeInputEvents = [];
    288    inputEvents = [];
    289    prepare(editor.firstChild.firstChild.nextSibling);
    290    getHTMLEditor().removeInlineProperty("href", "");
    291    is(editor.innerHTML, "<p>test: here is a link</p>",
    292      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should remove the <a> element');
    293    is(beforeInputEvents.length, 1,
    294      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause a "beforeinput" event');
    295    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    296    is(inputEvents.length, 1,
    297      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause an "input" event');
    298    checkInputEvent(inputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    299  }
    300 
    301  description = "When there is an <a> element which does not have href attribute and ";
    302  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    303    editor.innerHTML = "<p>test: <a>here</a> is an anchor</p>";
    304    editor.focus();
    305    beforeInputEvents = [];
    306    inputEvents = [];
    307    prepare(editor.firstChild.firstChild.nextSibling);
    308    getHTMLEditor().removeInlineProperty("href", "");
    309    is(editor.innerHTML, "<p>test: <a>here</a> is an anchor</p>",
    310      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should NOT remove the <a> element');
    311    is(beforeInputEvents.length, 1,
    312      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause a "beforeinput" event even though HTMLEditor will do nothing');
    313    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    314    is(inputEvents.length, 0,
    315      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should NOT cause an "input" event');
    316  }
    317 
    318  description = "When there is an <a> element whose name attribute is not empty and ";
    319  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    320    editor.innerHTML = '<p>test: <a name="foo">here</a> is a named anchor</p>';
    321    editor.focus();
    322    beforeInputEvents = [];
    323    inputEvents = [];
    324    prepare(editor.firstChild.firstChild.nextSibling);
    325    getHTMLEditor().removeInlineProperty("href", "");
    326    is(editor.innerHTML, '<p>test: <a name="foo">here</a> is a named anchor</p>',
    327      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should NOT remove the <a> element');
    328    is(beforeInputEvents.length, 1,
    329      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should cause a "beforeinput" event even though HTMLEditor will do nothing');
    330    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("href", ""): ');
    331    is(inputEvents.length, 0,
    332      description + condition + ': nsIHTMLEditor.removeInlineProperty("href", "") should NOT cause an "input" event');
    333  }
    334 
    335  description = "When there is an <a> element whose name attribute is not empty and ";
    336  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    337    editor.innerHTML = '<p>test: <a name="foo">here</a> is a named anchor</p>';
    338    editor.focus();
    339    beforeInputEvents = [];
    340    inputEvents = [];
    341    prepare(editor.firstChild.firstChild.nextSibling);
    342    getHTMLEditor().removeInlineProperty("name", "");
    343    is(editor.innerHTML, "<p>test: here is a named anchor</p>",
    344      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should remove the <a> element');
    345    is(beforeInputEvents.length, 1,
    346      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should cause a "beforeinput" event');
    347    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("name", ""): ');
    348    is(inputEvents.length, 1,
    349      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should cause an "input" event');
    350    checkInputEvent(inputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("name", ""): ');
    351  }
    352 
    353  // XXX In the case of "href", removeInlineProperty() removes the <a> element when href attribute is empty.
    354  description = "When there is an <a> element whose name attribute is empty and ";
    355  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    356    editor.innerHTML = '<p>test: <a name="">here</a> is a named anchor</p>';
    357    editor.focus();
    358    beforeInputEvents = [];
    359    inputEvents = [];
    360    prepare(editor.firstChild.firstChild.nextSibling);
    361    getHTMLEditor().removeInlineProperty("name", "");
    362    is(editor.innerHTML, '<p>test: <a name="">here</a> is a named anchor</p>',
    363      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT remove the <a> element');
    364    is(beforeInputEvents.length, 1,
    365      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should cause a "beforeinput" event even though HTMLEditor will do nothing');
    366    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("name", ""): ');
    367    is(inputEvents.length, 0,
    368      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT cause an "input" event');
    369  }
    370 
    371  description = "When there is an <a> element which does not have name attribute and ";
    372  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    373    editor.innerHTML = "<p>test: <a>here</a> is an anchor</p>";
    374    editor.focus();
    375    beforeInputEvents = [];
    376    inputEvents = [];
    377    prepare(editor.firstChild.firstChild.nextSibling);
    378    getHTMLEditor().removeInlineProperty("name", "");
    379    is(editor.innerHTML, "<p>test: <a>here</a> is an anchor</p>",
    380      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT remove the <a> element');
    381    is(beforeInputEvents.length, 1,
    382      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should cause a "beforeinput" event even though HTMLEditor will do nothing');
    383    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "")');
    384    is(inputEvents.length, 0,
    385      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT cause an "input" event');
    386  }
    387 
    388  description = "When there is an <a> element whose href attribute is not empty and ";
    389  for (let prepare of [selectFromTextSiblings, selectNode, selectAllChildren, selectChildContents]) {
    390    editor.innerHTML = '<p>test: <a href="about:blank">here</a> is a link</p>';
    391    editor.focus();
    392    beforeInputEvents = [];
    393    inputEvents = [];
    394    prepare(editor.firstChild.firstChild.nextSibling);
    395    getHTMLEditor().removeInlineProperty("name", "");
    396    is(editor.innerHTML, '<p>test: <a href="about:blank">here</a> is a link</p>',
    397      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT remove the <a> element');
    398    is(beforeInputEvents.length, 1,
    399      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should cause a "beforeinput" event even though HTMLEditor will do nothing');
    400    checkInputEvent(beforeInputEvents[0], "", description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "")');
    401    is(inputEvents.length, 0,
    402      description + condition + ': nsIHTMLEditor.removeInlineProperty("name", "") should NOT cause an "input" event');
    403  }
    404 
    405  editor.removeEventListener("beforeinput", onBeforeInput);
    406  editor.removeEventListener("input", onInput);
    407 
    408  SimpleTest.finish();
    409 });
    410 
    411 function getHTMLEditor() {
    412  var Ci = SpecialPowers.Ci;
    413  var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
    414  return editingSession.getEditorForWindow(window).QueryInterface(Ci.nsIHTMLEditor);
    415 }
    416 
    417 </script>
    418 </body>
    419 
    420 </html>