1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Include test fixture. 6GEN_INCLUDE(['../testing/chromevox_unittest_base.js']); 7 8/** 9 * A TTS class implementing speak and stop methods intended only for testing. 10 * @constructor 11 * @implements cvox.TtsInterface 12 */ 13function TestTts() { 14 this.strings = []; 15} 16 17/** 18 * The strings that were spoken since the last call to get(). 19 * @type {Array.<string>} 20 */ 21TestTts.prototype.strings; 22 23/** 24 * Returns the list of strings spoken since the last time this method was 25 * called, and then clears the list. 26 * @return {Array.<string>} The list of strings. 27 */ 28TestTts.prototype.get = function() { 29 var result = this.strings; 30 this.strings = []; 31 return result; 32}; 33 34/** @override */ 35TestTts.prototype.speak = function(text, queueMode, properties) { 36 this.strings.push(text); 37}; 38 39/** @override */ 40TestTts.prototype.isSpeaking = function() { 41 return false; 42}; 43 44/** @override */ 45TestTts.prototype.stop = function() { 46 // Do nothing. 47}; 48 49/** @override */ 50TestTts.prototype.increaseOrDecreaseProperty = 51 function(propertyName, increase) { 52 // Do nothing. 53}; 54 55/** 56 * Stores the last braille content. 57 * @constructor 58 * @implements cvox.BrailleInterface 59 */ 60function TestBraille() { 61 this.content = null; 62} 63 64/** @override */ 65TestBraille.prototype.write = function(params) { 66 this.content = params; 67}; 68 69/** 70 * Asserts the current braille content. 71 * 72 * @param {string} text Braille text. 73 * @param {number=} opt_start Selection start. 74 * @param {number=} opt_end Selection end. 75 */ 76TestBraille.assertContent = function(text, opt_start, opt_end) { 77 var c = cvox.ChromeVox.braille.content; 78 assertTrue(c != null); 79 opt_start = opt_start !== undefined ? opt_start : -1; 80 opt_end = opt_end !== undefined ? opt_end : opt_start; 81 assertEquals(text, c.text.toString()); 82 assertEquals(opt_start, c.startIndex); 83 assertEquals(opt_end, c.endIndex); 84}; 85 86/** 87 * Test fixture. 88 * @constructor 89 * @extends {ChromeVoxUnitTestBase} 90 */ 91function CvoxEditableTextUnitTest() {} 92 93CvoxEditableTextUnitTest.prototype = { 94 __proto__: ChromeVoxUnitTestBase.prototype, 95 96 /** @override */ 97 closureModuleDeps: [ 98 'cvox.ChromeVoxEditableHTMLInput', 99 'cvox.ChromeVoxEditableTextBase', 100 'cvox.ChromeVoxEventWatcher', 101 'cvox.TextChangeEvent', 102 'cvox.TtsInterface', 103 'cvox.TypingEcho', 104 ], 105 106 /** @override */ 107 setUp: function() { 108 // TODO: These tests are all assuming we used the IBeam cursor. 109 // We need to add coverage for block cursor. 110 cvox.ChromeVoxEditableTextBase.useIBeamCursor = true; 111 cvox.ChromeVox.typingEcho = cvox.TypingEcho.CHARACTER_AND_WORD; 112 cvox.ChromeVoxEditableTextBase.eventTypingEcho = false; 113 cvox.ChromeVox.braille = new TestBraille(); 114 115 /** Simple mock. */ 116 cvox.ChromeVox.msgs = {}; 117 118 /** 119 * Simply return the message id. 120 * @param {string} msg Message id. 121 * @return {string} Message id. 122 */ 123 cvox.ChromeVox.msgs.getMsg = function(msg) { 124 return msg; 125 }; 126 }, 127 128 /** 129 * Sets up for a cursor movement test. 130 * @param {string} tagName Desired tag name, "input" or "textarea". 131 * @return {Object} object containing the editable element, and functions 132 * to prepare, run the test, and tear down. 133 * @private 134 */ 135 setUpForCursorTest_: function(tagName) { 136 var element, editable; 137 switch (tagName) { 138 case 'input': 139 element = document.createElement('input'); 140 editable = new cvox.ChromeVoxEditableHTMLInput(element, new TestTts()); 141 break; 142 case 'textarea': 143 element = document.createElement('textarea'); 144 editable = new cvox.ChromeVoxEditableTextArea(element, new TestTts()); 145 break; 146 default: 147 throw 'invalid tagName in setUpForCursorTest_'; 148 } 149 document.body.appendChild(element); 150 element.focus(); 151 152 var expect = function(str) { 153 assertEquals(element.selectionStart, element.selectionEnd); 154 assertEquals(str, element.value.substring(0, element.selectionStart) + 155 '|' + element.value.substring(element.selectionEnd)); 156 }; 157 return { 158 editable: editable, 159 expect: expect, 160 prepare: function(str) { 161 var position = str.indexOf('|'); 162 var value = str.substring(0, position) + str.substring(position + 1); 163 element.value = value; 164 element.selectionStart = element.selectionEnd = position; 165 editable.update(true /* triggeredByUser */); 166 expect(str); 167 }, 168 tearDown: function() { 169 document.body.removeChild(element); 170 } 171 }; 172 } 173}; 174 175TEST_F('CvoxEditableTextUnitTest', 'CursorNavigation', function() { 176 var tts = new TestTts(); 177 var obj = new cvox.ChromeVoxEditableTextBase('Hello', 0, 0, false, tts); 178 179 obj.changed(new cvox.TextChangeEvent('Hello', 1, 1)); 180 obj.changed(new cvox.TextChangeEvent('Hello', 2, 2)); 181 obj.changed(new cvox.TextChangeEvent('Hello', 3, 3)); 182 obj.changed(new cvox.TextChangeEvent('Hello', 4, 4)); 183 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 184 obj.changed(new cvox.TextChangeEvent('Hello', 4, 4)); 185 obj.changed(new cvox.TextChangeEvent('Hello', 3, 3)); 186 assertEqualStringArrays(['H', 'e', 'l', 'l', 'o', 187 'o', 'l'], tts.get()); 188 obj.changed(new cvox.TextChangeEvent('Hello', 0, 0)); 189 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 190 assertEqualStringArrays(['Hel', 'Hello'], tts.get()); 191}); 192 193/** Test typing words. */ 194TEST_F('CvoxEditableTextUnitTest', 'TypingWords', function() { 195 var tts = new TestTts(); 196 var obj = new cvox.ChromeVoxEditableTextBase('', 0, 0, false, tts); 197 obj.changed(new cvox.TextChangeEvent('H', 1, 1)); 198 obj.changed(new cvox.TextChangeEvent('He', 2, 2)); 199 obj.changed(new cvox.TextChangeEvent('Hel', 3, 3)); 200 obj.changed(new cvox.TextChangeEvent('Hell', 4, 4)); 201 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 202 obj.changed(new cvox.TextChangeEvent('Hello,', 6, 6)); 203 obj.changed(new cvox.TextChangeEvent('Hello, ', 7, 7)); 204 obj.changed(new cvox.TextChangeEvent('Hello, W', 8, 8)); 205 obj.changed(new cvox.TextChangeEvent('Hello, Wo', 9, 9)); 206 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 10, 10)); 207 obj.changed(new cvox.TextChangeEvent('Hello, Worl', 11, 11)); 208 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 209 obj.changed(new cvox.TextChangeEvent('Hello, World.', 13, 13)); 210 assertEqualStringArrays(['H', 'e', 'l', 'l', 'o', 'Hello,', 211 ' ', 212 'W', 'o', 'r', 'l', 'd', 'World.'], 213 tts.get()); 214 215 // Backspace 216 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 217 obj.changed(new cvox.TextChangeEvent('Hello, Worl', 11, 11)); 218 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 10, 10)); 219 assertEqualStringArrays(['.', 'd', 'l'], tts.get()); 220 221 // Forward-delete 222 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 9, 9)); 223 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 8, 8)); 224 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 7, 7)); 225 obj.changed(new cvox.TextChangeEvent('Hello, or', 7, 7)); 226 obj.changed(new cvox.TextChangeEvent('Hello, r', 7, 7)); 227 obj.changed(new cvox.TextChangeEvent('Hello, ', 7, 7)); 228 assertEqualStringArrays(['r', 'o', 'W', 'W', 'o', 'r'], tts.get()); 229 230 // Clear all 231 obj.changed(new cvox.TextChangeEvent('', 0, 0)); 232 assertEqualStringArrays(['Hello, , deleted'], tts.get()); 233 234 // Paste / insert a whole word 235 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 236 assertEqualStringArrays(['Hello'], tts.get()); 237 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 238 assertEqualStringArrays([', World'], tts.get()); 239}); 240 241/** Test selection. */ 242TEST_F('CvoxEditableTextUnitTest', 'Selection', function() { 243 var tts = new TestTts(); 244 var obj = 245 new cvox.ChromeVoxEditableTextBase('Hello, world.', 0, 0, false, tts); 246 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 1)); 247 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 2)); 248 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 3)); 249 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 4)); 250 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 5)); 251 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 6)); 252 assertEqualStringArrays(['H', 'selected', 253 'e', 'added_to_selection', 254 'l', 'added_to_selection', 255 'l', 'added_to_selection', 256 'o', 'added_to_selection', 257 ',', 'added_to_selection'], 258 tts.get()); 259 obj.changed(new cvox.TextChangeEvent('Hello, world.', 0, 12)); 260 assertEqualStringArrays([' world', 'added_to_selection'], 261 tts.get()); 262 obj.changed(new cvox.TextChangeEvent('Hello, world.', 1, 12)); 263 assertEqualStringArrays(['H', 'removed_from_selection'], 264 tts.get()); 265 obj.changed(new cvox.TextChangeEvent('Hello, world.', 2, 5)); 266 assertEqualStringArrays(['llo', 'selected'], 267 tts.get()); 268 obj.changed(new cvox.TextChangeEvent('Hello, world.', 2, 2)); 269 assertEqualStringArrays(['Unselected'], 270 tts.get()); 271}); 272 273 274/** Test multi-line text. */ 275TEST_F('CvoxEditableTextUnitTest', 'MultiLineText', function() { 276 var str = 'This string\nspans\nfive lines.\n \n'; 277 var tts = new TestTts(); 278 var obj = new cvox.ChromeVoxEditableTextBase(str, 0, 0, false, tts); 279 obj.multiline = true; 280 obj.getLineIndex = function(index) { 281 if (index >= 33) { 282 return 4; 283 } else if (index >= 30) { 284 return 3; 285 } else if (index >= 18) { 286 return 2; 287 } else if (index >= 12) { 288 return 1; 289 } else { 290 return 0; 291 } 292 }; 293 obj.getLineStart = function(index) { 294 return [0, 12, 18, 30, 33][index]; 295 }; 296 obj.getLineEnd = function(index) { 297 return [11, 17, 29, 32, 33][index]; 298 }; 299 assertEquals('This string', obj.getLine(0)); 300 obj.changed(new cvox.TextChangeEvent(str, 12, 12)); 301 assertEqualStringArrays(['spans'], tts.get()); 302 TestBraille.assertContent('spans', 0); 303 obj.changed(new cvox.TextChangeEvent(str, 18, 18)); 304 assertEqualStringArrays(['five lines.'], tts.get()); 305 TestBraille.assertContent('five lines.', 0); 306 obj.changed(new cvox.TextChangeEvent(str, 30, 30)); 307 assertEqualStringArrays(['text_box_whitespace'], tts.get()); 308 TestBraille.assertContent(' ', 0); 309 obj.changed(new cvox.TextChangeEvent(str, 33, 33)); 310 assertEqualStringArrays(['text_box_blank'], tts.get()); 311 TestBraille.assertContent('', 0); 312 obj.changed(new cvox.TextChangeEvent(str, 0, 1)); 313 assertEqualStringArrays(['T', 'selected'], tts.get()); 314 TestBraille.assertContent('This string', 0, 1); 315 obj.changed(new cvox.TextChangeEvent(str, 0, 12)); 316 assertEqualStringArrays(['his string\n', 'added_to_selection'], 317 tts.get()); 318 // Newline stripped, thus 11, not 12. 319 TestBraille.assertContent('This string', 0, 11); 320 obj.changed(new cvox.TextChangeEvent(str, 0, str.length)); 321 assertEqualStringArrays([str.substr(12), 'added_to_selection'], 322 tts.get()); 323 TestBraille.assertContent('This string', 0, 11); 324 obj.changed(new cvox.TextChangeEvent(str, 12, 19)); 325 assertEqualStringArrays(['spans\nf', 'selected'], tts.get()); 326 TestBraille.assertContent('spans', 0, 5); 327}); 328 329 330/** 331 * Test autocomplete; suppose a user is typing "google.com/firefox" into an 332 * address bar, and it's being autocompleted. Sometimes it's autocompleted 333 * as they type, sometimes there's a short delay. 334 */ 335TEST_F('CvoxEditableTextUnitTest', 'Autocomplete', function() { 336 var tts = new TestTts(); 337 var obj = new cvox.ChromeVoxEditableTextBase('', 0, 0, false, tts); 338 339 // User types 'g' 340 obj.changed(new cvox.TextChangeEvent('g', 1, 1)); 341 assertEqualStringArrays(['g'], tts.get()); 342 343 // The rest of 'google.com' is autocompleted and automatically selected. 344 obj.changed(new cvox.TextChangeEvent('google.com', 1, 10)); 345 assertEqualStringArrays(['oogle.com, oogle.com'], tts.get()); 346 347 // The user doesn't realize it and types a few more characters of 'google.com' 348 // and this changes the selection (unselecting) as the user types them. 349 obj.changed(new cvox.TextChangeEvent('google.com', 2, 10)); 350 assertEqualStringArrays(['o', 'ogle.com'], tts.get()); 351 obj.changed(new cvox.TextChangeEvent('google.com', 3, 10)); 352 assertEqualStringArrays(['o', 'gle.com'], tts.get()); 353 obj.changed(new cvox.TextChangeEvent('google.com', 4, 10)); 354 assertEqualStringArrays(['g', 'le.com'], tts.get()); 355 356 // The user presses right-arrow, which fully unselects the remaining text. 357 obj.changed(new cvox.TextChangeEvent('google.com', 10, 10)); 358 assertEqualStringArrays(['Unselected'], tts.get()); 359 360 // The user types '/' 361 obj.changed(new cvox.TextChangeEvent('google.com/', 11, 11)); 362 assertEqualStringArrays(['com/'], tts.get()); 363 364 // The user types 'f', and 'finance' is autocompleted 365 obj.changed(new cvox.TextChangeEvent('google.com/finance', 12, 18)); 366 assertEqualStringArrays(['finance, inance'], tts.get()); 367 368 // The user types 'i' 369 obj.changed(new cvox.TextChangeEvent('google.com/finance', 13, 18)); 370 assertEqualStringArrays(['i', 'nance'], tts.get()); 371 372 // The user types 'r', now 'firefox' is autocompleted 373 obj.changed(new cvox.TextChangeEvent('google.com/firefox', 14, 18)); 374 assertEqualStringArrays(['refox, efox'], tts.get()); 375 376 // The user presses right-arrow to accept the completion. 377 obj.changed(new cvox.TextChangeEvent('google.com/firefox', 18, 18)); 378 assertEqualStringArrays(['Unselected'], tts.get()); 379}); 380 381 382/** 383 * Test a few common scenarios where text is replaced. 384 */ 385TEST_F('CvoxEditableTextUnitTest', 'ReplacingText', function() { 386 // Initial value is Alabama. 387 var tts = new TestTts(); 388 var obj = new cvox.ChromeVoxEditableTextBase('Alabama', 0, 0, false, tts); 389 390 // Entire text replaced with Alaska. 391 obj.changed(new cvox.TextChangeEvent('Alaska', 0, 0)); 392 assertEqualStringArrays(['Alaska'], tts.get()); 393 394 // Entire text selected. 395 obj.changed(new cvox.TextChangeEvent('Alaska', 0, 6)); 396 assertEqualStringArrays(['Alaska', 'selected'], tts.get()); 397 398 // Entire text replaced with Arizona. 399 obj.changed(new cvox.TextChangeEvent('Arizona', 7, 7)); 400 assertEqualStringArrays(['Arizona'], tts.get()); 401 402 // Entire text selected. 403 obj.changed(new cvox.TextChangeEvent('Arizona', 0, 7)); 404 assertEqualStringArrays(['Arizona', 'selected'], tts.get()); 405 406 // Click between 'r' and 'i'. 407 obj.changed(new cvox.TextChangeEvent('Arizona', 2, 2)); 408 assertEqualStringArrays(['Unselected'], tts.get()); 409 410 // Next character removed from selection. 411 obj.changed(new cvox.TextChangeEvent('Arizona', 2, 7)); 412 assertEqualStringArrays(['izona', 'selected'], tts.get()); 413 414 // Selection replaced with "kansas" to make Arkansas. This time it 415 // says "kansas" because the deleted text was selected. 416 obj.changed(new cvox.TextChangeEvent('Arkansas', 8, 8)); 417 assertEqualStringArrays(['kansas'], tts.get()); 418}); 419 420 421/** 422 * Test feedback when text changes in a long sentence. 423 */ 424TEST_F('CvoxEditableTextUnitTest', 'ReplacingLongText', function() { 425 var tts = new TestTts(); 426 var obj = new cvox.ChromeVoxEditableTextBase( 427 'I love deadlines. I like the whooshing sound they make as they fly by.', 428 0, 0, false, tts); 429 430 // Change the whole sentence without moving the cursor. It should speak 431 // only the part that changed, but it should speak whole words. 432 obj.changed(new cvox.TextChangeEvent( 433 'I love deadlines. I love the whooshing sounds they make as they fly by.', 434 0, 0)); 435 assertEqualStringArrays(['love the whooshing sounds'], tts.get()); 436}); 437 438/** Tests character echo. */ 439TEST_F('CvoxEditableTextUnitTest', 'CharacterEcho', function() { 440 cvox.ChromeVox.typingEcho = cvox.TypingEcho.CHARACTER; 441 var tts = new TestTts(); 442 var obj = new cvox.ChromeVoxEditableTextBase('', 0, 0, false, tts); 443 obj.changed(new cvox.TextChangeEvent('H', 1, 1)); 444 obj.changed(new cvox.TextChangeEvent('He', 2, 2)); 445 obj.changed(new cvox.TextChangeEvent('Hel', 3, 3)); 446 obj.changed(new cvox.TextChangeEvent('Hell', 4, 4)); 447 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 448 obj.changed(new cvox.TextChangeEvent('Hello,', 6, 6)); 449 obj.changed(new cvox.TextChangeEvent('Hello, ', 7, 7)); 450 obj.changed(new cvox.TextChangeEvent('Hello, W', 8, 8)); 451 obj.changed(new cvox.TextChangeEvent('Hello, Wo', 9, 9)); 452 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 10, 10)); 453 obj.changed(new cvox.TextChangeEvent('Hello, Worl', 11, 11)); 454 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 455 obj.changed(new cvox.TextChangeEvent('Hello, World.', 13, 13)); 456 assertEqualStringArrays( 457 ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '.'], 458 tts.get()); 459}); 460 461 462/** Tests word echo. */ 463TEST_F('CvoxEditableTextUnitTest', 'WordEcho', function() { 464 cvox.ChromeVox.typingEcho = cvox.TypingEcho.WORD; 465 var tts = new TestTts(); 466 var obj = new cvox.ChromeVoxEditableTextBase('', 0, 0, false, tts); 467 obj.changed(new cvox.TextChangeEvent('H', 1, 1)); 468 obj.changed(new cvox.TextChangeEvent('He', 2, 2)); 469 obj.changed(new cvox.TextChangeEvent('Hel', 3, 3)); 470 obj.changed(new cvox.TextChangeEvent('Hell', 4, 4)); 471 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 472 obj.changed(new cvox.TextChangeEvent('Hello,', 6, 6)); 473 obj.changed(new cvox.TextChangeEvent('Hello, ', 7, 7)); 474 obj.changed(new cvox.TextChangeEvent('Hello, W', 8, 8)); 475 obj.changed(new cvox.TextChangeEvent('Hello, Wo', 9, 9)); 476 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 10, 10)); 477 obj.changed(new cvox.TextChangeEvent('Hello, Worl', 11, 11)); 478 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 479 obj.changed(new cvox.TextChangeEvent('Hello, World.', 13, 13)); 480 assertEqualStringArrays( 481 ['Hello,', 'World.'], 482 tts.get()); 483}); 484 485 486/** Tests no echo. */ 487TEST_F('CvoxEditableTextUnitTest', 'NoEcho', function() { 488 cvox.ChromeVox.typingEcho = cvox.TypingEcho.NONE; 489 var tts = new TestTts(); 490 var obj = new cvox.ChromeVoxEditableTextBase('', 0, 0, false, tts); 491 obj.changed(new cvox.TextChangeEvent('H', 1, 1)); 492 obj.changed(new cvox.TextChangeEvent('He', 2, 2)); 493 obj.changed(new cvox.TextChangeEvent('Hel', 3, 3)); 494 obj.changed(new cvox.TextChangeEvent('Hell', 4, 4)); 495 obj.changed(new cvox.TextChangeEvent('Hello', 5, 5)); 496 obj.changed(new cvox.TextChangeEvent('Hello,', 6, 6)); 497 obj.changed(new cvox.TextChangeEvent('Hello, ', 7, 7)); 498 obj.changed(new cvox.TextChangeEvent('Hello, W', 8, 8)); 499 obj.changed(new cvox.TextChangeEvent('Hello, Wo', 9, 9)); 500 obj.changed(new cvox.TextChangeEvent('Hello, Wor', 10, 10)); 501 obj.changed(new cvox.TextChangeEvent('Hello, Worl', 11, 11)); 502 obj.changed(new cvox.TextChangeEvent('Hello, World', 12, 12)); 503 obj.changed(new cvox.TextChangeEvent('Hello, World.', 13, 13)); 504 assertEqualStringArrays( 505 [], 506 tts.get()); 507}); 508 509/** Tests cursor movement in an input field by character. */ 510TEST_F('CvoxEditableTextUnitTest', 'CursorMovementByCharacter', function() { 511 var test = this.setUpForCursorTest_('input'); 512 var editable = test.editable, prepare = test.prepare, expect = test.expect; 513 try { 514 // Moving near the beginning of the text. 515 prepare('|"Hello," says Sally.'); 516 editable.moveCursorToPreviousCharacter(); 517 expect('|"Hello," says Sally.'); 518 editable.moveCursorToNextCharacter(); 519 expect('"|Hello," says Sally.'); 520 editable.moveCursorToNextCharacter(); 521 expect('"H|ello," says Sally.'); 522 523 // Moving near the end of the text. 524 prepare('"Hello," says Sally|.'); 525 editable.moveCursorToPreviousCharacter(); 526 expect('"Hello," says Sall|y.'); 527 editable.moveCursorToNextCharacter(); 528 expect('"Hello," says Sally|.'); 529 editable.moveCursorToNextCharacter(); 530 expect('"Hello," says Sally.|'); 531 editable.moveCursorToNextCharacter(); 532 expect('"Hello," says Sally.|'); 533 } finally { 534 test.tearDown(); 535 } 536}); 537 538/** Tests cursor movement in an input field by word. */ 539TEST_F('CvoxEditableTextUnitTest', 'CursorMovementByWord', function() { 540 var test = this.setUpForCursorTest_('input'); 541 var editable = test.editable, prepare = test.prepare, expect = test.expect; 542 try { 543 // Moving forward. 544 prepare('"He|llo," says Sally.'); 545 editable.moveCursorToNextWord(); 546 expect('"Hello|," says Sally.'); 547 editable.moveCursorToNextWord(); 548 expect('"Hello," says| Sally.'); 549 editable.moveCursorToNextWord(); 550 expect('"Hello," says Sally|.'); 551 editable.moveCursorToNextWord(); 552 expect('"Hello," says Sally.|'); 553 editable.moveCursorToNextWord(); 554 expect('"Hello," says Sally.|'); 555 556 // Moving backward. 557 prepare('"Hello," says S|ally.'); 558 editable.moveCursorToPreviousWord(); 559 expect('"Hello," says |Sally.'); 560 editable.moveCursorToPreviousWord(); 561 expect('"Hello," |says Sally.'); 562 editable.moveCursorToPreviousWord(); 563 expect('"|Hello," says Sally.'); 564 editable.moveCursorToPreviousWord(); 565 expect('|"Hello," says Sally.'); 566 editable.moveCursorToPreviousWord(); 567 expect('|"Hello," says Sally.'); 568 } finally { 569 test.tearDown(); 570 } 571}); 572 573/** Tests that character and word movement still work in <textarea>. */ 574TEST_F('CvoxEditableTextUnitTest', 'CursorMovementTextArea', function() { 575 var test = this.setUpForCursorTest_('textarea'); 576 var editable = test.editable, prepare = test.prepare, expect = test.expect; 577 try { 578 prepare('|Hello, Larry.\nHello, Sergey.'); 579 editable.moveCursorToNextCharacter(); 580 expect('H|ello, Larry.\nHello, Sergey.'); 581 editable.moveCursorToNextWord(); 582 expect('Hello|, Larry.\nHello, Sergey.'); 583 editable.moveCursorToNextWord(); 584 expect('Hello, Larry|.\nHello, Sergey.'); 585 editable.moveCursorToNextWord(); 586 expect('Hello, Larry.\nHello|, Sergey.'); 587 editable.moveCursorToNextCharacter(); 588 expect('Hello, Larry.\nHello,| Sergey.'); 589 editable.moveCursorToPreviousWord(); 590 expect('Hello, Larry.\n|Hello, Sergey.'); 591 editable.moveCursorToPreviousCharacter(); 592 expect('Hello, Larry.|\nHello, Sergey.'); 593 } finally { 594 test.tearDown(); 595 } 596}); 597 598/** Tests that line navigation works. */ 599TEST_F('CvoxEditableTextUnitTest', 'CursorMovementByLine', function() { 600 var test = this.setUpForCursorTest_('textarea'); 601 var editable = test.editable, prepare = test.prepare, expect = test.expect; 602 try { 603 prepare('123\n1234\n1234|5\n\nHi'); 604 editable.moveCursorToPreviousLine(); 605 expect('123\n1234|\n12345\n\nHi'); 606 editable.moveCursorToPreviousLine(); 607 expect('123|\n1234\n12345\n\nHi'); 608 editable.moveCursorToNextLine(); 609 expect('123\n123|4\n12345\n\nHi'); 610 editable.moveCursorToNextLine(); 611 expect('123\n1234\n123|45\n\nHi'); 612 editable.moveCursorToNextLine(); 613 expect('123\n1234\n12345\n|\nHi'); 614 editable.moveCursorToNextLine(); 615 expect('123\n1234\n12345\n\n|Hi'); 616 editable.moveCursorToNextLine(); 617 expect('123\n1234\n12345\n\nHi|'); 618 619 prepare('foo|bar'); 620 editable.moveCursorToPreviousLine(); 621 expect('|foobar'); 622 editable.moveCursorToPreviousLine(); 623 expect('|foobar'); 624 editable.moveCursorToNextLine(); 625 expect('foobar|'); 626 editable.moveCursorToNextLine(); 627 expect('foobar|'); 628 } finally { 629 test.tearDown(); 630 } 631}); 632 633/** Tests that paragraph navigation works. */ 634TEST_F('CvoxEditableTextUnitTest', 'CursorMovementByParagraph', function() { 635 var test = this.setUpForCursorTest_('textarea'); 636 var editable = test.editable, prepare = test.prepare, expect = test.expect; 637 try { 638 prepare('Para|graph 1\nParagraph 2\nParagraph 3'); 639 editable.moveCursorToNextParagraph(); 640 expect('Paragraph 1\n|Paragraph 2\nParagraph 3'); 641 editable.moveCursorToNextParagraph(); 642 expect('Paragraph 1\nParagraph 2\n|Paragraph 3'); 643 editable.moveCursorToNextParagraph(); 644 expect('Paragraph 1\nParagraph 2\nParagraph 3|'); 645 editable.moveCursorToPreviousParagraph(); 646 expect('Paragraph 1\nParagraph 2\n|Paragraph 3'); 647 editable.moveCursorToPreviousParagraph(); 648 expect('Paragraph 1\n|Paragraph 2\nParagraph 3'); 649 editable.moveCursorToPreviousParagraph(); 650 expect('|Paragraph 1\nParagraph 2\nParagraph 3'); 651 } finally { 652 test.tearDown(); 653 } 654}); 655 656/** Tests normalization of TextChangeEvent's */ 657TEST_F('CvoxEditableTextUnitTest', 'TextChangeEvent', function() { 658 var event1 = new cvox.TextChangeEvent('foo', 0, 1, true); 659 var event2 = new cvox.TextChangeEvent('foo', 1, 0, true); 660 var event3 = new cvox.TextChangeEvent('foo', 1, 1, true); 661 662 assertEquals(0, event1.start); 663 assertEquals(1, event1.end); 664 665 assertEquals(0, event2.start); 666 assertEquals(1, event2.end); 667 668 assertEquals(1, event3.start); 669 assertEquals(1, event3.end); 670}); 671