move-around-generated-content.html (7781B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Test for caret movement around generated content</title> 6 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1958985"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/resources/testdriver.js"></script> 10 <script src="/resources/testdriver-vendor.js"></script> 11 <script src="/resources/testdriver-actions.js"></script> 12 <script> 13 "use strict"; 14 15 function getRangeDescription(range) { 16 function getNodeDescription(node) { 17 if (!node) { 18 return "null"; 19 } 20 switch (node.nodeType) { 21 case Node.TEXT_NODE: 22 return `${node.nodeName} "${node.data}"`; 23 case Node.ELEMENT_NODE: 24 return `<${node.nodeName.toLowerCase()}>`; 25 default: 26 return `${node.nodeName}`; 27 } 28 } 29 if (range === null) { 30 return "null"; 31 } 32 if (range === undefined) { 33 return "undefined"; 34 } 35 return range.startContainer == range.endContainer && 36 range.startOffset == range.endOffset 37 ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})` 38 : `(${getNodeDescription(range.startContainer)}, ${ 39 range.startOffset 40 }) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`; 41 } 42 43 const kArrowLeft = "\uE012"; 44 const kArrowUp = "\uE013"; 45 const kArrowRight = "\uE014"; 46 const kArrowDown = "\uE015"; 47 48 function sendKey(k) { 49 return new test_driver.Actions().keyDown(k).keyUp(k).send(); 50 } 51 52 promise_test(async () => { 53 await new Promise(resolve => { 54 addEventListener("load", resolve, {once: true}); 55 }); 56 }, "Initializing tests"); 57 58 promise_test(async t => { 59 const editingHost = document.querySelector("#test1"); 60 editingHost.focus(); 61 const p = editingHost.querySelector("#a"); 62 63 test(() => { 64 assert_equals( 65 getRangeDescription(getSelection().getRangeAt(0)), 66 getRangeDescription({ 67 startContainer: editingHost.querySelector("#a").firstChild, 68 startOffset: 0, 69 endContainer: editingHost.querySelector("#a").firstChild, 70 endOffset: 0, 71 }), 72 ); 73 }, `${t.name}: caret should start at the beginning of the first line`); 74 75 await sendKey(kArrowDown); 76 test(() => { 77 assert_equals( 78 getRangeDescription(getSelection().getRangeAt(0)), 79 getRangeDescription({ 80 startContainer: editingHost.querySelector("#one").firstChild, 81 startOffset: 0, 82 endContainer: editingHost.querySelector("#one").firstChild, 83 endOffset: 0, 84 }), 85 ); 86 }, `${t.name}: arrow-down should move the caret to the start of the first list item`); 87 88 await sendKey(kArrowDown); 89 test(() => { 90 assert_equals( 91 getRangeDescription(getSelection().getRangeAt(0)), 92 getRangeDescription({ 93 startContainer: editingHost.querySelector("#two"), 94 startOffset: 0, 95 endContainer: editingHost.querySelector("#two"), 96 endOffset: 0, 97 }), 98 ); 99 }, `${t.name}: arrow-down should move the caret to the second list item`); 100 101 await sendKey(kArrowDown); 102 test(() => { 103 assert_equals( 104 getRangeDescription(getSelection().getRangeAt(0)), 105 getRangeDescription({ 106 startContainer: editingHost.querySelector("#three").firstChild, 107 startOffset: 0, 108 endContainer: editingHost.querySelector("#three").firstChild, 109 endOffset: 0, 110 }), 111 ); 112 }, `${t.name}: arrow-down should move the caret to the third list item`); 113 114 await sendKey(kArrowDown); 115 test(() => { 116 assert_equals( 117 getRangeDescription(getSelection().getRangeAt(0)), 118 getRangeDescription({ 119 startContainer: editingHost.querySelector("#z").firstChild, 120 startOffset: 0, 121 endContainer: editingHost.querySelector("#z").firstChild, 122 endOffset: 0, 123 }), 124 ); 125 }, `${t.name}: arrow-down should move the caret to the final paragraph`); 126 }, "Moving caret between list items using arrow keys"); 127 128 promise_test(async t => { 129 const editingHost = document.querySelector("#test2"); 130 editingHost.focus(); 131 const p = editingHost.querySelector("#before"); 132 133 test(() => { 134 assert_equals( 135 getRangeDescription(getSelection().getRangeAt(0)), 136 getRangeDescription({ 137 startContainer: editingHost.querySelector("#before").firstChild, 138 startOffset: 0, 139 endContainer: editingHost.querySelector("#before").firstChild, 140 endOffset: 0, 141 }), 142 ); 143 }, `${t.name}: caret should start at the beginning of the first line`); 144 145 await sendKey(kArrowDown); 146 test(() => { 147 assert_equals( 148 getRangeDescription(getSelection().getRangeAt(0)), 149 getRangeDescription({ 150 startContainer: editingHost.querySelector("#quote").firstChild, 151 startOffset: 0, 152 endContainer: editingHost.querySelector("#quote").firstChild, 153 endOffset: 0, 154 }), 155 ); 156 }, `${t.name}: arrow-down should move the caret to the start of the block quote`); 157 158 await sendKey(kArrowDown); 159 test(() => { 160 assert_equals( 161 getRangeDescription(getSelection().getRangeAt(0)), 162 getRangeDescription({ 163 startContainer: editingHost.querySelector("#after").firstChild, 164 startOffset: 0, 165 endContainer: editingHost.querySelector("#after").firstChild, 166 endOffset: 0, 167 }), 168 ); 169 }, `${t.name}: arrow-down should move the caret to the final paragraph`); 170 171 await sendKey(kArrowLeft); 172 test(() => { 173 assert_equals( 174 getRangeDescription(getSelection().getRangeAt(0)), 175 getRangeDescription({ 176 startContainer: editingHost.querySelector("#quote").firstChild, 177 startOffset: 5, 178 endContainer: editingHost.querySelector("#quote").firstChild, 179 endOffset: 5, 180 }), 181 ); 182 }, `${t.name}: arrow-left should move the caret to the end of the quote`); 183 184 await sendKey(kArrowUp); 185 test(() => { 186 assert_equals( 187 getRangeDescription(getSelection().getRangeAt(0)), 188 getRangeDescription({ 189 startContainer: editingHost.querySelector("#before").firstChild, 190 startOffset: 10, 191 endContainer: editingHost.querySelector("#before").firstChild, 192 endOffset: 10, 193 }), 194 ); 195 }, `${t.name}: arrow-up should move the caret to into the first line`); 196 197 await sendKey(kArrowRight); 198 test(() => { 199 assert_equals( 200 getRangeDescription(getSelection().getRangeAt(0)), 201 getRangeDescription({ 202 startContainer: editingHost.querySelector("#before").firstChild, 203 startOffset: 11, 204 endContainer: editingHost.querySelector("#before").firstChild, 205 endOffset: 11, 206 }), 207 ); 208 }, `${t.name}: arrow-right should move the caret forward by one character`); 209 210 await sendKey(kArrowDown); 211 test(() => { 212 assert_equals( 213 getRangeDescription(getSelection().getRangeAt(0)), 214 getRangeDescription({ 215 startContainer: editingHost.querySelector("#quote").firstChild, 216 startOffset: 5, 217 endContainer: editingHost.querySelector("#quote").firstChild, 218 endOffset: 5, 219 }), 220 ); 221 }, `${t.name}: arrow-down should move the caret to the end of the quote`); 222 }, "Moving caret past the block-quote using arrow keys"); 223 </script> 224 <style> 225 div { 226 font-family: monospace; 227 } 228 ul { 229 list-style-type: none; 230 } 231 li::before { 232 content: "*\00a0"; 233 display: inline-block; 234 } 235 blockquote { 236 margin-inline-start: 5ch; 237 } 238 blockquote::after { 239 content: "\00a0*"; 240 display: inline-block; 241 } 242 </style> 243 </head> 244 <body> 245 <div id=test1 contenteditable> 246 <p id=a>abc</p> 247 <ul> 248 <li id=one>one</li> 249 <li id=two><br></li> 250 <li id=three>three</li> 251 </ul> 252 <p id=z>xyz</p> 253 </div> 254 <div id=test2 contenteditable> 255 <p id=before>paragraph before the blockquote</p> 256 <blockquote id=quote>quote</blockquote> 257 <p id=after>after the blockquote</p> 258 </div> 259 </body> 260 </html>