tor-browser

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

input-events-get-target-ranges-deleting-in-list-items.tentative.html (57167B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <meta name="timeout" content="long">
      4 <meta name="variant" content="?Backspace,ul">
      5 <meta name="variant" content="?Backspace,ol">
      6 <meta name="variant" content="?Delete,ul">
      7 <meta name="variant" content="?Delete,ol">
      8 <title>InputEvent.getTargetRanges() at deleting in/around/across list item elements</title>
      9 <div contenteditable></div>
     10 <script src="input-events-get-target-ranges.js"></script>
     11 <script src="/resources/testharness.js"></script>
     12 <script src="/resources/testharnessreport.js"></script>
     13 <script src="/resources/testdriver.js"></script>
     14 <script src="/resources/testdriver-vendor.js"></script>
     15 <script src="/resources/testdriver-actions.js"></script>
     16 <script>
     17 "use strict";
     18 
     19 const [action, list] = location.search.substring(1).split(",");
     20 function run() {
     21  switch (action) {
     22    case "Backspace":
     23      return sendBackspaceKey();
     24    case "Delete":
     25      return sendDeleteKey();
     26    default:
     27      throw "Unhandled variant";
     28  }
     29 }
     30 
     31 /**
     32 * @param innerHTML     Initial `innerHTML` value of the editor.
     33 * @param data
     34 *          expectedInnerHTML
     35 *                      Expected `innerHTML` of the editor after calling
     36 *                      `run()`.  This can be array of string if there are
     37 *                      some acceptable differences like whether there is
     38 *                      an invisible `<br>` element at end of list item.
     39 *          expectedTargetRanges
     40 *                      `null` or `unspecified` if `beforeinput` event shouldn't
     41 *                      be fired.
     42 *                      Otherwise, function returning an array of objects
     43 *                      which have `startContainer`, `startOffset`,
     44 *                      `endContainer`, `endOffset`.  This will be called
     45 *                      before calling `run()` and compared with
     46 *                      `getTargetRanges()` after that.
     47 *          expectInputEvent:
     48 *                      `true` if it should cause an `input` event.
     49 */
     50 function addPromiseTest(innerHTML, data) {
     51  promise_test(async (t) => {
     52    initializeTest(innerHTML);
     53    let expectedTargetRanges =
     54      typeof data.expectedTargetRanges === "function"
     55        ? data.expectedTargetRanges()
     56        : null;
     57    await run();
     58    checkEditorContentResultAsSubTest(data.expectedInnerHTML, t.name);
     59    if (expectedTargetRanges !== null) {
     60      checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedTargetRanges);
     61      if (data.expectInputEvent) {
     62        checkGetTargetRangesOfInputOnDeleteSomething();
     63      } else {
     64        checkGetTargetRangesOfInputOnDoNothing();
     65      }
     66    } else {
     67      checkBeforeinputAndInputEventsOnNOOP();
     68    }
     69  }, `${action} at "${innerHTML}"`);
     70 }
     71 
     72 addPromiseTest(
     73  `<${list}><li>list[-item1</li><li>list]-item2</li></${list}>`,
     74  {
     75    expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`,
     76    expectedTargetRanges: () => {
     77      return [
     78        {
     79          startContainer: gEditor.querySelector("li").firstChild,
     80          startOffset: "list".length,
     81          endContainer: gEditor.querySelector("li + li").firstChild,
     82          endOffset: "list".length,
     83        },
     84      ];
     85    },
     86    expectInputEvent: true,
     87  }
     88 );
     89 
     90 addPromiseTest(
     91  `<${list}><li>list-[item1</li><li>]list-item2</li></${list}>`,
     92  {
     93    expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`,
     94    expectedTargetRanges: () => {
     95      return [
     96        {
     97          startContainer: gEditor.querySelector("li").firstChild,
     98          startOffset: "list-".length,
     99          endContainer: gEditor.querySelector("li + li").firstChild,
    100          endOffset: 0,
    101        },
    102      ];
    103    },
    104    expectInputEvent: true,
    105  }
    106 );
    107 
    108 addPromiseTest(
    109  `<${list}><li>list-[item1</li><li>}list-item2</li></${list}>`,
    110  {
    111    expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`,
    112    expectedTargetRanges: () => {
    113      return [
    114        {
    115          startContainer: gEditor.querySelector("li").firstChild,
    116          startOffset: "list-".length,
    117          endContainer: gEditor.querySelector("li + li"),
    118          endOffset: 0,
    119        },
    120      ];
    121    },
    122    expectInputEvent: true,
    123  }
    124 );
    125 
    126 addPromiseTest(
    127  `<${list}><li>list-item1[</li><li>list]-item2</li></${list}>`,
    128  {
    129    expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`,
    130    expectedTargetRanges: () => {
    131      return [
    132        {
    133          startContainer: gEditor.querySelector("li").firstChild,
    134          startOffset: gEditor.querySelector("li").firstChild.length,
    135          endContainer: gEditor.querySelector("li + li").firstChild,
    136          endOffset: "list".length,
    137        },
    138      ];
    139    },
    140    expectInputEvent: true,
    141  }
    142 );
    143 
    144 addPromiseTest(
    145  `<${list}><li>list-item1{</li><li>list]-item2</li></${list}>`,
    146  {
    147    expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`,
    148    expectedTargetRanges: () => {
    149      return [
    150        {
    151          startContainer: gEditor.querySelector("li"),
    152          startOffset: 1,
    153          endContainer: gEditor.querySelector("li + li").firstChild,
    154          endOffset: "list".length,
    155        },
    156      ];
    157    },
    158    expectInputEvent: true,
    159  }
    160 );
    161 
    162 addPromiseTest(
    163  `<${list}><li>list-item1[</li><li>]list-item2</li></${list}>`,
    164  {
    165    expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
    166    expectedTargetRanges: () => {
    167      return [
    168        {
    169          startContainer: gEditor.querySelector("li").firstChild,
    170          startOffset: gEditor.querySelector("li").firstChild.length,
    171          endContainer: gEditor.querySelector("li + li").firstChild,
    172          endOffset: 0,
    173        },
    174      ];
    175    },
    176    expectInputEvent: true,
    177  }
    178 );
    179 
    180 addPromiseTest(
    181  action === "Backspace"
    182    ? `<${list}><li>list-item1</li><li>[]list-item2</li></${list}>`
    183    : `<${list}><li>list-item1[]</li><li>list-item2</li></${list}>`,
    184  {
    185    expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
    186    expectedTargetRanges: () => {
    187      return [
    188        {
    189          startContainer: gEditor.querySelector("li").firstChild,
    190          startOffset: gEditor.querySelector("li").firstChild.length,
    191          endContainer: gEditor.querySelector("li + li").firstChild,
    192          endOffset: 0,
    193        },
    194      ];
    195    },
    196    expectInputEvent: true,
    197  }
    198 );
    199 
    200 addPromiseTest(
    201  action === "Backspace"
    202    ? `<${list}><li>list-item1<br></li><li>[]list-item2</li></${list}>`
    203    : `<${list}><li>list-item1[]<br></li><li>list-item2</li></${list}>`,
    204  {
    205    expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
    206    expectedTargetRanges: () => {
    207      return action === "Backspace"
    208        ? [
    209            {
    210              startContainer: gEditor.querySelector("li"),
    211              startOffset: 1,
    212              endContainer: gEditor.querySelector("li + li").firstChild,
    213              endOffset: 0,
    214            },
    215          ]
    216        : [
    217            {
    218              startContainer: gEditor.querySelector("li").firstChild,
    219              startOffset: gEditor.querySelector("li").firstChild.length,
    220              endContainer: gEditor.querySelector("li + li").firstChild,
    221              endOffset: 0,
    222            },
    223          ];
    224    },
    225    expectInputEvent: true,
    226  }
    227 );
    228 
    229 addPromiseTest(
    230  action === "Backspace"
    231    ? `<${list}><li>list-item1<br><br></li><li>[]list-item2</li></${list}>`
    232    : `<${list}><li>list-item1[]<br><br></li><li>list-item2</li></${list}>`,
    233  {
    234    expectedInnerHTML: [
    235      `<${list}><li>list-item1<br>list-item2</li></${list}>`,
    236      `<${list}><li>list-item1<br>list-item2<br></li></${list}>`,
    237    ],
    238    expectedTargetRanges: () => {
    239      return action === "Backspace"
    240        ? [
    241            {
    242              startContainer: gEditor.querySelector("li"),
    243              startOffset: 1,
    244              endContainer: gEditor.querySelector("li + li").firstChild,
    245              endOffset: 0,
    246            },
    247          ]
    248        : [
    249            {
    250              startContainer: gEditor.querySelector("li").firstChild,
    251              startOffset: gEditor.querySelector("li").firstChild.length,
    252              endContainer: gEditor.querySelector("li + li").firstChild,
    253              endOffset: 0,
    254            },
    255          ];
    256    },
    257    expectInputEvent: true,
    258  }
    259 );
    260 
    261 addPromiseTest(
    262  action === "Backspace"
    263    ? `<${list}><li>list-item1</li><li>[]list-item2<br>second line of list-item2</li></${list}>`
    264    : `<${list}><li>list-item1[]</li><li>list-item2<br>second line of list-item2</li></${list}>`,
    265  {
    266    expectedInnerHTML: `<${list}><li>list-item1list-item2</li><li>second line of list-item2</li></${list}>`,
    267    expectedTargetRanges: () => {
    268      return action === "Backspace"
    269        ? [
    270            {
    271              startContainer: gEditor.querySelector("li"),
    272              startOffset: 1,
    273              endContainer: gEditor.querySelector("li + li").firstChild,
    274              endOffset: 0,
    275            },
    276          ]
    277        : [
    278            {
    279              startContainer: gEditor.querySelector("li").firstChild,
    280              startOffset: gEditor.querySelector("li").firstChild.length,
    281              endContainer: gEditor.querySelector("li + li").firstChild,
    282              endOffset: 0,
    283            },
    284          ];
    285    },
    286    expectInputEvent: true,
    287  }
    288 );
    289 
    290 addPromiseTest(
    291  action === "Backspace"
    292    ? `<${list}><li><p>list-item1</p></li><li>[]list-item2</li></${list}>`
    293    : `<${list}><li><p>list-item1[]</p></li><li>list-item2</li></${list}>`,
    294  {
    295    expectedInnerHTML: `<${list}><li><p>list-item1list-item2</p></li></${list}>`,
    296    expectedTargetRanges: () => {
    297      return action === "Backspace"
    298        ? [
    299            {
    300              startContainer: gEditor.querySelector("p").firstChild,
    301              startOffset: gEditor.querySelector("p").firstChild.length,
    302              endContainer: gEditor.querySelector("li + li").firstChild,
    303              endOffset: 0,
    304            },
    305          ]
    306        : [
    307            {
    308              startContainer: gEditor.querySelector("p").firstChild,
    309              startOffset: gEditor.querySelector("p").firstChild.length,
    310              endContainer: gEditor.querySelector("li + li").firstChild,
    311              endOffset: 0,
    312            },
    313          ];
    314    },
    315    expectInputEvent: true,
    316  }
    317 );
    318 
    319 addPromiseTest(
    320  action === "Backspace"
    321    ? `<${list}><li>list-item1</li><li><p>[]list-item2</p></li></${list}>`
    322    : `<${list}><li>list-item1[]</li><li><p>list-item2</p></li></${list}>`,
    323  {
    324    expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
    325    expectedTargetRanges: () => {
    326      return action === "Backspace"
    327        ? [
    328            {
    329              startContainer: gEditor.querySelector("li").firstChild,
    330              startOffset: gEditor.querySelector("li").firstChild.length,
    331              endContainer: gEditor.querySelector("p").firstChild,
    332              endOffset: 0,
    333            },
    334          ]
    335        : [
    336            {
    337              startContainer: gEditor.querySelector("li").firstChild,
    338              startOffset: gEditor.querySelector("li").firstChild.length,
    339              endContainer: gEditor.querySelector("p").firstChild,
    340              endOffset: 0,
    341            },
    342          ];
    343    },
    344    expectInputEvent: true,
    345  }
    346 );
    347 
    348 addPromiseTest(
    349  `<${list}><li>[list-item1]</li></${list}>`,
    350  {
    351    expectedInnerHTML: `<${list}><li><br></li></${list}>`,
    352    expectedTargetRanges: () => {
    353      return [
    354        {
    355          startContainer: gEditor.querySelector("li").firstChild,
    356          startOffset: 0,
    357          endContainer: gEditor.querySelector("li").firstChild,
    358          endOffset: gEditor.querySelector("li").firstChild.length,
    359        },
    360      ];
    361    },
    362    expectInputEvent: true,
    363  }
    364 );
    365 
    366 addPromiseTest(
    367  `<${list}><li>{list-item1}</li></${list}>`,
    368  {
    369    expectedInnerHTML: `<${list}><li><br></li></${list}>`,
    370    expectedTargetRanges: () => {
    371      return [
    372        {
    373          startContainer: gEditor.querySelector("li").firstChild,
    374          startOffset: 0,
    375          endContainer: gEditor.querySelector("li").firstChild,
    376          endOffset: gEditor.querySelector("li").firstChild.length,
    377        },
    378      ];
    379    },
    380    expectInputEvent: true,
    381  }
    382 );
    383 
    384 // Even if the last list item is selected, don't delete the list and
    385 // the last list item element.  This is a triple click case on Gecko.
    386 addPromiseTest(
    387  `<${list}>{<li>list-item1</li>}</${list}>`,
    388  {
    389    expectedInnerHTML: `<${list}><li><br></li></${list}>`,
    390    expectedTargetRanges: () => {
    391      return [
    392        {
    393          startContainer: gEditor.querySelector("li").firstChild,
    394          startOffset: 0,
    395          endContainer: gEditor.querySelector("li").firstChild,
    396          endOffset: gEditor.querySelector("li").firstChild.length,
    397        },
    398      ];
    399    },
    400    expectInputEvent: true,
    401  }
    402 );
    403 
    404 // A list item is selected and it's not the last one, can delete it.
    405 addPromiseTest(
    406  `<${list}>{<li>list-item1</li>}<li>list-item2</li></${list}>`,
    407  {
    408    expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`,
    409    expectedTargetRanges: () => {
    410      return [
    411        {
    412          startContainer: gEditor.querySelector(`${list}`),
    413          startOffset: 0,
    414          endContainer: gEditor.querySelector(`${list}`),
    415          endOffset: 1,
    416        },
    417      ];
    418    },
    419    expectInputEvent: true,
    420  }
    421 );
    422 
    423 // Delete list element when deleting from empty last list item.
    424 addPromiseTest(
    425  `<${list}><li>{}<br></li></${list}>`,
    426  {
    427    expectedInnerHTML: ["", "<br>", "<div><br></div>"],
    428    expectedTargetRanges: () => {
    429      return [
    430        {
    431          startContainer: gEditor,
    432          startOffset: 0,
    433          endContainer: gEditor,
    434          endOffset: 1,
    435        },
    436      ];
    437    },
    438    expectInputEvent: true,
    439  }
    440 );
    441 
    442 addPromiseTest(
    443  `{<${list}><li><br></li></${list}>}`,
    444  {
    445    expectedInnerHTML: ["", "<br>", "<div><br></div>"],
    446    expectedTargetRanges: () => {
    447      return [
    448        {
    449          startContainer: gEditor,
    450          startOffset: 0,
    451          endContainer: gEditor,
    452          endOffset: 1,
    453        },
    454      ];
    455    },
    456    expectInputEvent: true,
    457  }
    458 );
    459 
    460 addPromiseTest(
    461  `<div>{<${list}><li><br></li></${list}>}</div>`,
    462  {
    463    expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"],
    464    expectedTargetRanges: () => {
    465      return [
    466        {
    467          startContainer: gEditor.querySelector("div"),
    468          startOffset: 0,
    469          endContainer: gEditor.querySelector("div"),
    470          endOffset: 1,
    471        },
    472      ];
    473    },
    474    expectInputEvent: true,
    475  }
    476 );
    477 
    478 // It may be better to ignore the invisible white-space and take same action
    479 // as above, but it requires more expensive check before deleting.  So perhaps,
    480 // this behavior is reasonable.
    481 addPromiseTest(
    482  `<div>{  <${list}><li><br></li></${list}>  }</div>`,
    483  {
    484    expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"],
    485    expectedTargetRanges: () => {
    486      return [
    487        {
    488          startContainer: gEditor.querySelector("div"),
    489          startOffset: 0,
    490          endContainer: gEditor.querySelector("div"),
    491          endOffset: 3,
    492        },
    493      ];
    494    },
    495    expectInputEvent: true,
    496  }
    497 );
    498 
    499 addPromiseTest(
    500  `<div><${list}><li>{}<br></li></${list}></div>`,
    501  {
    502    expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"],
    503    expectedTargetRanges: () => {
    504      return [
    505        {
    506          startContainer: gEditor.querySelector("div"),
    507          startOffset: 0,
    508          endContainer: gEditor.querySelector("div"),
    509          endOffset: 1,
    510        },
    511      ];
    512    },
    513    expectInputEvent: true,
    514  }
    515 );
    516 
    517 // XXX Blink does not delete the list element if its first or last <li> element
    518 //     is not editable.  However, it means that user cannot delete the list
    519 //     element, and it's not consistent behavior when only middle list item(s)
    520 //     are not editable.  Perhaps, once it makes the list element has only
    521 //     one empty list item element, then, another deleting operation allows to
    522 //     delete the list element.
    523 addPromiseTest(
    524  `<div>{<${list}><li contenteditable="false"><br></li></${list}>}</div>`,
    525  {
    526    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    527    expectedTargetRanges: () => {
    528      return [
    529        {
    530          startContainer: gEditor.querySelector(list),
    531          startOffset: 0,
    532          endContainer: gEditor.querySelector(list),
    533          endOffset: 1,
    534        },
    535      ];
    536    },
    537    expectInputEvent: true,
    538  }
    539 );
    540 
    541 addPromiseTest(
    542  `<div>{<${list}><li contenteditable="false">list-item1</li></${list}>}</div>`,
    543  {
    544    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    545    expectedTargetRanges: () => {
    546      return [
    547        {
    548          startContainer: gEditor.querySelector(list),
    549          startOffset: 0,
    550          endContainer: gEditor.querySelector(list),
    551          endOffset: 1,
    552        },
    553      ];
    554    },
    555    expectInputEvent: true,
    556  }
    557 );
    558 
    559 addPromiseTest(
    560  `<div>{<${list}><li contenteditable="false">list-item1</li><li><br></li></${list}>}</div>`,
    561  {
    562    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    563    expectedTargetRanges: () => {
    564      return [
    565        {
    566          startContainer: gEditor.querySelector(list),
    567          startOffset: 0,
    568          endContainer: gEditor.querySelector("li + li"),
    569          endOffset: 1,
    570        },
    571      ];
    572    },
    573    expectInputEvent: true,
    574  }
    575 );
    576 
    577 addPromiseTest(
    578  `<div>{<${list}><li contenteditable="false">list-item1</li><li>list-item2</li></${list}>}</div>`,
    579  {
    580    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    581    expectedTargetRanges: () => {
    582      return [
    583        {
    584          startContainer: gEditor.querySelector(list),
    585          startOffset: 0,
    586          endContainer: gEditor.querySelector("li + li").firstChild,
    587          endOffset: gEditor.querySelector("li + li").firstChild.length,
    588        },
    589      ];
    590    },
    591    expectInputEvent: true,
    592  }
    593 );
    594 
    595 addPromiseTest(
    596  `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li></${list}>}</div>`,
    597  {
    598    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    599    expectedTargetRanges: () => {
    600      return [
    601        {
    602          startContainer: gEditor.querySelector("li").firstChild,
    603          startOffset: 0,
    604          endContainer: gEditor.querySelector(list),
    605          endOffset: 2,
    606        },
    607      ];
    608    },
    609    expectInputEvent: true,
    610  }
    611 );
    612 
    613 addPromiseTest(
    614  `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li></${list}>}</div>`,
    615  {
    616    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    617    expectedTargetRanges: () => {
    618      return [
    619        {
    620          startContainer: gEditor.querySelector("li").firstChild,
    621          startOffset: 0,
    622          endContainer: gEditor.querySelector(list),
    623          endOffset: 2,
    624        },
    625      ];
    626    },
    627    expectInputEvent: true,
    628  }
    629 );
    630 
    631 addPromiseTest(
    632  `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li><li><br></li></${list}>}</div>`,
    633  {
    634    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    635    expectedTargetRanges: () => {
    636      return [
    637        {
    638          startContainer: gEditor.querySelector("li").firstChild,
    639          startOffset: 0,
    640          endContainer: gEditor.querySelector("li + li + li"),
    641          endOffset: 1,
    642        },
    643      ];
    644    },
    645    expectInputEvent: true,
    646  }
    647 );
    648 
    649 addPromiseTest(
    650  `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li><li>list-item3</li></${list}>}</div>`,
    651  {
    652    expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`,
    653    expectedTargetRanges: () => {
    654      return [
    655        {
    656          startContainer: gEditor.querySelector("li").firstChild,
    657          startOffset: 0,
    658          endContainer: gEditor.querySelector("li + li + li").firstChild,
    659          endOffset: gEditor.querySelector("li + li + li").firstChild.length,
    660        },
    661      ];
    662    },
    663    expectInputEvent: true,
    664  }
    665 );
    666 
    667 addPromiseTest(
    668  `<${list}><li>list-item1</li>{<li>list-item2</li>}<li>list-item3</li></${list}>`,
    669  {
    670    expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item3</li></${list}>`,
    671    expectedTargetRanges: () => {
    672      return [
    673        {
    674          startContainer: gEditor.querySelector(`${list}`),
    675          startOffset: 1,
    676          endContainer: gEditor.querySelector(`${list}`),
    677          endOffset: 2,
    678        },
    679      ];
    680    },
    681    expectInputEvent: true,
    682  }
    683 );
    684 
    685 // Selecting last list item element shouldn't delete the list item.
    686 addPromiseTest(
    687  `<${list}><li>list-item1</li>{<li>list-item2</li>}</${list}>`,
    688  {
    689    expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`,
    690    expectedTargetRanges: () => {
    691      return [
    692        {
    693          startContainer: gEditor.querySelector(`${list} > li + li`).firstChild,
    694          startOffset: 0,
    695          endContainer: gEditor.querySelector(`${list} > li + li`).firstChild,
    696          endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length,
    697        },
    698      ];
    699    },
    700    expectInputEvent: true,
    701  }
    702 );
    703 
    704 addPromiseTest(
    705  `<${list}><li>list-item1</li><li>list-item2</li>{<li>list-item3</li>}</${list}>`,
    706  {
    707    expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`,
    708    expectedTargetRanges: () => {
    709      return [
    710        {
    711          startContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild,
    712          startOffset: 0,
    713          endContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild,
    714          endOffset: gEditor.querySelector(`${list} > li + li + li`).firstChild.length,
    715        },
    716      ];
    717    },
    718    expectInputEvent: true,
    719  }
    720 );
    721 
    722 for (let childList of ["ul", "ol"]) {
    723  addPromiseTest(
    724    `<${list}><li>list-item1</li>{<li>list-item2</li>}<li><${childList}><li><br></li></${childList}></li></${list}>`,
    725    {
    726      expectedInnerHTML: `<${list}><li>list-item1</li><li><${childList}><li><br></li></${childList}></li></${list}>`,
    727      expectedTargetRanges: () => {
    728        return [
    729          {
    730            startContainer: gEditor.querySelector(`${list}`),
    731            startOffset: 1,
    732            endContainer: gEditor.querySelector(`${list}`),
    733            endOffset: 2,
    734          },
    735        ];
    736      },
    737      expectInputEvent: true,
    738    }
    739  );
    740 
    741  // Invalid nested list elements cases.  Treat the nested list element as a list item element.
    742  addPromiseTest(
    743    `<${list}><li>list-item1</li>{<li>list-item2</li>}<${childList}><li><br></li></${childList}></${list}>`,
    744    {
    745      expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li><br></li></${childList}></${list}>`,
    746      expectedTargetRanges: () => {
    747        return [
    748          {
    749            startContainer: gEditor.querySelector(`${list}`),
    750            startOffset: 1,
    751            endContainer: gEditor.querySelector(`${list}`),
    752            endOffset: 2,
    753          },
    754        ];
    755      },
    756      expectInputEvent: true,
    757    }
    758  );
    759 
    760  addPromiseTest(
    761    `<${list}><li>list-item1</li><li>list-item2</li>{<${childList}><li><br></li></${childList}>}</${list}>`,
    762    {
    763      expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`,
    764      expectedTargetRanges: () => {
    765        return [
    766          {
    767            startContainer: gEditor.querySelector(`${list}`),
    768            startOffset: 2,
    769            endContainer: gEditor.querySelector(`${list}`),
    770            endOffset: 3,
    771          },
    772        ];
    773      },
    774      expectInputEvent: true,
    775    }
    776  );
    777 }
    778 
    779 // Don't delete list and joined list items when only there content are selected.
    780 addPromiseTest(
    781  `<${list}><li>[list-item1</li><li>list-item2]</li></${list}>`,
    782  {
    783    expectedInnerHTML: `<${list}><li><br></li></${list}>`,
    784    expectedTargetRanges: () => {
    785      return [
    786        {
    787          startContainer: gEditor.querySelector("li").firstChild,
    788          startOffset: 0,
    789          endContainer: gEditor.querySelector("li + li").firstChild,
    790          endOffset: gEditor.querySelector("li + li").firstChild.length,
    791        },
    792      ];
    793    },
    794    expectInputEvent: true,
    795  }
    796 );
    797 
    798 addPromiseTest(
    799  `<${list}><li>[list-item1</li><li>list-item2]</li><li>list-item3</li></${list}>`,
    800  {
    801    expectedInnerHTML: `<${list}><li><br></li><li>list-item3</li></${list}>`,
    802    expectedTargetRanges: () => {
    803      return [
    804        {
    805          startContainer: gEditor.querySelector("li").firstChild,
    806          startOffset: 0,
    807          endContainer: gEditor.querySelector("li + li").firstChild,
    808          endOffset: gEditor.querySelector("li + li").firstChild.length,
    809        },
    810      ];
    811    },
    812    expectInputEvent: true,
    813  }
    814 );
    815 
    816 addPromiseTest(
    817  `<${list}><li>list-item1</li><li>[list-item2]</li><li>list-item3</li></${list}>`,
    818  {
    819    expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li><li>list-item3</li></${list}>`,
    820    expectedTargetRanges: () => {
    821      return [
    822        {
    823          startContainer: gEditor.querySelector("li + li").firstChild,
    824          startOffset: 0,
    825          endContainer: gEditor.querySelector("li + li").firstChild,
    826          endOffset: gEditor.querySelector("li + li").firstChild.length,
    827        },
    828      ];
    829    },
    830    expectInputEvent: true,
    831  }
    832 );
    833 
    834 addPromiseTest(
    835  `<${list}><li>list-item1</li><li>[list-item2</li><li>list-item3]</li></${list}>`,
    836  {
    837    expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`,
    838    expectedTargetRanges: () => {
    839      return [
    840        {
    841          startContainer: gEditor.querySelector("li + li").firstChild,
    842          startOffset: 0,
    843          endContainer: gEditor.querySelector("li + li + li").firstChild,
    844          endOffset: gEditor.querySelector("li + li + li").firstChild.length,
    845        },
    846      ];
    847    },
    848    expectInputEvent: true,
    849  }
    850 );
    851 
    852 // Ported tests from editing/delete.js and editing/forwarddelete.js
    853 for (let otherList of ["ul", "ol"]) {
    854  if (action === "Backspace") {
    855  addPromiseTest(
    856    `<${otherList}><li>list-item1</li></${otherList}><${list}><li>l[]ist-item2</li></${list}>`,
    857    {
    858      expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`,
    859      expectedTargetRanges: () => {
    860        return [
    861          {
    862            startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild,
    863            startOffset: 0,
    864            endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild,
    865            endOffset: "l".length,
    866          },
    867        ];
    868      },
    869      expectInputEvent: true,
    870    }
    871  );
    872 
    873  addPromiseTest(
    874    `<${list}><li>list-item1[]</li></${list}><${otherList}><li>list-item2</li></${otherList}>`,
    875    {
    876      expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`,
    877      expectedTargetRanges: () => {
    878        return [
    879          {
    880            startContainer: gEditor.querySelector("li").firstChild,
    881            startOffset: "list-item".length,
    882            endContainer: gEditor.querySelector("li").firstChild,
    883            endOffset: "list-item1".length,
    884          },
    885        ];
    886      },
    887      expectInputEvent: true,
    888    }
    889  );
    890  } else {
    891    addPromiseTest(
    892      `<${list}><li>list-item[]1</li></${list}><${otherList}><li>list-item2</li></${otherList}>`,
    893      {
    894        expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`,
    895        expectedTargetRanges: () => {
    896          return [
    897            {
    898              startContainer: gEditor.querySelector("li").firstChild,
    899              startOffset: "list-item".length,
    900              endContainer: gEditor.querySelector("li").firstChild,
    901              endOffset: "list-item1".length,
    902            },
    903          ];
    904        },
    905        expectInputEvent: true,
    906      }
    907    );
    908 
    909    addPromiseTest(
    910      `<${otherList}><li>list-item1</li></${otherList}><${list}><li>[]list-item2</li></${list}>`,
    911      {
    912        expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`,
    913        expectedTargetRanges: () => {
    914          return [
    915            {
    916              startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild,
    917              startOffset: 0,
    918              endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild,
    919              endOffset: "l".length,
    920            },
    921          ];
    922        },
    923        expectInputEvent: true,
    924      }
    925    );
    926  }
    927 
    928  addPromiseTest(
    929    `<${list}><li>list-item1[</li><li>list-item2]</li></${list}><${otherList}><li>list-item3</li></${otherList}>`,
    930    {
    931      expectedInnerHTML: `<${list}><li>list-item1</li></${list}><${otherList}><li>ist-item3</li><li>ist-item4</li></${otherList}>`,
    932      expectedTargetRanges: () => {
    933        return [
    934          {
    935            startContainer: gEditor.querySelector("li").firstChild,
    936            startOffset: gEditor.querySelector("li").firstChild.length,
    937            endContainer: gEditor.querySelector("li + li").firstChild,
    938            endOffset: gEditor.querySelector("li + li").firstChild.length,
    939          },
    940        ];
    941      },
    942      expectInputEvent: true,
    943    }
    944  );
    945 }
    946 
    947 
    948 // Invalid nested list element cases.  Traditionally, all browser engines
    949 // insert child list element without wrapping it with a list item element.
    950 // So, keeping the behavior in these cases are important for backward
    951 // compatibility.
    952 // https://bugzilla.mozilla.org/show_bug.cgi?id=487524
    953 for (let childList of ["ul", "ol"]) {
    954  addPromiseTest(
    955    `<${list}><li>[list-item1</li><${childList}><li>}list-item2</li></ul></${list}>`,
    956    {
    957      expectedInnerHTML: [
    958        `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`,
    959        `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`,
    960      ],
    961      expectedTargetRanges: () => {
    962        return [
    963          {
    964            startContainer: gEditor.querySelector("li").firstChild,
    965            startOffset: 0,
    966            endContainer: gEditor.querySelector(`${list} > ${childList} > li`),
    967            endOffset: 0,
    968          },
    969        ];
    970      },
    971      expectInputEvent: true,
    972    }
    973  );
    974 
    975  addPromiseTest(
    976    `<${list}><li>[list-item1</li><${childList}><li>list-item2]</li></${childList}></${list}>`,
    977    {
    978      expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`,
    979      expectedTargetRanges: () => {
    980        return [
    981          {
    982            startContainer: gEditor.querySelector("li").firstChild,
    983            startOffset: 0,
    984            endContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
    985            endOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length,
    986          },
    987        ];
    988      },
    989      expectInputEvent: true,
    990    }
    991  );
    992 
    993  addPromiseTest(
    994    `<${list}><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`,
    995    {
    996      expectedInnerHTML: [
    997        `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`,
    998        `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`,
    999      ],
   1000      expectedTargetRanges: () => {
   1001        return [
   1002          {
   1003            startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
   1004            startOffset: 0,
   1005            endContainer: gEditor.querySelector(`${list} > li`),
   1006            endOffset: 0,
   1007          },
   1008        ];
   1009      },
   1010      expectInputEvent: true,
   1011    }
   1012  );
   1013 
   1014  addPromiseTest(
   1015    `<${list}><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`,
   1016    {
   1017      expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`,
   1018      expectedTargetRanges: () => {
   1019        return [
   1020          {
   1021            startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
   1022            startOffset: 0,
   1023            endContainer: gEditor.querySelector(`${childList} + li`).firstChild,
   1024            endOffset: gEditor.querySelector(`${childList} + li`).firstChild.length,
   1025          },
   1026        ];
   1027      },
   1028      expectInputEvent: true,
   1029    }
   1030  );
   1031 
   1032  addPromiseTest(
   1033    `<${list}><${childList}><li>list-item1</li><li>[list-item2</li></${childList}><li>}list-item3</li></${list}>`,
   1034    {
   1035      expectedInnerHTML: `<${list}><${childList}><li>list-item1</li><li>list-item3</li></${childList}></${list}>`,
   1036      expectedTargetRanges: () => {
   1037        return [
   1038          {
   1039            startContainer: gEditor.querySelector(`${list} > ${childList} > li + li`).firstChild,
   1040            startOffset: 0,
   1041            endContainer: gEditor.querySelector(`${list} > li`),
   1042            endOffset: 0,
   1043          },
   1044        ];
   1045      },
   1046      expectInputEvent: true,
   1047    }
   1048  );
   1049 
   1050  addPromiseTest(
   1051    `<${list}><li>[list-item1</li><${childList}><li>list-item2</li><li>}list-item3</li></${childList}></${list}>`,
   1052    {
   1053      expectedInnerHTML: [
   1054        `<${list}><${childList}><li>list-item3</li></${childList}></${list}>`,
   1055        `<${list}><${childList}><li>list-item3<br></li></${childList}></${list}>`,
   1056      ],
   1057      expectedTargetRanges: () => {
   1058        return [
   1059          {
   1060            startContainer: gEditor.querySelector(`li`).firstChild,
   1061            startOffset: 0,
   1062            endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`),
   1063            endOffset: 0,
   1064          },
   1065        ];
   1066      },
   1067      expectInputEvent: true,
   1068    }
   1069  );
   1070 
   1071  addPromiseTest(
   1072    `<${list}><li>list-item1</li><li>[list-item2</li><${childList}><li>list-item3</li><li>}list-item4</li></${childList}></${list}>`,
   1073    {
   1074      expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li>list-item4</li></${childList}></${list}>`,
   1075      expectedTargetRanges: () => {
   1076        return [
   1077          {
   1078            startContainer: gEditor.querySelector(`li + li`).firstChild,
   1079            startOffset: 0,
   1080            endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`),
   1081            endOffset: 0,
   1082          },
   1083        ];
   1084      },
   1085      expectInputEvent: true,
   1086    }
   1087  );
   1088 
   1089  // Valid sub list element cases.
   1090  addPromiseTest(
   1091    `<${list}><li>[list-item1</li><li><${childList}><li>list-item2]</li></${childList}></li></${list}>`,
   1092    {
   1093      expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`,
   1094      expectedTargetRanges: () => {
   1095        return [
   1096          {
   1097            startContainer: gEditor.querySelector(`li`).firstChild,
   1098            startOffset: 0,
   1099            endContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1100            endOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length,
   1101          },
   1102        ];
   1103      },
   1104      expectInputEvent: true,
   1105    }
   1106  );
   1107 
   1108  addPromiseTest(
   1109    `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`,
   1110    {
   1111      expectedInnerHTML: [
   1112        `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`,
   1113        `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`,
   1114      ],
   1115      expectedTargetRanges: () => {
   1116        return [
   1117          {
   1118            startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1119            startOffset: 0,
   1120            endContainer: gEditor.querySelector(`${list} > li + li`),
   1121            endOffset: 0,
   1122          },
   1123        ];
   1124      },
   1125      expectInputEvent: true,
   1126    }
   1127  );
   1128 
   1129  addPromiseTest(
   1130    `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`,
   1131    {
   1132      expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`,
   1133      expectedTargetRanges: () => {
   1134        return [
   1135          {
   1136            startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1137            startOffset: 0,
   1138            endContainer: gEditor.querySelector(`${list} > li + li`).firstChild,
   1139            endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length,
   1140          },
   1141        ];
   1142      },
   1143      expectInputEvent: true,
   1144    }
   1145  );
   1146 }
   1147 
   1148 // When deleting the last list item in a sub list, only the list should
   1149 // be removed.  This makes users feel like doing outdent.
   1150 for (let childList of ["ul", "ol"]) {
   1151  addPromiseTest(
   1152    `<${list}><li><${childList}><li>{}<br></li></${childList}></li></${list}>`,
   1153    {
   1154      expectedInnerHTML: `<${list}><li><br></li></${list}>`,
   1155      expectedTargetRanges: () => {
   1156        return [
   1157          {
   1158            startContainer: gEditor.querySelector(`li`),
   1159            startOffset: 0,
   1160            endContainer: gEditor.querySelector(`li`),
   1161            endOffset: 1,
   1162          },
   1163        ];
   1164      },
   1165      expectInputEvent: true,
   1166    }
   1167  );
   1168 
   1169  addPromiseTest(
   1170    `<${list}><li><${childList}><li>[list-item1]</li></${childList}></li></${list}>`,
   1171    {
   1172      expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`,
   1173      expectedTargetRanges: () => {
   1174        return [
   1175          {
   1176            startContainer: gEditor.querySelector(`li li`).firstChild,
   1177            startOffset: 0,
   1178            endContainer: gEditor.querySelector(`li li`).firstChild,
   1179            endOffset: gEditor.querySelector(`li li`).firstChild.length,
   1180          },
   1181        ];
   1182      },
   1183      expectInputEvent: true,
   1184    }
   1185  );
   1186 
   1187  addPromiseTest(
   1188    `<${list}><li>{<${childList}><li>list-item1</li></${childList}>}</li></${list}>`,
   1189    {
   1190      expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`,
   1191      expectedTargetRanges: () => {
   1192        return [
   1193          {
   1194            startContainer: gEditor.querySelector(`li li`).firstChild,
   1195            startOffset: 0,
   1196            endContainer: gEditor.querySelector(`li li`).firstChild,
   1197            endOffset: gEditor.querySelector(`li li`).firstChild.length,
   1198          },
   1199        ];
   1200      },
   1201      expectInputEvent: true,
   1202    }
   1203  );
   1204 
   1205  addPromiseTest(
   1206    `<${list}><li><${childList}><li>{}<br></li></${childList}></li><li>list-item2</li></${list}>`,
   1207    {
   1208      expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`,
   1209      expectedTargetRanges: () => {
   1210        return [
   1211          {
   1212            startContainer: gEditor.querySelector(`li`),
   1213            startOffset: 0,
   1214            endContainer: gEditor.querySelector(`li`),
   1215            endOffset: 1,
   1216          },
   1217        ];
   1218      },
   1219      expectInputEvent: true,
   1220    }
   1221  );
   1222 
   1223  addPromiseTest(
   1224    `<${list}><li>list-item1</li><li><${childList}><li>{}<br></li></${childList}></li></${list}>`,
   1225    {
   1226      expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`,
   1227      expectedTargetRanges: () => {
   1228        return [
   1229          {
   1230            startContainer: gEditor.querySelector(`li + li`),
   1231            startOffset: 0,
   1232            endContainer: gEditor.querySelector(`li + li`),
   1233            endOffset: 1,
   1234          },
   1235        ];
   1236      },
   1237      expectInputEvent: true,
   1238    }
   1239  );
   1240 
   1241  // Invalid cases.
   1242  addPromiseTest(
   1243    `<${list}><${childList}><li>{}<br></li></${childList}></${list}>`,
   1244    {
   1245      expectedInnerHTML: `<${list}><li><br></li></${list}>`,
   1246      expectedTargetRanges: () => {
   1247        return [
   1248          {
   1249            startContainer: gEditor.querySelector(`${list}`),
   1250            startOffset: 0,
   1251            endContainer: gEditor.querySelector(`${list}`),
   1252            endOffset: 1,
   1253          },
   1254        ];
   1255      },
   1256      expectInputEvent: true,
   1257    }
   1258  );
   1259 
   1260  addPromiseTest(
   1261    `<${list}><${childList}><li>[list-item1]</li></${childList}></${list}>`,
   1262    {
   1263      expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`,
   1264      expectedTargetRanges: () => {
   1265        return [
   1266          {
   1267            startContainer: gEditor.querySelector(`li`).firstChild,
   1268            startOffset: 0,
   1269            endContainer: gEditor.querySelector(`li`).firstChild,
   1270            endOffset: gEditor.querySelector(`li`).firstChild.length,
   1271          },
   1272        ];
   1273      },
   1274      expectInputEvent: true,
   1275    }
   1276  );
   1277 
   1278  addPromiseTest(
   1279    `<${list}>{<${childList}><li>list-item1</li></${childList}>}</${list}>`,
   1280    {
   1281      expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`,
   1282      expectedTargetRanges: () => {
   1283        return [
   1284          {
   1285            startContainer: gEditor.querySelector(`li`).firstChild,
   1286            startOffset: 0,
   1287            endContainer: gEditor.querySelector(`li`).firstChild,
   1288            endOffset: gEditor.querySelector(`li`).firstChild.length,
   1289          },
   1290        ];
   1291      },
   1292      expectInputEvent: true,
   1293    }
   1294  );
   1295 
   1296  addPromiseTest(
   1297    `<${list}><${childList}><li>{}<br></li></${childList}><li>list-item2</li></${list}>`,
   1298    {
   1299      expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`,
   1300      expectedTargetRanges: () => {
   1301        return [
   1302          {
   1303            startContainer: gEditor.querySelector(`${list}`),
   1304            startOffset: 0,
   1305            endContainer: gEditor.querySelector(`${list}`),
   1306            endOffset: 1,
   1307          },
   1308        ];
   1309      },
   1310      expectInputEvent: true,
   1311    }
   1312  );
   1313 
   1314  addPromiseTest(
   1315    `<${list}><li>list-item1</li><${childList}><li>{}<br></li></${childList}></${list}>`,
   1316    {
   1317      expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`,
   1318      expectedTargetRanges: () => {
   1319        return [
   1320          {
   1321            startContainer: gEditor.querySelector(`${list}`),
   1322            startOffset: 1,
   1323            endContainer: gEditor.querySelector(`${list}`),
   1324            endOffset: 2,
   1325          },
   1326        ];
   1327      },
   1328      expectInputEvent: true,
   1329    }
   1330  );
   1331 }
   1332 
   1333 // Joining same level list elements.
   1334 for (let otherList of ["ul", "ol"]) {
   1335  addPromiseTest(
   1336    `<${list}><li>[list-item1</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`,
   1337    {
   1338      expectedInnerHTML: [
   1339        `<${list}><li>list-item2</li></${list}>`,
   1340        `<${list}><li>list-item2<br></li></${list}>`,
   1341      ],
   1342      expectedTargetRanges: () => {
   1343        return [
   1344          {
   1345            startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1346            startOffset: 0,
   1347            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1348            endOffset: 0,
   1349          },
   1350        ];
   1351      },
   1352      expectInputEvent: true,
   1353    }
   1354  );
   1355 
   1356  addPromiseTest(
   1357    `<${list}><li>[list-item1</li></${list}><${otherList}><li>list-item2]</li></${otherList}>`,
   1358    {
   1359      expectedInnerHTML: `<${list}><li><br></li></${list}>`,
   1360      expectedTargetRanges: () => {
   1361        return [
   1362          {
   1363            startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1364            startOffset: 0,
   1365            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1366            endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length,
   1367          },
   1368        ];
   1369      },
   1370      expectInputEvent: true,
   1371    }
   1372  );
   1373 
   1374  addPromiseTest(
   1375    `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`,
   1376    {
   1377      expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
   1378      expectedTargetRanges: () => {
   1379        return [
   1380          {
   1381            startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1382            startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1383            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1384            endOffset: 0,
   1385          },
   1386        ];
   1387      },
   1388      expectInputEvent: true,
   1389    }
   1390  );
   1391 
   1392  addPromiseTest(
   1393    `<${list}><li>first line in list-item1<br>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`,
   1394    {
   1395      expectedInnerHTML: `<${list}><li>first line in list-item1<br>list-item1list-item2</li></${list}>`,
   1396      expectedTargetRanges: () => {
   1397        return [
   1398          {
   1399            startContainer: gEditor.querySelector(`${list} > li > br`).nextSibling,
   1400            startOffset: gEditor.querySelector(`${list} > li > br`).nextSibling.length,
   1401            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1402            endOffset: 0,
   1403          },
   1404        ];
   1405      },
   1406      expectInputEvent: true,
   1407    }
   1408  );
   1409 
   1410  addPromiseTest(
   1411    `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2<br>second line in list-item2</li></${otherList}>`,
   1412    {
   1413      expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>second line in list-item2</li></${otherList}>`,
   1414      expectedTargetRanges: () => {
   1415        return [
   1416          {
   1417            startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1418            startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1419            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1420            endOffset: 0,
   1421          },
   1422        ];
   1423      },
   1424      expectInputEvent: true,
   1425    }
   1426  );
   1427 
   1428  addPromiseTest(
   1429    `<${list}><li>list-item1</li><li>list-item2[</li></${list}><${otherList}><li>}list-item3</li></${otherList}>`,
   1430    {
   1431      expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2list-item3</li></${list}>`,
   1432      expectedTargetRanges: () => {
   1433        return [
   1434          {
   1435            startContainer: gEditor.querySelector(`${list} > li + li`).firstChild,
   1436            startOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length,
   1437            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1438            endOffset: 0,
   1439          },
   1440        ];
   1441      },
   1442      expectInputEvent: true,
   1443    }
   1444  );
   1445 
   1446  addPromiseTest(
   1447    `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li><li>list-item3</li></${otherList}>`,
   1448    {
   1449      expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>list-item3</li></${otherList}>`,
   1450      expectedTargetRanges: () => {
   1451        return [
   1452          {
   1453            startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1454            startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1455            endContainer: gEditor.querySelector(`${list} + ${otherList} > li`),
   1456            endOffset: 0,
   1457          },
   1458        ];
   1459      },
   1460      expectInputEvent: true,
   1461    }
   1462  );
   1463 }
   1464 
   1465 // Joining nested left list and right list element.  Move the content in first line from selection end in the right
   1466 // list item element into end of the left list item element.
   1467 for (let childList of ["ul", "ol"]) {
   1468  for (let otherList of ["ul", "ol"]) {
   1469    addPromiseTest(
   1470      `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>}list-item2</li></${otherList}>`,
   1471      {
   1472        expectedInnerHTML: [
   1473          `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`,
   1474          `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`,
   1475        ],
   1476        expectedTargetRanges: () => {
   1477          return [
   1478            {
   1479              startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1480              startOffset: 0,
   1481              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1482              endOffset: 0,
   1483            },
   1484          ];
   1485        },
   1486        expectInputEvent: true,
   1487      }
   1488    );
   1489 
   1490    addPromiseTest(
   1491      `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`,
   1492      {
   1493        expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`,
   1494        expectedTargetRanges: () => {
   1495          return [
   1496            {
   1497              startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1498              startOffset: 0,
   1499              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1500              endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length,
   1501            },
   1502          ];
   1503        },
   1504        expectInputEvent: true,
   1505      }
   1506    );
   1507 
   1508    addPromiseTest(
   1509      `<${list}><li><${childList}><li>list-item1[</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`,
   1510      {
   1511        expectedInnerHTML: `<${list}><li><${childList}><li>list-item1</li></${childList}></li></${list}>`,
   1512        expectedTargetRanges: () => {
   1513          return [
   1514            {
   1515              startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild,
   1516              startOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length,
   1517              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1518              endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length,
   1519            },
   1520          ];
   1521        },
   1522        expectInputEvent: true,
   1523      }
   1524    );
   1525 
   1526    // Invalid cases.
   1527    addPromiseTest(
   1528      `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>}list-item2</li></${otherList}>`,
   1529      {
   1530        expectedInnerHTML: [
   1531          `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`,
   1532          `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`,
   1533        ],
   1534        expectedTargetRanges: () => {
   1535          return [
   1536            {
   1537              startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
   1538              startOffset: 0,
   1539              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1540              endOffset: 0,
   1541            },
   1542          ];
   1543        },
   1544        expectInputEvent: true,
   1545      }
   1546    );
   1547 
   1548    addPromiseTest(
   1549      `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`,
   1550      {
   1551        expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`,
   1552        expectedTargetRanges: () => {
   1553          return [
   1554            {
   1555              startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
   1556              startOffset: 0,
   1557              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1558              endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length,
   1559            },
   1560          ];
   1561        },
   1562        expectInputEvent: true,
   1563      }
   1564    );
   1565 
   1566    addPromiseTest(
   1567      `<${list}><${childList}><li>list-item1[</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`,
   1568      {
   1569        expectedInnerHTML: `<${list}><${childList}><li>list-item1</li></${childList}></${list}>`,
   1570        expectedTargetRanges: () => {
   1571          return [
   1572            {
   1573              startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild,
   1574              startOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length,
   1575              endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild,
   1576              endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length,
   1577            },
   1578          ];
   1579        },
   1580        expectInputEvent: true,
   1581      }
   1582    );
   1583  }
   1584 }
   1585 
   1586 // Joining left list and nested right list element.  Basically, the first line from the selection end should
   1587 // be moved into the end of the left list item element, but if all content in the left list is being deleted,
   1588 // keep the right list elements.
   1589 for (let childList of ["ul", "ol"]) {
   1590  for (let otherList of ["ul", "ol"]) {
   1591    addPromiseTest(
   1592      `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`,
   1593      {
   1594        expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
   1595        expectedTargetRanges: () => {
   1596          return [
   1597            {
   1598              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1599              startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1600              endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`),
   1601              endOffset: 0,
   1602            },
   1603          ];
   1604        },
   1605        expectInputEvent: true,
   1606      }
   1607    );
   1608 
   1609    addPromiseTest(
   1610      `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`,
   1611      {
   1612        expectedInnerHTML: [
   1613          `<${otherList}><li><${childList}><li>list-item2</li></${childList}></li></${otherList}>`,
   1614          `<${otherList}><li><${childList}><li>list-item2<br></li></${childList}></li></${otherList}>`,
   1615        ],
   1616        expectedTargetRanges: () => {
   1617          return [
   1618            {
   1619              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1620              startOffset: 0,
   1621              endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`),
   1622              endOffset: 0,
   1623            },
   1624          ];
   1625        },
   1626        expectInputEvent: true,
   1627      }
   1628    );
   1629 
   1630    addPromiseTest(
   1631      `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>list-item2]</li></${childList}></li></${otherList}>`,
   1632      {
   1633        expectedInnerHTML: `<${list}><li><br></li></${list}>`,
   1634        expectedTargetRanges: () => {
   1635          return [
   1636            {
   1637              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1638              startOffset: 0,
   1639              endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild,
   1640              endOffset: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild.length,
   1641            },
   1642          ];
   1643        },
   1644        expectInputEvent: true,
   1645      }
   1646    );
   1647 
   1648    addPromiseTest(
   1649      `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></li></${otherList}>`,
   1650      {
   1651        expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li><${childList}><li>second line of list-item2</li></${childList}></li></${otherList}>`,
   1652        expectedTargetRanges: () => {
   1653          return [
   1654            {
   1655              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1656              startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1657              endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`),
   1658              endOffset: 0,
   1659            },
   1660          ];
   1661        },
   1662        expectInputEvent: true,
   1663      }
   1664    );
   1665 
   1666    // Invalid cases.
   1667    addPromiseTest(
   1668      `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`,
   1669      {
   1670        expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`,
   1671        expectedTargetRanges: () => {
   1672          return [
   1673            {
   1674              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1675              startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1676              endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`),
   1677              endOffset: 0,
   1678            },
   1679          ];
   1680        },
   1681        expectInputEvent: true,
   1682      }
   1683    );
   1684 
   1685    addPromiseTest(
   1686      `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`,
   1687      {
   1688        expectedInnerHTML: [
   1689          `<${otherList}><${childList}><li>list-item2</li></${childList}></${otherList}>`,
   1690          `<${otherList}><${childList}><li>list-item2<br></li></${childList}></${otherList}>`,
   1691        ],
   1692        expectedTargetRanges: () => {
   1693          return [
   1694            {
   1695              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1696              startOffset: 0,
   1697              endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`),
   1698              endOffset: 0,
   1699            },
   1700          ];
   1701        },
   1702        expectInputEvent: true,
   1703      }
   1704    );
   1705 
   1706    addPromiseTest(
   1707      `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>list-item2]</li></${childList}></${otherList}>`,
   1708      {
   1709        expectedInnerHTML: `<${list}><li><br></li></${list}>`,
   1710        expectedTargetRanges: () => {
   1711          return [
   1712            {
   1713              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1714              startOffset: 0,
   1715              endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild,
   1716              endOffset: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild.length,
   1717            },
   1718          ];
   1719        },
   1720        expectInputEvent: true,
   1721      }
   1722    );
   1723 
   1724    addPromiseTest(
   1725      `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></${otherList}>`,
   1726      {
   1727        expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><${childList}><li>second line of list-item2</li></${childList}></${otherList}>`,
   1728        expectedTargetRanges: () => {
   1729          return [
   1730            {
   1731              startContainer: gEditor.querySelector(`${list} > li`).firstChild,
   1732              startOffset: gEditor.querySelector(`${list} > li`).firstChild.length,
   1733              endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`),
   1734              endOffset: 0,
   1735            },
   1736          ];
   1737        },
   1738        expectInputEvent: true,
   1739      }
   1740    );
   1741  }
   1742 }
   1743 
   1744 </script>