2 * Copyright 2013 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
8 * Tester for lonpress typing accents.
10 function LongPressTypingTester(layout) {
15 LongPressTypingTester.prototype = {
17 * Extends the subtask scheduler.
19 __proto__: SubtaskScheduler.prototype,
22 * The candidate popup.
23 * @type {?kb-altkey-container}
25 get candidatesPopup() {
26 var keyset = $('keyboard').activeKeyset;
27 assertTrue(!!keyset, 'Unable to find active keyset.');
28 var popup = keyset.querySelector('kb-altkey-container');
29 assertTrue(!!popup, 'Unable to find altkey container.');
34 * Mocks pressing a key.
35 * @param {string} label The key to press.
36 * @param {string} keysetId Initial keyset.
38 keyPress: function(label, keysetId) {
41 Debug('mock keypress on \'' + label + '\'');
43 // Verify that popup is initially hidden.
44 var popup = self.candidatesPopup;
45 assertTrue(!!popup && popup.hidden,
46 'Candidate popup should be hidden initially.');
49 var key = findKey(label);
50 assertTrue(!!key, 'Unable to find key labelled "' + label + '".');
51 key.down({pointerId: 1});
53 this.addWaitCondition(fn, keysetId);
58 * Retrieves a key from the candidate popup.
59 * @return {?kb-altkey} The matching key or undefined if not found.
61 findCandidate: function(label) {
62 var popup = this.candidatesPopup;
63 var candidates = popup.querySelectorAll('kb-altkey');
64 for (var i = 0; i < candidates.length; i++) {
65 if (candidates[i].textContent == label)
71 * Mocks selection of a key from the candidate popup.
72 * @param {string} baseLabel Label for the pressed key.
73 * @param {string} candidateLabel Label for the selected key.
74 * @param {int} keyCode The key code for the selected key.
76 selectCandidate: function(baseLabel, candidateLabel, keyCode) {
79 Debug('mock keyup on \'' + candidateLabel + '\'');
81 // Verify that popup window is visible.
82 var popup = self.candidatesPopup;
83 assertFalse(popup.hidden, 'Candidate popup should be visible.');
85 // Verify that the popup window contains the base and candidate keys.
86 var altKey = self.findCandidate(candidateLabel);
87 var baseKey = self.findCandidate(baseLabel);
88 var errorMessage = function(label) {
89 return 'Unable to find \'' + label + '\' in candidate list.'
91 assertTrue(!!altKey, errorMessage(candidateLabel));
92 assertTrue(!!baseKey, errorMessage(baseLabel));
94 // A keyout event should be dispatched before a keyover event if the
95 // candidateLabel is not the baseLabel.
96 if (baseLabel != candidateLabel) {
97 baseKey.out({pointerId: 1, relatedTarget: baseKey});
98 altKey.over({pointerId: 1, relatedTarget: altKey});
101 // Verify that the candidate key is typed on release of the longpress.
102 var send = chrome.virtualKeyboardPrivate.sendKeyEvent;
103 var unicodeValue = candidateLabel.charCodeAt(0);
104 send.addExpectation({
106 charValue: unicodeValue,
108 modifiers: Modifier.NONE
110 send.addExpectation({
112 charValue: unicodeValue,
114 modifiers: Modifier.NONE
116 var mockEvent = {pointerId: 1};
117 altKey.up(mockEvent);
121 state: 'candidatePopupVisibility',
128 * Mocks aborting a longpress selection.
129 * @param {string} baselabel The label for the pressed key.
131 abortSelection: function(baseLabel) {
133 var fn = function() {
134 Debug('mock abort on \'' + baseLabel + '\'');
136 // Verify that popup window is visible.
137 var popup = self.candidatesPopup;
138 assertFalse(popup.hidden, 'Candidate popup should be visible.');
140 // Verify that the popup window contains the base and candidate keys.
141 var baseKey = self.findCandidate(baseLabel);
142 var errorMessage = function(label) {
143 return 'Unable to find \'' + label + '\' in candidate list.'
145 assertTrue(!!baseKey, errorMessage(baseLabel));
146 baseKey.out({pointerId: 1, relatedTarget: baseKey});
147 popup.up({pointerId: 1});
150 state: 'candidatePopupVisibility',
157 * Waits for the candidate popup to close.
159 verifyClosedPopup: function() {
160 var fn = function() {
161 Debug('Validated that candidate popup has closed.');
164 state: 'candidatePopupVisibility',
172 * Tests that typing characters on the default lowercase keyboard triggers the
173 * correct sequence of events. The test is run asynchronously since the
174 * keyboard loads keysets dynamically.
176 function testLowercaseKeysetAsync(testDoneCallback) {
177 var runTest = function() {
178 // Keyboard defaults to lowercase.
179 mockTypeCharacter('a', 0x41, Modifier.NONE);
180 mockTypeCharacter('s', 0x53, Modifier.NONE);
181 mockTypeCharacter('.', 0xBE, Modifier.NONE);
182 mockTypeCharacter('\b', 0x08, Modifier.NONE, 0x08);
183 mockTypeCharacter('\n', 0x0D, Modifier.NONE, 0x0A);
184 mockTypeCharacter(' ', 0x20, Modifier.NONE);
186 onKeyboardReady('testLowercaseKeysetAsync', runTest, testDoneCallback);
190 * Tests long press on a key that has alternate sugestions. For example,
191 * longpressing the 'a' key displays 'a acute' 'a grave', etc. Longpressing
192 * characters on the top row of the keyboard displays numbers as alternatives.
194 function testLongPressTypeAccentedCharacterAsync(testDoneCallback) {
195 var tester = new LongPressTypingTester(Layout.DEFAULT);
197 var checkLongPressType = function(key, candidate, keyCode) {
198 tester.keyPress(key, Keyset.LOWER);
199 tester.wait(1000, Keyset.LOWER);
200 tester.selectCandidate(key, candidate, keyCode);
201 tester.verifyClosedPopup();
204 // Test popup for letters with candidate lists that are derived from a
205 // single source (hintText or accents).
206 // Type lowercase A grave
207 checkLongPressType('a', '\u00E0', 0);
208 // Type the digit '1' (hintText on 'q' key).
209 checkLongPressType('q', '1', 0x31);
211 // Test popup for letter that has a candidate list combining hintText and
213 // Type lowercase E acute.
214 checkLongPressType('e', '\u00E9', 0, Modifier.NONE);
215 // Type the digit '3' (hintText on the 'e' key).
216 checkLongPressType('e', '3', 0x33, Modifier.NONE);
218 // Mock aborting a longpress selection.
219 tester.keyPress('e', Keyset.LOWER);
220 tester.wait(1000, Keyset.LOWER);
221 tester.abortSelection('e');
222 tester.verifyClosedPopup();
224 // Mock longpress q then release it. Catches regression in crbug/305649.
225 checkLongPressType('q', 'q', 0x51);
227 tester.scheduleTest('testLongPressTypeAccentedCharacterAsync',
232 * When typing quickly, one can often press a second key before releasing the
233 * first. This test confirms that both keys are typed in the correct order.
235 function testAutoReleasePreviousKey(testDoneCallback) {
236 var runTest = function() {
237 var key = findKey('a');
238 assertTrue(!!key, 'Unable to find key labelled "a".');
239 var unicodeValue = 'a'.charCodeAt(0);
240 var send = chrome.virtualKeyboardPrivate.sendKeyEvent;
241 send.addExpectation({
243 charValue: unicodeValue,
245 modifiers: Modifier.NONE
247 send.addExpectation({
249 charValue: unicodeValue,
251 modifiers: Modifier.NONE
253 var mockEvent = {pointerId:2};
255 mockTypeCharacter('s', 0x53, Modifier.NONE);
257 onKeyboardReady('testAutoReleasePreviousKey', runTest, testDoneCallback);
261 * When touch typing, one can often press a key and move slightly out of the key
262 * area before releasing the key. This test confirms that the key is not
265 function testFingerOutType(testDoneCallback) {
266 var runTest = function() {
267 var key = findKey('a');
268 assertTrue(!!key, 'Unable to find key labelled "a".');
269 var unicodeValue = 'a'.charCodeAt(0);
270 var send = chrome.virtualKeyboardPrivate.sendKeyEvent;
272 // Test finger moves out of typed key slightly before release. The key
273 // should not be dropped.
274 send.addExpectation({
276 charValue: unicodeValue,
278 modifiers: Modifier.NONE
280 send.addExpectation({
282 charValue: unicodeValue,
284 modifiers: Modifier.NONE
286 var mockEvent = { pointerId:2 };
289 // Mocks finger releases after moved out of the 'a' key.
290 $('keyboard').up(mockEvent);
292 // Test a second finger types on a different key before first finger
293 // releases (yet moves out of the typed key). The first typed key should not
295 send.addExpectation({
297 charValue: unicodeValue,
299 modifiers: Modifier.NONE
301 send.addExpectation({
303 charValue: unicodeValue,
305 modifiers: Modifier.NONE
309 mockTypeCharacter('s', 0x53, Modifier.NONE);
311 onKeyboardReady('testFingerOutType', runTest, testDoneCallback);
315 * Tests that flicking upwards on a key with hintText types the hint text.
316 * @param {Function} testDoneCallback The callback function on completion.
318 // TODO(rsadam): Reenable when crbug.com/323211 is fixed.
319 function disabled_testSwipeFlick(testDoneCallback) {
320 var mockEvent = function(xOffset, yOffset, target, relatedTarget) {
321 var bounds = target.getBoundingClientRect();
325 screenX: bounds.left + xOffset,
326 // Note: Y is negative in the 'up' direction.
327 screenY: bounds.bottom - yOffset,
329 relatedTarget: relatedTarget
332 var runTest = function() {
333 var key = findKey('.');
334 var send = chrome.virtualKeyboardPrivate.sendKeyEvent;
335 // Test flick on the '.', expect '?' to appear.
336 send.addExpectation({
338 charValue: '?'.charCodeAt(0),
340 modifiers: Modifier.SHIFT
342 send.addExpectation({
344 charValue: '?'.charCodeAt(0),
346 modifiers: Modifier.SHIFT
348 var height = key.clientHeight;
349 var width = key.clientWidth;
350 $('keyboard').down(mockEvent(0, 0, key));
351 $('keyboard').move(mockEvent(0, height/2, key));
352 $('keyboard').up(mockEvent(0, height/2, key));
354 // Test flick that exits the keyboard area. Expect '1' to appear.
355 var qKey = findKey('q');
356 send.addExpectation({
358 charValue: '1'.charCodeAt(0),
360 modifiers: Modifier.NONE
362 send.addExpectation({
364 charValue: '1'.charCodeAt(0),
366 modifiers: Modifier.NONE
368 $('keyboard').down(mockEvent(width/2, height/2, qKey));
369 $('keyboard').move(mockEvent(width/2, height, qKey));
370 $('keyboard').out(mockEvent(width/2, 2*height, qKey, $('keyboard')));
372 // Test basic long flick. Should not have any output.
373 $('keyboard').down(mockEvent(0, 0, key));
374 $('keyboard').move(mockEvent(0, height/2, key));
375 $('keyboard').move(mockEvent(0, 2*height, key));
376 $('keyboard').up(mockEvent(0, 2*height, key));
378 // Test flick that crosses the original key boundary.
379 send.addExpectation({
381 charValue: '?'.charCodeAt(0),
383 modifiers: Modifier.SHIFT
385 send.addExpectation({
387 charValue: '?'.charCodeAt(0),
389 modifiers: Modifier.SHIFT
391 var lKey = findKey('l');
392 $('keyboard').down(mockEvent(0, height/2, key));
393 $('keyboard').move(mockEvent(0, height, key));
394 key.out(mockEvent(0, height, key, lKey));
395 $('keyboard').move(mockEvent(0, height/2, lKey));
396 $('keyboard').up(mockEvent(0, height/2, lKey));
398 // Test long flick that crosses the original key boundary.
399 $('keyboard').down(mockEvent(0, 0, key));
400 $('keyboard').move(mockEvent(0, height/2, key));
401 key.out(mockEvent(0, height, key, lKey));
402 $('keyboard').move(mockEvent(0, height, lKey));
403 $('keyboard').up(mockEvent(0, height, lKey));
405 // Test composed swipe and flick. Should not have any output.
406 var move = chrome.virtualKeyboardPrivate.moveCursor;
407 move.addExpectation(SwipeDirection.RIGHT,
408 Modifier.CONTROL & Modifier.SHIFT);
409 $('keyboard').down(mockEvent(0, 0, key));
410 $('keyboard').move(mockEvent(0, height, key));
411 $('keyboard').move(mockEvent(width, height, key));
412 $('keyboard').up(mockEvent(width, height, key));
414 onKeyboardReady('testSwipeFlick', runTest, testDoneCallback);