Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1406)

Side by Side Diff: third_party/WebKit/LayoutTests/editing/spelling/spellcheck_test.js

Issue 2590823006: Get rid of verify-with-timeout in spellcheck_test (Closed)
Patch Set: Wed Dec 21 16:51:05 JST 2016 Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 // This file provides 7 // This file provides
8 // |spellcheck_test(sample, tester, expectedText, opt_title)| asynchronous test 8 // |spellcheck_test(sample, tester, expectedText, opt_title)| asynchronous test
9 // to W3C test harness for easier writing of spellchecker test cases. 9 // to W3C test harness for easier writing of spellchecker test cases.
10 // 10 //
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 */ 268 */
269 serializeInternal(node) { 269 serializeInternal(node) {
270 if (isElement(node)) 270 if (isElement(node))
271 return this.handleElementNode(node); 271 return this.handleElementNode(node);
272 if (isCharacterData(node)) 272 if (isCharacterData(node))
273 return this.handleCharacterData(node); 273 return this.handleCharacterData(node);
274 throw new Error(`Unexpected node ${node}`); 274 throw new Error(`Unexpected node ${node}`);
275 } 275 }
276 } 276 }
277 277
278 /**
279 * @param {!Document} document
280 * @return {boolean}
281 */
282 function hasPendingSpellCheckRequest(document) {
283 return internals.lastSpellCheckRequestSequence(document) !==
284 internals.lastSpellCheckProcessedSequence(document);
285 }
286
278 /** @type {string} */ 287 /** @type {string} */
279 const kTitle = 'title'; 288 const kTitle = 'title';
280 /** @type {string} */ 289 /** @type {string} */
281 const kCallback = 'callback'; 290 const kCallback = 'callback';
282 /** @type {string} */ 291 /** @type {string} */
283 const kIsSpellcheckTest = 'isSpellcheckTest'; 292 const kIsSpellcheckTest = 'isSpellcheckTest';
284 293
285 /**
286 * @param {!Test} testObject
287 * @param {!Sample} sample
288 * @param {string} expectedText
289 * @param {number} remainingRetry
290 * @param {number} retryInterval
291 */
292 function verifyMarkers(
293 testObject, sample, expectedText, remainingRetry, retryInterval) {
294 assert_not_equals(
295 window.internals, undefined,
296 'window.internals is required for running automated spellcheck tests.');
297
298 /** @type {!MarkerSerializer} */
299 const serializer = new MarkerSerializer({
300 spelling: '#',
301 grammar: '~'});
302
303 try {
304 assert_equals(serializer.serialize(sample.document), expectedText);
305 testObject.done();
306 } catch (error) {
307 if (remainingRetry <= 0)
308 throw error;
309
310 // Force invoking idle time spellchecker in case it has not been run yet.
311 if (window.testRunner)
312 window.testRunner.runIdleTasks(() => {});
313
314 // TODO(xiaochengh): We should make SpellCheckRequester::didCheck trigger
315 // something in JavaScript (e.g., a |Promise|), so that we can actively
316 // know the completion of spellchecking instead of passively waiting for
317 // markers to appear or disappear.
318 testObject.step_timeout(
319 () => verifyMarkers(testObject, sample, expectedText,
320 remainingRetry - 1, retryInterval),
321 retryInterval);
322 }
323 }
324
325 // Spellchecker gets triggered not only by text and selection change, but also 294 // Spellchecker gets triggered not only by text and selection change, but also
326 // by focus change. For example, misspelling markers in <INPUT> disappear when 295 // by focus change. For example, misspelling markers in <INPUT> disappear when
327 // the window loses focus, even though the selection does not change. 296 // the window loses focus, even though the selection does not change.
328 // Therefore, we disallow spellcheck tests from running simultaneously to 297 // Therefore, we disallow spellcheck tests from running simultaneously to
329 // prevent interference among them. If we call spellcheck_test while another 298 // prevent interference among them. If we call spellcheck_test while another
330 // test is running, the new test will be added into testQueue waiting for the 299 // test is running, the new test will be added into testQueue waiting for the
331 // completion of the previous test. 300 // completion of the previous test.
332 301
333 /** @type {boolean} */ 302 /** @type {boolean} */
334 var spellcheckTestRunning = false; 303 var spellcheckTestRunning = false;
335 /** @type {!Array<!Object>} */ 304 /** @type {!Array<!Object>} */
336 const testQueue = []; 305 const testQueue = [];
337 306
307 // We need to ensure correct usage of testRunner.runIdleTasks() that:
308 // 1. We don't call runIdleTasks if another runIdleTasks is called but the
309 // callback has not been invoked yet; Otherwise, the current call is ignored.
310 // 2. When the callback is invoked, we only verify test cases whose testers
311 // finished before calling runIdleTasks(); Otherwise, the idle time spell
312 // check may have not been invoked at the verification time.
313
314 /** @type {boolean} */
315 var runIdleTasksRequested = false;
316 /**
317 * @type {!Array<!Function>} Verification functions of test cases whose idle
318 * idle spell checkers are requested before the current call of runIdleTasks.
319 */
320 var idleVerificationReadyQueue = [];
321 /**
322 * @type {!Array<!Function>} Verification functions of test cases whose idle
323 * idle spell checkers are requested after the current call of runIdleTasks.
324 */
325 var idleVerificationWaitingQueue = [];
326
327 function batchIdleVerification() {
328 runIdleTasksRequested = false;
329 idleVerificationReadyQueue.forEach(func => func());
330 idleVerificationReadyQueue = idleVerificationWaitingQueue;
331 idleVerificationWaitingQueue = [];
332 if (idleVerificationReadyQueue.length) {
333 runIdleTasksRequested = true;
334 testRunner.runIdleTasks(batchIdleVerification);
335 }
336 }
337
338 /** 338 /**
339 * @param {!Test} testObject 339 * @param {!Test} testObject
340 * @param {!Sample|string} input 340 * @param {!Sample|string} input
341 * @param {function(!Document)|string} tester 341 * @param {function(!Document)|string} tester
342 * @param {string} expectedText 342 * @param {string} expectedText
343 */ 343 */
344 function invokeSpellcheckTest(testObject, input, tester, expectedText) { 344 function invokeSpellcheckTest(testObject, input, tester, expectedText) {
345 spellcheckTestRunning = true; 345 spellcheckTestRunning = true;
346 346
347 testObject.step(() => { 347 testObject.step(() => {
348 // TODO(xiaochengh): Merge the following part with |assert_selection|. 348 // TODO(xiaochengh): Merge the following part with |assert_selection|.
349 /** @type {!Sample} */ 349 /** @type {!Sample} */
350 const sample = typeof(input) === 'string' ? new Sample(input) : input; 350 const sample = typeof(input) === 'string' ? new Sample(input) : input;
351 testObject.sample = sample; 351 testObject.sample = sample;
352 352
353 if (typeof(tester) === 'function') { 353 if (typeof(tester) === 'function') {
354 tester.call(window, sample.document); 354 tester.call(window, sample.document);
355 } else if (typeof(tester) === 'string') { 355 } else if (typeof(tester) === 'string') {
356 const strings = tester.split(/ (.+)/); 356 const strings = tester.split(/ (.+)/);
357 sample.document.execCommand(strings[0], false, strings[1]); 357 sample.document.execCommand(strings[0], false, strings[1]);
358 } else { 358 } else {
359 assert_unreached(`Invalid tester: ${tester}`); 359 assert_unreached(`Invalid tester: ${tester}`);
360 } 360 }
361 361
362 /** @type {number} */ 362 assert_not_equals(
363 const kMaxRetry = 10; 363 window.testRunner, undefined,
364 /** @type {number} */ 364 'window.testRunner is required for automated spellcheck tests.');
365 const kRetryInterval = 50; 365 assert_not_equals(
366 window.internals, undefined,
367 'window.internals is required for automated spellcheck tests.');
366 368
367 // TODO(xiaochengh): We should make SpellCheckRequester::didCheck trigger 369 /** @type {!Function} */
368 // something in JavaScript (e.g., a |Promise|), so that we can actively know 370 const verification = () => {
369 // the completion of spellchecking instead of passively waiting for markers 371 testObject.step(() => {
370 // to appear or disappear. 372 if (hasPendingSpellCheckRequest(sample.document))
371 testObject.step_timeout( 373 return;
372 () => verifyMarkers(testObject, sample, expectedText, 374
373 kMaxRetry, kRetryInterval), 375 /** @type {!MarkerSerializer} */
374 kRetryInterval); 376 const serializer = new MarkerSerializer({
377 spelling: '#',
378 grammar: '~'});
379
380 assert_equals(serializer.serialize(sample.document), expectedText);
381 testObject.done();
382 });
383 }
384
385 // Verify when all spell check requests are resolved.
386 testRunner.setSpellCheckResolvedCallback(verification);
387
388 // For tests that do not expect new markers, verify with runIdleTasks.
389 if (runIdleTasksRequested) {
390 idleVerificationWaitingQueue.push(verification);
391 return;
392 }
393
394 idleVerificationReadyQueue.push(verification);
395 runIdleTasksRequested = true;
396 testRunner.runIdleTasks(batchIdleVerification);
375 }); 397 });
376 } 398 }
377 399
378 add_result_callback(testObj => { 400 add_result_callback(testObj => {
379 if (!testObj.properties[kIsSpellcheckTest]) 401 if (!testObj.properties[kIsSpellcheckTest])
380 return; 402 return;
381 403
382 /** @type {boolean} */ 404 /** @type {boolean} */
383 var shouldRemoveSample = false; 405 var shouldRemoveSample = false;
384 if (testObj.status === testObj.PASS) { 406 if (testObj.status === testObj.PASS) {
385 if (testObj.properties[kCallback]) 407 if (testObj.properties[kCallback])
386 testObj.properties[kCallback](testObj.sample); 408 testObj.properties[kCallback](testObj.sample);
387 else 409 else
388 shouldRemoveSample = true; 410 shouldRemoveSample = true;
389 } else { 411 } else {
390 if (window.testRunner) 412 if (window.testRunner)
391 shouldRemoveSample = true; 413 shouldRemoveSample = true;
392 } 414 }
393 415
394 if (shouldRemoveSample) 416 if (shouldRemoveSample)
395 testObj.sample.remove(); 417 testObj.sample.remove();
396 418
397 // This is the earliest timing when a new spellcheck_test can be started. 419 // We may be in a spellCheckResolvedCallback here, so removing the callback
398 spellcheckTestRunning = false; 420 // (and hence, all remaining tasks) must be done asynchronously.
421 setTimeout(() => {
422 if (window.testRunner)
423 testRunner.removeSpellCheckResolvedCallback();
399 424
400 /** @type {Object} */ 425 // This is the earliest timing when a new spellcheck_test can be started.
401 const next = testQueue.shift(); 426 spellcheckTestRunning = false;
402 if (next === undefined) 427
403 return; 428 /** @type {Object} */
404 invokeSpellcheckTest(next.testObject, next.input, 429 const next = testQueue.shift();
405 next.tester, next.expectedText); 430 if (next === undefined)
431 return;
432 invokeSpellcheckTest(next.testObject, next.input,
433 next.tester, next.expectedText);
434 }, 0);
406 }); 435 });
407 436
408 /** 437 /**
409 * @param {Object=} passedArgs 438 * @param {Object=} passedArgs
410 * @return {!Object} 439 * @return {!Object}
411 */ 440 */
412 function getTestArguments(passedArgs) { 441 function getTestArguments(passedArgs) {
413 const args = {}; 442 const args = {};
414 args[kIsSpellcheckTest] = true; 443 args[kIsSpellcheckTest] = true;
415 [kTitle, kCallback].forEach(key => args[key] = undefined); 444 [kTitle, kCallback].forEach(key => args[key] = undefined);
(...skipping 30 matching lines...) Expand all
446 tester: tester, expectedText: expectedText}); 475 tester: tester, expectedText: expectedText});
447 return; 476 return;
448 } 477 }
449 478
450 invokeSpellcheckTest(testObject, input, tester, expectedText); 479 invokeSpellcheckTest(testObject, input, tester, expectedText);
451 } 480 }
452 481
453 // Export symbols 482 // Export symbols
454 window.spellcheck_test = spellcheckTest; 483 window.spellcheck_test = spellcheckTest;
455 })(); 484 })();
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698