Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / editing / spelling / spellcheck-async-mutation.html
blobbf4b631d66b83b49e027fde0a8d1101ed8273c41
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <script src="../../resources/js-test.js"></script>
5 <script src="../editing.js"></script>
6 <script src="resources/util.js"></script>
7 <style>
8 .editing {
9 border: 2px solid red;
10 padding: 6px;
11 font-size: 18px;
13 </style>
14 </head>
15 <body>
16 <pre id="description"></pre>
17 <pre id="console"></pre>
19 <div id="source">zz zz zz</textarea>
21 <div id="container"></div>
23 <div id="move-target"></div>
25 <script>
26 description(
27 "Test for asynchronous spellchecking in case DOM mutation happens. " +
28 "This test checks crash won't happen if DOM mutations happened."
31 var jsTestIsAsync = true;
33 if (window.internals) {
34 internals.settings.setAsynchronousSpellCheckingEnabled(true);
35 internals.settings.setUnifiedTextCheckerEnabled(true);
38 var sourceIds = ['source'];
39 var destElems = ['textarea', 'input', 'contenteditable'];
40 var tweaks = ['delete', 'move', 'mutate'];
42 var testData = [];
43 for (var i = 0; i < sourceIds.length; ++i) {
44 for (var j = 0; j < destElems.length; ++j) {
45 for (var k = 0; k < tweaks.length; ++k) {
46 testData.push({
47 sourceId: sourceIds[i],
48 destElem: destElems[j],
49 tweak: tweaks[k]
50 });
55 var sel = window.getSelection();
57 function removeAllChildren(elem) {
58 while (elem.firstChild)
59 elem.removeChild(elem.firstChild);
62 var testNo = 0;
63 function doTestIfAny() {
64 // Clean up first.
65 removeAllChildren(document.getElementById('container'));
66 removeAllChildren(document.getElementById('move-target'));
68 var next = testData.shift();
69 if (next)
70 return window.setTimeout(function(){ doTest(++testNo, next); }, 0);
72 // No more tests. Tear down.
73 removeAllChildren(document.getElementById('container'));
74 removeAllChildren(document.getElementById('move-target'));
76 if (window.testRunner)
77 finishJSTest();
80 var requestId;
81 var lastRequestId;
82 function doTest(testNo, testData) {
83 function createElement(kind) {
84 if (kind == 'textarea' || kind == 'input')
85 return document.createElement(kind);
87 var div = document.createElement('div');
88 div.setAttribute('contenteditable', true);
89 return div;
92 debug("");
93 debug("Test Start: " + testNo);
95 var source = document.getElementById(testData.sourceId);
96 var destination = createElement(testData.destElem);
97 document.getElementById('container').appendChild(destination);
99 if (window.internals)
100 lastRequestId = internals.lastSpellCheckRequestSequence(document);
102 // A spellcheck request will be invoked.
103 doCopyAndPaste(source, destination);
105 setTimeout(function() {
106 if (window.internals)
107 requestId = internals.lastSpellCheckRequestSequence(document);
108 shouldBeGreaterThanOrEqual('requestId', 'lastRequestId + 1');
110 // Then, tweak
111 tweak(destination, testData.tweak);
113 waitForSpellCheckRequestDone(requestId, destination, testData.tweak, 10, 1);
114 }, 0);
117 function doCopyAndPaste(source, dest) {
118 function focusOn(elem) {
119 if (elem instanceof HTMLInputElement || elem instanceof HTMLTextAreaElement)
120 elem.focus();
121 else
122 sel.selectAllChildren(elem);
125 sel.selectAllChildren(source);
126 document.execCommand("Copy");
128 focusOn(dest);
129 document.execCommand("Paste");
132 function tweak(elem, kind) {
133 switch (kind) {
134 case 'delete':
135 elem.parentNode.removeChild(elem);
136 return;
137 case 'move':
138 var target = document.getElementById('move-target');
139 target.appendChild(elem);
140 return;
141 case 'mutate':
142 if (elem instanceof HTMLInputElement || elem instanceof HTMLTextAreaElement)
143 elem.value = 'zzz';
144 else
145 elem.innerHTML = 'zzz';
146 return;
147 default:
148 testFailed('Unknown kind of tweak');
149 return;
153 function waitForSpellCheckRequestDone(requestId, destination, tweakKind, restTry, nsleep) {
154 // No more try.
155 if (restTry <= 0) {
156 testFailed('Failed verification');
157 setTimeout(doTestIfAny, 0);
158 return;
161 if (window.internals)
162 var lastProcessedId = internals.lastSpellCheckProcessedSequence(document);
164 if (requestId != lastProcessedId) {
165 setTimeout(function() {
166 waitForSpellCheckRequestDone(requestId, destination, tweakKind, restTry - 1, nsleep * 2);
167 }, nsleep);
168 return;
171 if (verifyExistenceOfMarkers(destination, tweakKind)) {
172 testPassed('Request has been processed.');
173 } else {
174 testFailed('Request has been processed but we detected unexpected marker location.');
177 setTimeout(doTestIfAny, 0);
180 function verifyExistenceOfMarkers(elem, tweakKind) {
181 if (!window.internals)
182 return true;
184 switch (tweakKind) {
185 case 'delete':
186 return true;
187 case 'move':
188 // In move, marker should be there. However since markers are removed when unfocusing
189 // an input if it's the input what's moved and it's not focused return true right away.
190 if (elem instanceof HTMLInputElement && elem != document.activeElement)
191 return true;
192 var markerNum = internals.markerCountForNode(findFirstTextNode(elem), "spelling");
193 if (markerNum != 3)
194 return false;
195 for (var i = 0; i < 3; ++i) {
196 var range = internals.markerRangeForNode(findFirstTextNode(elem), "spelling", i);
197 if (range.toString() != "zz")
198 return false;
200 return true;
201 case 'mutate':
202 // In mutation, there aren't markers.
203 return internals.markerCountForNode(findFirstTextNode(elem), "spelling") == 0;
204 default:
205 testFailed('Unknown kind of tweak');
206 return true;
210 doTestIfAny();
212 var successfullyParsed = true;
213 </script>
214 </body>
215 </html>