FormControlRange-interactive-basic.html (3820B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="/resources/testdriver.js"></script> 6 <script src="/resources/testdriver-vendor.js"></script> 7 <script src="/resources/testdriver-actions.js"></script> 8 <body></body> 9 <script> 10 'use strict'; 11 12 const BACKSPACE = '\uE003'; 13 const DELETE = '\uE017'; 14 const controls = ['input', 'textarea']; 15 16 function setup(control, value) { 17 document.body.innerHTML = control === 'input' ? '<input type="text">' : '<textarea></textarea>'; 18 const element = document.body.firstElementChild; 19 element.value = value; 20 element.focus(); 21 return element; 22 } 23 24 async function typeKeys(element, text) { await test_driver.send_keys(element, text); } 25 26 function makeRange(element, start, end) { 27 const range = new FormControlRange(); 28 range.setFormControlRange(element, start, end); 29 return range; 30 } 31 32 controls.forEach(control => { 33 [ 34 { 35 name: 'at start boundary keeps start; end extends (multi-char)', 36 init: { value:'ABCDE', s:1, e:3, caret:1, ins:'pq' }, 37 exp: { s:1, e:5, text:'pqBC' } 38 }, 39 { 40 name: 'inside range extends end by length', 41 init: { value:'ABCDE', s:1, e:4, caret:2, ins:'pq' }, 42 exp: { s:1, e:6, text:'BpqCD' } 43 }, 44 { 45 name: 'at end boundary leaves offsets unchanged (multi-char)', 46 init: { value:'ABCDE', s:1, e:3, caret:3, ins:'pq' }, 47 exp: { s:1, e:3, text:'BC' } 48 }, 49 ].forEach(({ name, init, exp }) => { 50 promise_test(async t => { 51 const element = setup(control, init.value); 52 const range = makeRange(element, init.s, init.e); 53 element.setSelectionRange(init.caret, init.caret); 54 await typeKeys(element, init.ins); 55 assert_equals(range.startOffset, exp.s, 'startOffset'); 56 assert_equals(range.endOffset, exp.e, 'endOffset'); 57 assert_equals(range.toString(), exp.text, 'range text'); 58 }, `Insertion: ${name} (${control}).`); 59 }); 60 61 [ 62 { name: 'single char inside range', 63 init:{ value:'ABCDE', s:1, e:4, a:2, b:3, text:'q' }, 64 exp:{ s:1, e:4, text:'BqD' } 65 }, 66 ].forEach(({ name, init, exp }) => { 67 promise_test(async t => { 68 const element = setup(control, init.value); 69 const range = makeRange(element, init.s, init.e); 70 element.setSelectionRange(init.a, init.b); 71 await typeKeys(element, init.text); 72 assert_equals(range.startOffset, exp.s); 73 assert_equals(range.endOffset, exp.e); 74 assert_equals(range.toString(), exp.text); 75 }, `Equal-length replacement: ${name} (${control}).`); 76 }); 77 78 [ 79 { name:'backspace before range shifts both left', 80 init:{ value:'ABCDE', s:2, e:5, caret:2, key:BACKSPACE }, 81 exp:{ value:'ACDE', s:1, e:4, text:'CDE' } }, 82 { name:'forward delete inside range contracts end by 1', 83 init:{ value:'ABCDE', s:1, e:4, caret:2, key:DELETE }, 84 exp:{ value:'ABDE', s:1, e:3, text:'BD' } }, 85 { name:'forward delete at end boundary no effect on range', 86 init:{ value:'ABCDE', s:1, e:3, caret:3, key:DELETE }, 87 exp:{ value:'ABCE', s:1, e:3, text:'BC' } }, 88 { name:'backspace at control start is no-op', 89 init:{ value:'ABCDE', s:0, e:2, caret:0, key:BACKSPACE }, 90 exp:{ value:'ABCDE', s:0, e:2, text:'AB' } }, 91 ].forEach(({ name, init, exp }) => { 92 promise_test(async t => { 93 const element = setup(control, init.value); 94 const range = makeRange(element, init.s, init.e); 95 element.setSelectionRange(init.caret, init.caret); 96 await typeKeys(element, init.key); 97 assert_equals(element.value, exp.value); 98 assert_equals(range.startOffset, exp.s); 99 assert_equals(range.endOffset, exp.e); 100 assert_equals(range.toString(), exp.text); 101 }, `Deletion: ${name} (${control}).`); 102 }); 103 }); 104 </script>