Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / test / data / chromeos / virtual_keyboard / typing_test.js
1 /*
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.
5  */
6
7 /**
8  * Tester for lonpress typing accents.
9  */
10 function LongPressTypingTester(layout) {
11   this.layout = layout;
12   this.subtasks = [];
13 }
14
15 LongPressTypingTester.prototype = {
16   /**
17    * Extends the subtask scheduler.
18    */
19   __proto__: SubtaskScheduler.prototype,
20
21   /**
22    * The candidate popup.
23    * @type {?kb-altkey-container}
24    */
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.');
30     return popup;
31   },
32
33   /**
34    * Mocks pressing a key.
35    * @param {string} label The key to press.
36    * @param {string} keysetId Initial keyset.
37    */
38   keyPress: function(label, keysetId) {
39     var self = this;
40     var fn = function() {
41       Debug('mock keypress on \'' + label + '\'');
42
43       // Verify that popup is initially hidden.
44       var popup = self.candidatesPopup;
45       assertTrue(!!popup && popup.hidden,
46                  'Candidate popup should be hidden initially.');
47
48       // Mock keypress.
49       var key = findKey(label);
50       assertTrue(!!key, 'Unable to find key labelled "' + label + '".');
51       key.down({pointerId: 1});
52     };
53     this.addWaitCondition(fn, keysetId);
54     this.addSubtask(fn);
55   },
56
57   /**
58    * Retrieves a key from the candidate popup.
59    * @return {?kb-altkey}  The matching key or undefined if not found.
60    */
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)
66         return candidates[i];
67     }
68   },
69
70   /**
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.
75    */
76   selectCandidate: function(baseLabel, candidateLabel, keyCode) {
77     var self = this;
78     var fn = function() {
79       Debug('mock keyup on \'' + candidateLabel + '\'');
80
81       // Verify that popup window is visible.
82       var popup = self.candidatesPopup;
83       assertFalse(popup.hidden, 'Candidate popup should be visible.');
84
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.'
90       }
91       assertTrue(!!altKey, errorMessage(candidateLabel));
92       assertTrue(!!baseKey, errorMessage(baseLabel));
93
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});
99       }
100
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({
105         type: 'keydown',
106         charValue: unicodeValue,
107         keyCode: keyCode,
108         modifiers: Modifier.NONE
109       });
110       send.addExpectation({
111         type: 'keyup',
112         charValue: unicodeValue,
113         keyCode: keyCode,
114         modifiers: Modifier.NONE
115       });
116       var mockEvent = {pointerId: 1};
117       altKey.up(mockEvent);
118       popup.up(mockEvent);
119     };
120     fn.waitCondition = {
121       state: 'candidatePopupVisibility',
122       value: true
123     };
124     this.addSubtask(fn);
125   },
126
127   /**
128    * Mocks aborting a longpress selection.
129    * @param {string} baselabel The label for the pressed key.
130    */
131   abortSelection: function(baseLabel) {
132     var self = this;
133     var fn = function() {
134       Debug('mock abort on \'' + baseLabel + '\'');
135
136       // Verify that popup window is visible.
137       var popup = self.candidatesPopup;
138       assertFalse(popup.hidden, 'Candidate popup should be visible.');
139
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.'
144       }
145       assertTrue(!!baseKey, errorMessage(baseLabel));
146       baseKey.out({pointerId: 1, relatedTarget: baseKey});
147       popup.up({pointerId: 1});
148     };
149     fn.waitCondition = {
150       state: 'candidatePopupVisibility',
151       value: true
152     };
153     this.addSubtask(fn);
154   },
155
156   /**
157    * Waits for the candidate popup to close.
158    */
159   verifyClosedPopup: function() {
160     var fn = function() {
161       Debug('Validated that candidate popup has closed.');
162     };
163     fn.waitCondition = {
164       state: 'candidatePopupVisibility',
165       value: false
166     };
167     this.addSubtask(fn);
168   }
169 }
170
171 /**
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.
175  */
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);
185   };
186   onKeyboardReady('testLowercaseKeysetAsync', runTest, testDoneCallback);
187 }
188
189 /**
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.
193  */
194 function testLongPressTypeAccentedCharacterAsync(testDoneCallback) {
195   var tester = new LongPressTypingTester(Layout.DEFAULT);
196
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();
202   };
203
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);
210
211   // Test popup for letter that has a candidate list combining hintText and
212   // accented letters.
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);
217
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();
223
224   // Mock longpress q then release it. Catches regression in crbug/305649.
225   checkLongPressType('q', 'q', 0x51);
226
227   tester.scheduleTest('testLongPressTypeAccentedCharacterAsync',
228                       testDoneCallback);
229 }
230
231 /**
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.
234  */
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({
242       type: 'keydown',
243       charValue: unicodeValue,
244       keyCode: 0x41,
245       modifiers: Modifier.NONE
246     });
247     send.addExpectation({
248       type: 'keyup',
249       charValue: unicodeValue,
250       keyCode: 0x41,
251       modifiers: Modifier.NONE
252     });
253     var mockEvent = {pointerId:2};
254     key.down(mockEvent);
255     mockTypeCharacter('s', 0x53, Modifier.NONE);
256   };
257   onKeyboardReady('testAutoReleasePreviousKey', runTest, testDoneCallback);
258 }
259
260 /**
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
263  * dropped.
264  */
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;
271
272     // Test finger moves out of typed key slightly before release. The key
273     // should not be dropped.
274     send.addExpectation({
275       type: 'keydown',
276       charValue: unicodeValue,
277       keyCode: 0x41,
278       modifiers: Modifier.NONE
279     });
280     send.addExpectation({
281       type: 'keyup',
282       charValue: unicodeValue,
283       keyCode: 0x41,
284       modifiers: Modifier.NONE
285     });
286     var mockEvent = { pointerId:2 };
287     key.down(mockEvent);
288     key.out(mockEvent);
289     // Mocks finger releases after moved out of the 'a' key.
290     $('keyboard').up(mockEvent);
291
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
294     // be dropped.
295     send.addExpectation({
296       type: 'keydown',
297       charValue: unicodeValue,
298       keyCode: 0x41,
299       modifiers: Modifier.NONE
300     });
301     send.addExpectation({
302       type: 'keyup',
303       charValue: unicodeValue,
304       keyCode: 0x41,
305       modifiers: Modifier.NONE
306     });
307     key.down(mockEvent);
308     key.out(mockEvent);
309     mockTypeCharacter('s', 0x53, Modifier.NONE);
310   };
311   onKeyboardReady('testFingerOutType', runTest, testDoneCallback);
312 }
313
314 /**
315  * Tests that flicking upwards on a key with hintText types the hint text.
316  * @param {Function} testDoneCallback The callback function on completion.
317  */
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();
322     return {
323       pointerId: 1,
324       isPrimary: true,
325       screenX: bounds.left + xOffset,
326       // Note: Y is negative in the 'up' direction.
327       screenY: bounds.bottom - yOffset,
328       target: target,
329       relatedTarget: relatedTarget
330     };
331   }
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({
337       type: 'keydown',
338       charValue: '?'.charCodeAt(0),
339       keyCode: 0xBF,
340       modifiers: Modifier.SHIFT
341     });
342     send.addExpectation({
343       type: 'keyup',
344       charValue: '?'.charCodeAt(0),
345       keyCode: 0xBF,
346       modifiers: Modifier.SHIFT
347     });
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));
353
354     // Test flick that exits the keyboard area. Expect '1' to appear.
355     var qKey = findKey('q');
356     send.addExpectation({
357       type: 'keydown',
358       charValue: '1'.charCodeAt(0),
359       keyCode: 0x31,
360       modifiers: Modifier.NONE
361     });
362     send.addExpectation({
363       type: 'keyup',
364       charValue: '1'.charCodeAt(0),
365       keyCode: 0x31,
366       modifiers: Modifier.NONE
367     });
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')));
371
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));
377
378     // Test flick that crosses the original key boundary.
379     send.addExpectation({
380       type: 'keydown',
381       charValue: '?'.charCodeAt(0),
382       keyCode: 0xBF,
383       modifiers: Modifier.SHIFT
384     });
385     send.addExpectation({
386       type: 'keyup',
387       charValue: '?'.charCodeAt(0),
388       keyCode: 0xBF,
389       modifiers: Modifier.SHIFT
390     });
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));
397
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));
404
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));
413   };
414   onKeyboardReady('testSwipeFlick', runTest, testDoneCallback);
415 }