textfieldselection-setRangeText.html (5911B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>text field selection: setRangeText</title> 4 <link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org"> 5 <link rel=help href="https://html.spec.whatwg.org/multipage/#textFieldSelection"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <style> 9 #display_none {display:none;} 10 </style> 11 <div id="log"></div> 12 <input type=text id=text value="foobar"> 13 <input type=search id=search value="foobar"> 14 <input type=tel id=tel value="foobar"> 15 <input type=url id=url value="foobar"> 16 <input type=password id=password value="foobar"> 17 <input id=display_none value="foobar"> 18 <textarea id=textarea>foobar</textarea> 19 <script> 20 var input = document.createElement("input"); 21 input.id = "input_not_in_doc"; 22 input.value = "foobar"; 23 24 var elements = [ 25 document.getElementById("text"), 26 document.getElementById("search"), 27 document.getElementById("tel"), 28 document.getElementById("url"), 29 document.getElementById("password"), 30 document.getElementById("display_none"), 31 document.getElementById("textarea"), 32 input, 33 ] 34 35 function untilEvent(element, eventName) { 36 return new Promise((resolve) => { 37 element.addEventListener(eventName, resolve, { once: true }); 38 }); 39 } 40 41 elements.forEach(function(element) { 42 test(function() { 43 element.value = "foobar"; 44 element.selectionStart = 0; 45 element.selectionEnd = 3; 46 assert_equals(element.selectionStart, 0); 47 assert_equals(element.selectionEnd, 3); 48 element.setRangeText("foobar2"); 49 assert_equals(element.value, "foobar2bar"); 50 assert_equals(element.selectionStart, 0); 51 assert_equals(element.selectionEnd, 7); 52 element.setRangeText("foobar3", 7, 10); 53 assert_equals(element.value, "foobar2foobar3"); 54 }, element.id + " setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments"); 55 56 test(function(){ 57 element.value = "foobar"; 58 element.selectionStart = 0; 59 element.selectionEnd = 0; 60 61 element.setRangeText("foobar2", 0, 3); // no 4th arg, default "preserve" 62 assert_equals(element.value, "foobar2bar"); 63 assert_equals(element.selectionStart, 0); 64 assert_equals(element.selectionEnd, 0); 65 }, element.id + " selectionMode missing"); 66 67 test(function(){ 68 element.value = "foobar" 69 element.setRangeText("foo", 3, 6, "select"); 70 assert_equals(element.value, "foofoo"); 71 assert_equals(element.selectionStart, 3); 72 assert_equals(element.selectionEnd, 6); 73 }, element.id + " selectionMode 'select'"); 74 75 test(function(){ 76 element.value = "foobar" 77 element.setRangeText("foo", 3, 6, "start"); 78 assert_equals(element.value, "foofoo"); 79 assert_equals(element.selectionStart, 3); 80 assert_equals(element.selectionEnd, 3); 81 }, element.id + " selectionMode 'start'"); 82 83 test(function(){ 84 element.value = "foobar" 85 element.setRangeText("foobar", 3, 6, "end"); 86 assert_equals(element.value, "foofoobar"); 87 assert_equals(element.selectionStart, 9); 88 assert_equals(element.selectionEnd, 9); 89 }, element.id + " selectionMode 'end'"); 90 91 test(function(){ 92 element.value = "foobar" 93 element.selectionStart = 0; 94 element.selectionEnd = 5; 95 assert_equals(element.selectionStart, 0); 96 element.setRangeText("", 3, 6, "preserve"); 97 assert_equals(element.value, "foo"); 98 assert_equals(element.selectionStart, 0); 99 assert_equals(element.selectionEnd, 3); 100 }, element.id + " selectionMode 'preserve'"); 101 102 test(function(){ 103 assert_throws_dom("INDEX_SIZE_ERR", function() { 104 element.setRangeText("barfoo", 2, 1); 105 }); 106 }, element.id + " setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception"); 107 108 test(function(){ 109 assert_throws_js(TypeError, function() { 110 element.setRangeText(); 111 }); 112 }, element.id + " setRangeText without argument throws a type error"); 113 114 promise_test(async (t) => { 115 // At this point there are already "select" events queued up on 116 // "element". Give them time to fire; otherwise we can get spurious 117 // passes. 118 // 119 // This is unfortunately racy in that we might _still_ get spurious 120 // passes. I'm not sure how best to handle that. 121 t.step_timeout(function() { 122 var q = false; 123 element.onselect = t.step_func_done(function(e) { 124 assert_true(q, "event should be queued"); 125 assert_true(e.isTrusted, "event is trusted"); 126 assert_true(e.bubbles, "event bubbles"); 127 assert_false(e.cancelable, "event is not cancelable"); 128 }); 129 element.setRangeText("foobar2", 0, 6); 130 q = true; 131 }, 10); 132 }, element.id + " setRangeText fires a select event"); 133 134 promise_test(async () => { 135 element.value = "XXXXXXXXXXXXXXXXXXX"; 136 const { length } = element.value; 137 element.setSelectionRange(0, length); 138 await untilEvent(element, "select"); 139 element.setRangeText("foo", 2, 2); 140 await untilEvent(element, "select"); 141 assert_equals(element.selectionStart, 0, ".selectionStart"); 142 assert_equals(element.selectionEnd, length + 3, ".selectionEnd"); 143 }, element.id + " setRangeText fires a select event when fully selected"); 144 145 promise_test(async () => { 146 element.value = "XXXXXXXXXXXXXXXXXXX"; 147 element.select(); 148 await untilEvent(element, "select"); 149 element.setRangeText("foo", 2, 2); 150 await untilEvent(element, "select"); 151 assert_equals(element.selectionStart, 0, ".selectionStart"); 152 assert_equals(element.selectionEnd, element.value.length, ".selectionEnd"); 153 }, element.id + " setRangeText fires a select event after select()"); 154 }) 155 </script>