| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <html> | 2 <script src="../../resources/testharness.js"></script> |
| 3 <head> | 3 <script src="../../resources/testharnessreport.js"></script> |
| 4 <script src="../../resources/js-test.js"></script> | 4 <script src="../assert_selection.js"></script> |
| 5 <script src="../editing.js"></script> | 5 <script src="spellcheck_test.js"></script> |
| 6 <script src="resources/util.js"></script> | 6 <script> |
| 7 <style> | 7 spellcheck_test( |
| 8 .editing { | 8 '<div><textarea id="destination"></textarea></div><div id="move-target"></di
v>', |
| 9 border: 2px solid red; | 9 document => { |
| 10 padding: 6px; | 10 document.getSelection().setClipboardData('zz zz zz'); |
| 11 font-size: 18px; | 11 const destination = document.getElementById('destination'); |
| 12 } | 12 destination.focus(); |
| 13 </style> | 13 document.execCommand('paste'); |
| 14 </head> | 14 destination.remove(); |
| 15 <body> | 15 }, |
| 16 <pre id="description"></pre> | 16 '<div></div><div id="move-target"></div>', |
| 17 <pre id="console"></pre> | 17 'Delete <textarea> with pending spell check request.'); |
| 18 | 18 |
| 19 <div id="source">zz zz zz</textarea> | 19 spellcheck_test( |
| 20 '<div><textarea id="destination"></textarea></div><div id="move-target"></di
v>', |
| 21 document => { |
| 22 document.getSelection().setClipboardData('zz zz zz'); |
| 23 const destination = document.getElementById('destination'); |
| 24 destination.focus(); |
| 25 document.execCommand('paste'); |
| 26 document.getElementById('move-target').appendChild(destination); |
| 27 }, |
| 28 '<div></div><div id="move-target"><textarea id="destination">#zz# #zz# #zz#<
/textarea></div>', |
| 29 'Move <textarea> with pending spell check request.'); |
| 20 | 30 |
| 21 <div id="container"></div> | 31 spellcheck_test( |
| 32 '<div><textarea id="destination"></textarea></div><div id="move-target"></di
v>', |
| 33 document => { |
| 34 document.getSelection().setClipboardData('zz zz zz'); |
| 35 const destination = document.getElementById('destination'); |
| 36 destination.focus(); |
| 37 document.execCommand('paste'); |
| 38 destination.value = 'zzz'; |
| 39 }, |
| 40 '<div><textarea id="destination">zzz</textarea></div><div id="move-target"><
/div>', |
| 41 'Mutate content of <textarea> with pending spell check request.'); |
| 22 | 42 |
| 23 <div id="move-target"></div> | 43 spellcheck_test( |
| 44 '<div><input id="destination"></div><div id="move-target"></div>', |
| 45 document => { |
| 46 document.getSelection().setClipboardData('zz zz zz'); |
| 47 const destination = document.getElementById('destination'); |
| 48 destination.focus(); |
| 49 document.execCommand('paste'); |
| 50 destination.remove(); |
| 51 }, |
| 52 '<div></div><div id="move-target"></div>', |
| 53 'Delete <input> with pending spell check request.'); |
| 24 | 54 |
| 25 <script> | 55 spellcheck_test( |
| 26 description( | 56 '<div><input id="destination"></div><div id="move-target"></div>', |
| 27 "Test for asynchronous spellchecking in case DOM mutation happens. " + | 57 document => { |
| 28 "This test checks crash won't happen if DOM mutations happened." | 58 document.getSelection().setClipboardData('zz zz zz'); |
| 29 ); | 59 const destination = document.getElementById('destination'); |
| 60 destination.focus(); |
| 61 document.execCommand('paste'); |
| 62 document.getElementById('move-target').appendChild(destination); |
| 63 }, |
| 64 // No marker because focus is lost after moving. |
| 65 '<div></div><div id="move-target"><input id="destination" value="zz zz zz"><
/div>', |
| 66 'Move <input> with pending spell check request.'); |
| 30 | 67 |
| 31 var jsTestIsAsync = true; | 68 spellcheck_test( |
| 32 if (window.testRunner) | 69 '<div><input id="destination"></div><div id="move-target"></div>', |
| 33 testRunner.setMockSpellCheckerEnabled(true); | 70 document => { |
| 71 document.getSelection().setClipboardData('zz zz zz'); |
| 72 const destination = document.getElementById('destination'); |
| 73 destination.focus(); |
| 74 document.execCommand('paste'); |
| 75 destination.value = 'zzz'; |
| 76 }, |
| 77 '<div><input id="destination" value="zzz"></div><div id="move-target"></div>
', |
| 78 'Mutate content of <input> with pending spell check request.'); |
| 34 | 79 |
| 35 var sourceIds = ['source']; | 80 spellcheck_test( |
| 36 var destElems = ['textarea', 'input', 'contenteditable']; | 81 '<div><div contenteditable id="destination"></div></div><div id="move-target
"></div>', |
| 37 var tweaks = ['delete', 'move', 'mutate']; | 82 document => { |
| 83 document.getSelection().setClipboardData('zz zz zz'); |
| 84 const destination = document.getElementById('destination'); |
| 85 destination.focus(); |
| 86 document.execCommand('paste'); |
| 87 destination.remove(); |
| 88 }, |
| 89 '<div></div><div id="move-target"></div>', |
| 90 'Delete <div> with pending spell check request.'); |
| 38 | 91 |
| 39 var testData = []; | 92 spellcheck_test( |
| 40 for (var i = 0; i < sourceIds.length; ++i) { | 93 '<div><div contenteditable id="destination"></div></div><div id="move-target
"></div>', |
| 41 for (var j = 0; j < destElems.length; ++j) { | 94 document => { |
| 42 for (var k = 0; k < tweaks.length; ++k) { | 95 document.getSelection().setClipboardData('zz zz zz'); |
| 43 testData.push({ | 96 const destination = document.getElementById('destination'); |
| 44 sourceId: sourceIds[i], | 97 destination.focus(); |
| 45 destElem: destElems[j], | 98 document.execCommand('paste'); |
| 46 tweak: tweaks[k] | 99 document.getElementById('move-target').appendChild(destination); |
| 47 }); | 100 }, |
| 48 } | 101 // No marker because checking range stays in the original <div> after moving
. |
| 49 } | 102 '<div></div><div id="move-target"><div contenteditable id="destination">zz z
z zz</div></div>', |
| 50 } | 103 'Move <div> with pending spell check request.'); |
| 51 | 104 |
| 52 var sel = window.getSelection(); | 105 spellcheck_test( |
| 53 | 106 '<div><div contenteditable id="destination"></div></div><div id="move-target
"></div>', |
| 54 function removeAllChildren(elem) { | 107 document => { |
| 55 while (elem.firstChild) | 108 document.getSelection().setClipboardData('zz zz zz'); |
| 56 elem.removeChild(elem.firstChild); | 109 const destination = document.getElementById('destination'); |
| 57 } | 110 destination.focus(); |
| 58 | 111 document.execCommand('paste'); |
| 59 var testNo = 0; | 112 destination.innerHTML = 'zzz'; |
| 60 function doTestIfAny() { | 113 }, |
| 61 // Clean up first. | 114 '<div><div contenteditable id="destination">zzz</div></div><div id="move-tar
get"></div>', |
| 62 removeAllChildren(document.getElementById('container')); | 115 'Mutate content of <div> with pending spell check request.'); |
| 63 removeAllChildren(document.getElementById('move-target')); | |
| 64 | |
| 65 var next = testData.shift(); | |
| 66 if (next) | |
| 67 return window.setTimeout(function(){ doTest(++testNo, next); }, 0); | |
| 68 | |
| 69 // No more tests. Tear down. | |
| 70 removeAllChildren(document.getElementById('container')); | |
| 71 removeAllChildren(document.getElementById('move-target')); | |
| 72 | |
| 73 if (window.testRunner) | |
| 74 finishJSTest(); | |
| 75 } | |
| 76 | |
| 77 var requestId; | |
| 78 var lastRequestId; | |
| 79 function doTest(testNo, testData) { | |
| 80 function createElement(kind) { | |
| 81 if (kind == 'textarea' || kind == 'input') | |
| 82 return document.createElement(kind); | |
| 83 | |
| 84 var div = document.createElement('div'); | |
| 85 div.setAttribute('contenteditable', true); | |
| 86 return div; | |
| 87 } | |
| 88 | |
| 89 debug(""); | |
| 90 debug("Test Start: " + testNo); | |
| 91 | |
| 92 var source = document.getElementById(testData.sourceId); | |
| 93 var destination = createElement(testData.destElem); | |
| 94 document.getElementById('container').appendChild(destination); | |
| 95 | |
| 96 if (window.internals) | |
| 97 lastRequestId = internals.lastSpellCheckRequestSequence(document); | |
| 98 | |
| 99 // A spellcheck request will be invoked. | |
| 100 doCopyAndPaste(source, destination); | |
| 101 | |
| 102 setTimeout(function() { | |
| 103 if (window.internals) | |
| 104 requestId = internals.lastSpellCheckRequestSequence(document); | |
| 105 shouldBeGreaterThanOrEqual('requestId', 'lastRequestId + 1'); | |
| 106 | |
| 107 // Then, tweak | |
| 108 tweak(destination, testData.tweak); | |
| 109 | |
| 110 waitForSpellCheckRequestDone(requestId, destination, testData.tweak, 10,
1); | |
| 111 }, 0); | |
| 112 } | |
| 113 | |
| 114 function doCopyAndPaste(source, dest) { | |
| 115 function focusOn(elem) { | |
| 116 if (elem instanceof HTMLInputElement || elem instanceof HTMLTextAreaElem
ent) | |
| 117 elem.focus(); | |
| 118 else | |
| 119 sel.selectAllChildren(elem); | |
| 120 } | |
| 121 | |
| 122 sel.selectAllChildren(source); | |
| 123 document.execCommand("Copy"); | |
| 124 | |
| 125 focusOn(dest); | |
| 126 document.execCommand("Paste"); | |
| 127 } | |
| 128 | |
| 129 function tweak(elem, kind) { | |
| 130 switch (kind) { | |
| 131 case 'delete': | |
| 132 elem.parentNode.removeChild(elem); | |
| 133 return; | |
| 134 case 'move': | |
| 135 var target = document.getElementById('move-target'); | |
| 136 target.appendChild(elem); | |
| 137 return; | |
| 138 case 'mutate': | |
| 139 if (elem instanceof HTMLInputElement || elem instanceof HTMLTextAreaElem
ent) | |
| 140 elem.value = 'zzz'; | |
| 141 else | |
| 142 elem.innerHTML = 'zzz'; | |
| 143 return; | |
| 144 default: | |
| 145 testFailed('Unknown kind of tweak'); | |
| 146 return; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 function waitForSpellCheckRequestDone(requestId, destination, tweakKind, restTry
, nsleep) { | |
| 151 // No more try. | |
| 152 if (restTry <= 0) { | |
| 153 testFailed('Failed verification'); | |
| 154 setTimeout(doTestIfAny, 0); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 if (window.internals) | |
| 159 var lastProcessedId = internals.lastSpellCheckProcessedSequence(document
); | |
| 160 | |
| 161 if (requestId != lastProcessedId) { | |
| 162 setTimeout(function() { | |
| 163 waitForSpellCheckRequestDone(requestId, destination, tweakKind, rest
Try - 1, nsleep * 2); | |
| 164 }, nsleep); | |
| 165 return; | |
| 166 } | |
| 167 | |
| 168 if (verifyExistenceOfMarkers(destination, tweakKind)) { | |
| 169 testPassed('Request has been processed.'); | |
| 170 } else { | |
| 171 testFailed('Request has been processed but we detected unexpected marker
location.'); | |
| 172 } | |
| 173 | |
| 174 setTimeout(doTestIfAny, 0); | |
| 175 } | |
| 176 | |
| 177 function verifyExistenceOfMarkers(elem, tweakKind) { | |
| 178 if (!window.internals) | |
| 179 return true; | |
| 180 | |
| 181 switch (tweakKind) { | |
| 182 case 'delete': | |
| 183 return true; | |
| 184 case 'move': | |
| 185 // In move, marker should be there. However since markers are removed wh
en unfocusing | |
| 186 // an input if it's the input what's moved and it's not focused return t
rue right away. | |
| 187 if (elem instanceof HTMLInputElement && elem != document.activeElement) | |
| 188 return true; | |
| 189 var markerNum = internals.markerCountForNode(findFirstTextNode(elem), "s
pelling"); | |
| 190 if (markerNum != 3) | |
| 191 return false; | |
| 192 for (var i = 0; i < 3; ++i) { | |
| 193 var range = internals.markerRangeForNode(findFirstTextNode(elem), "s
pelling", i); | |
| 194 if (range.toString() != "zz") | |
| 195 return false; | |
| 196 } | |
| 197 return true; | |
| 198 case 'mutate': | |
| 199 // In mutation, there aren't markers. | |
| 200 return internals.markerCountForNode(findFirstTextNode(elem), "spelling")
== 0; | |
| 201 default: | |
| 202 testFailed('Unknown kind of tweak'); | |
| 203 return true; | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 doTestIfAny(); | |
| 208 | |
| 209 var successfullyParsed = true; | |
| 210 </script> | 116 </script> |
| 211 </body> | |
| 212 </html> | |
| OLD | NEW |