2 * Copyright 2014 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.
11 var DEFAULT_CONTEXT_ID
= 1;
12 var LONGPRESS_DELAY
= 1100;
15 * The enumeration of message types. This should be kept in sync with the
26 * Create mocks for the virtualKeyboardPrivate API. Any tests that trigger API
27 * calls must set expectations for call signatures.
30 realSetTimeout
= window
.setTimeout
;
31 mockController
= new MockController();
32 mockTimer
= new MockTimer();
35 mockController
.createFunctionMock(chrome
.input
.ime
, 'commitText');
36 var validateCommit = function(index
, expected
, observed
) {
37 // Only consider the first argument, the details object.
38 var expectedEvent
= expected
[0];
39 var observedEvent
= observed
[0];
40 assertEquals(expectedEvent
.text
,
42 'Mismatched commit text.');
44 sendMessage
= chrome
.runtime
.sendMessage
;
45 chrome
.runtime
.sendMessage = function(msg
){
46 // Forward message to the mocked method.
47 if (msg
.type
== Type
.COMMIT_TEXT
)
48 chrome
.input
.ime
.commitText(msg
)
50 console
.error("Unknown message type: " + msg
.type
);
52 chrome
.input
.ime
.commitText
.validateCall
= validateCommit
;
55 function RunTest(testFn
, testDoneCallback
) {
56 var pollTillReady = function() {
57 if (window
.isKeyboardReady()) {
62 realSetTimeout(pollTillReady
, 100);
69 * Verify that API calls match expectations.
72 mockController
.verifyMocks();
73 mockController
.reset();
74 chrome
.runtime
.sendMessage
= sendMessage
;
75 mockTimer
.uninstall();
79 * Checks whether the element is currently being displayed on screen.
80 * @param {Object} The object to check.
83 function isActive(el
) {
84 return window
.getComputedStyle(el
).display
!= "none";
90 * Map from keys to layout specific key ids. This only contains a small subset
91 * of the keys which are used in testing. The ids are based on the XKB layouts
92 * in GoogleKeyboardInput-xkb.crx. Ids that start with a number are escaped
93 * so that document.querySelector returns the correct element.
97 'us' : '#\\31 01kbd-k-29',
98 'us.compact.qwerty' : '#compactkbd-k-key-11',
101 'us' : '#\\31 01kbd-k-44',
102 'us.compact.qwerty' : '#compactkbd-k-key-24',
105 'us' : '#\\31 01kbd-k-31',
106 'us.compact.qwerty' : '#compactkbd-k-key-13',
109 'us' : '#\\31 01kbd-k-17',
110 'us.compact.qwerty': '#compactkbd-k-key-2',
113 'us' : '#\\31 01kbd-k-37',
114 'us.compact.qwerty' : '#compactkbd-k-key-19',
117 'us' : '#\\31 01kbd-k-24',
118 'us.compact.qwerty' : '#compactkbd-k-key-9',
121 'us' : '#\\31 01kbd-k-41',
122 'us.compact.qwerty' : '#compactkbd-k-21',
125 'us' : '#\\31 01kbd-k-28',
130 * Gets the key id of the specified character.
131 * @param {string} layout The current keyboard layout.
132 * @param {char} char The character to press.
134 var getKeyId_ = function(layout
, char) {
135 var lower
= char.toLowerCase();
136 assertTrue(!!KEY_IDS
[lower
], "Cannot find cached key id: " + char);
137 assertTrue(!!KEY_IDS
[lower
][layout
],
138 "Cannot find cached key id: " + char + " in " + layout
);
139 return KEY_IDS
[lower
][layout
];
143 * Returns the current layout id.
146 var getLayoutId_ = function() {
147 // TODO(rsadam@): Generalize this.
148 var id
= window
.location
.search
.split("id=")[1];
149 assertTrue(!!id
, "No layout found.");
154 * Returns the layout with the id provided. Periods in the id are replaced by
156 * @param id {string} id The layout id.
160 var getLayout_ = function(id
) {
161 // Escape periods to hyphens.
162 var layoutId
= id
.replace(/\./g, '-');
163 var layout
= document
.querySelector('#' + layoutId
);
164 assertTrue(!!layout
, "Cannot find layout with id: " + layoutId
);
169 * Returns the layout with the id provided. Periods in the id are replaced by
171 * @param id {string} id The layout id.
175 var getLayout_ = function(id
) {
176 // Escape periods to hyphens.
177 var layoutId
= id
.replace(/\./g, '-');
178 var layout
= document
.querySelector('#' + layoutId
);
179 assertTrue(!!layout
, "Cannot find layout with id: " + layoutId
);
184 * Returns the key object corresponding to the character.
185 * @return {string} char The character.
187 var getKey_ = function(char) {
188 var layoutId
= getLayoutId();
189 var layout
= getLayout_(layoutId
);
191 // All keys in the layout that are in the target keys position.
192 var candidates
= layout
.querySelectorAll(getKeyId_(layoutId
, char));
193 assertTrue(candidates
.length
> 0, "Cannot find key: " + char);
194 var visible
= Array
.prototype.filter
.call(candidates
, isActive
);
196 assertEquals(1, visible
.length
,
197 "Expect exactly one visible key for char: " + char);
201 exports
.getKey
= getKey_
;
202 exports
.getLayoutId
= getLayoutId_
;
206 * Generates a mouse event and dispatches it on the target.
207 * @param target {Object} The target of the event.
208 * @param type {String} The type of the mouse event.
210 function generateMouseEvent(target
, type
) {
211 var e
= new MouseEvent(type
, {bubbles
:true, cancelable
:true});
212 target
.dispatchEvent(e
);
216 * Mocks a key type using the mouse.
217 * @param {Object} key The key to click on.
219 function mockMouseTypeOnKey(key
) {
220 generateMouseEvent(key
, 'mouseover');
221 generateMouseEvent(key
, 'mousedown');
222 generateMouseEvent(key
, 'mouseup');
223 generateMouseEvent(key
, 'click');
224 generateMouseEvent(key
, 'mouseover');
225 generateMouseEvent(key
, 'mouseout');
229 * Mocks a character type using the mouse. Expects the character will be
231 * @param {String} char The character to type.
233 function mockMouseType(char) {
234 var send
= chrome
.input
.ime
.commitText
;
235 send
.addExpectation({
236 contextId
: DEFAULT_CONTEXT_ID
,
239 var key
= getKey(char);
240 mockMouseTypeOnKey(key
);
244 * Generates a touch event and dispatches it on the target.
245 * @param target {Object} The target of the event.
246 * @param type {String} The type of the touch event.
248 function generateTouchEvent(target
, type
) {
249 // UIEvent does not allow mocking pageX pageY of the event, so we use the
250 // parent Event class.
251 var e
= document
.createEvent('Event');
252 e
.initEvent(type
, true, true);
253 var rect
= target
.getBoundingClientRect();
256 target
.dispatchEvent(e
);
260 * Mocks a character type using touch.
261 * @param {String} char The expected character.
263 function mockTouchType(char) {
264 var send
= chrome
.input
.ime
.commitText
;
265 send
.addExpectation({
266 contextId
: DEFAULT_CONTEXT_ID
,
269 var key
= getKey(char);
270 generateTouchEvent(key
, 'touchstart');
271 generateTouchEvent(key
, 'touchend');
275 * Returns, if present, the active alternate key container.
278 function getActiveAltContainer() {
279 // TODO(rsadam): Simplify once code refactor to remove unneeded containers is
281 var all
= document
.querySelectorAll('.inputview-altdata-view');
282 var filtered
= Array
.prototype.filter
.call(all
, isActive
);
283 assertTrue(filtered
.length
<= 1, "More than one active container.");
284 return filtered
.length
> 0 ? filtered
[0] : null;
288 * Mocks a character long press.
289 * @param {String} char The character to longpress.
290 * @param {Array<string>} altKeys the expected alt keys.
291 * @param {number} index The index of the alt key to select.
293 function mockLongpress(char, altKeys
, index
) {
294 var key
= getKey(char);
296 generateTouchEvent(key
, 'touchstart');
297 mockTimer
.tick(LONGPRESS_DELAY
);
299 var container
= getActiveAltContainer();
300 assertTrue(!!container
, "Cannot find active alt container.");
301 var options
= container
.querySelectorAll('.inputview-altdata-key');
302 assertEquals(altKeys
.length
, options
.length
,
303 "Unexpected number of alt keys.");
304 // Check all altKeys present and in order specified.
305 for (var i
= 0; i
< altKeys
.length
; i
++) {
306 assertEquals(altKeys
[i
], options
[i
].textContent
);
308 // Expect selection to be typed
309 var send
= chrome
.input
.ime
.commitText
;
310 send
.addExpectation({
311 contextId
: DEFAULT_CONTEXT_ID
,
312 text
: altKeys
[index
],
314 // TODO(rsadam:) Add support for touch move.
315 generateTouchEvent(key
, 'touchend', true, true)
316 assertFalse(isActive(container
), "Alt key container was not hidden.");