Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 var mockController; | 7 var mockController; |
| 8 var mockTimer; | 8 var mockTimer; |
| 9 var setComposition; | 9 var setComposition; |
| 10 var realSetTimeout; | |
| 10 | 11 |
| 11 var DEFAULT_CONTEXT_ID = 1; | 12 var DEFAULT_CONTEXT_ID = 1; |
| 13 var LONGPRESS_DELAY = 1100; | |
| 12 | 14 |
| 13 /** | 15 /** |
| 14 * Create mocks for the virtualKeyboardPrivate API. Any tests that trigger API | 16 * Create mocks for the virtualKeyboardPrivate API. Any tests that trigger API |
| 15 * calls must set expectations for call signatures. | 17 * calls must set expectations for call signatures. |
| 16 */ | 18 */ |
| 17 function setUp() { | 19 function setUp() { |
| 20 realSetTimeout = setTimeout; | |
|
bshe
2014/06/03 11:35:26
nit: window.setTimeout
rsadam
2014/06/03 13:41:57
Done.
| |
| 18 mockController = new MockController(); | 21 mockController = new MockController(); |
| 19 mockTimer = new MockTimer(); | 22 mockTimer = new MockTimer(); |
| 20 mockTimer.install(); | 23 mockTimer.install(); |
| 21 | 24 |
| 22 mockController.createFunctionMock(chrome.input.ime, 'commitText'); | 25 mockController.createFunctionMock(chrome.input.ime, 'commitText'); |
| 23 var validateCommit = function(index, expected, observed) { | 26 var validateCommit = function(index, expected, observed) { |
| 24 // Only consider the first argument, the details object. | 27 // Only consider the first argument, the details object. |
| 25 var expectedEvent = expected[0]; | 28 var expectedEvent = expected[0]; |
| 26 var observedEvent = observed[0]; | 29 var observedEvent = observed[0]; |
| 27 assertEquals(expectedEvent.text, | 30 assertEquals(expectedEvent.text, |
| 28 observedEvent.text, | 31 observedEvent.text, |
| 29 'Mismatched commit text.'); | 32 'Mismatched commit text.'); |
| 30 }; | 33 }; |
| 31 chrome.input.ime.commitText.validateCall = validateCommit; | 34 chrome.input.ime.commitText.validateCall = validateCommit; |
| 32 | 35 |
| 33 setComposition = chrome.input.ime.setComposition; | 36 setComposition = chrome.input.ime.setComposition; |
| 34 // Mocks setComposition manually to immediately callback. The mock controller | 37 // Mocks setComposition manually to immediately callback. The mock controller |
| 35 // does not support callback functions. | 38 // does not support callback functions. |
| 36 chrome.input.ime.setComposition = function(obj, callback) { | 39 chrome.input.ime.setComposition = function(obj, callback) { |
| 37 callback(); | 40 callback(); |
| 38 } | 41 } |
| 39 window.setContext({'contextID': DEFAULT_CONTEXT_ID, 'type': 'text'}); | 42 window.setContext({'contextID': DEFAULT_CONTEXT_ID, 'type': 'text'}); |
| 40 // TODO(rsadam): Mock additional extension API calls as required. | 43 // TODO(rsadam): Mock additional extension API calls as required. |
| 41 } | 44 } |
| 42 | 45 |
| 46 function RunTest(testFn, testDoneCallback) { | |
| 47 var pollTillReady = function() { | |
| 48 if (window.isKeyboardReady()) { | |
| 49 testFn(); | |
| 50 testDoneCallback(); | |
| 51 } else | |
| 52 realSetTimeout(pollTillReady, 100); | |
| 53 } | |
| 54 pollTillReady(); | |
| 55 } | |
| 56 | |
| 43 /** | 57 /** |
| 44 * Verify that API calls match expectations. | 58 * Verify that API calls match expectations. |
| 45 */ | 59 */ |
| 46 function tearDown() { | 60 function tearDown() { |
| 47 mockController.verifyMocks(); | 61 mockController.verifyMocks(); |
| 48 mockController.reset(); | 62 mockController.reset(); |
| 49 mockTimer.uninstall(); | 63 mockTimer.uninstall(); |
| 50 chrome.input.ime.setComposition = setComposition; | 64 chrome.input.ime.setComposition = setComposition; |
| 51 } | 65 } |
| 52 | 66 |
| 53 /** | 67 /** |
| 54 * Checks whether the element is currently being displayed on screen. | 68 * Checks whether the element is currently being displayed on screen. |
| 55 * @param {Object} The object to check. | 69 * @param {Object} The object to check. |
| 56 * @return {boolean} | 70 * @return {boolean} |
| 57 */ | 71 */ |
| 58 function isActive(el) { | 72 function isActive(el) { |
| 59 return window.getComputedStyle(el).display != "none"; | 73 return window.getComputedStyle(el).display != "none"; |
| 60 } | 74 } |
| 61 | 75 |
| 62 (function(exports) { | 76 (function(exports) { |
| 63 | 77 |
| 64 /** | 78 /** |
| 65 * Map from keys to layout specific key ids. This only contains a small subset | 79 * Map from keys to layout specific key ids. This only contains a small subset |
| 66 * of the keys which are used in testing. The ids are based on the XKB layouts | 80 * of the keys which are used in testing. The ids are based on the XKB layouts |
| 67 * in GoogleKeyboardInput-xkb.crx. | 81 * in GoogleKeyboardInput-xkb.crx. Ids that start with a number are escaped |
| 82 * so that document.querySelector returns the correct element. | |
| 68 */ | 83 */ |
| 69 var KEY_IDS = { | 84 var KEY_IDS = { |
| 70 'a' : { | 85 'a' : { |
| 71 'us' : '101kbd-k-29', | 86 'us' : '#\\31 01kbd-k-29', |
| 72 'us.compact' : 'compactkbd-k-key-10', | 87 'us.compact.qwerty' : '#compactkbd-k-key-11', |
| 73 }, | 88 }, |
| 74 'c' : { | 89 'c' : { |
| 75 'us' : '101kbd-k-44', | 90 'us' : '#\\31 01kbd-k-44', |
| 76 'us.compact' : 'compactkbd-k-key-21', | 91 'us.compact.qwerty' : '#compactkbd-k-key-24', |
| 77 | 92 |
| 78 }, | 93 }, |
| 79 'd' : { | 94 'd' : { |
| 80 'us' : '101kbd-k-31', | 95 'us' : '#\\31 01kbd-k-31', |
| 81 'us.compact' : 'compactkbd-k-key-12', | 96 'us.compact.qwerty' : '#compactkbd-k-key-13', |
| 82 | 97 |
| 83 }, | 98 }, |
| 99 'e' : { | |
| 100 'us' : '#\\31 01kbd-k-43', | |
| 101 'us.compact.qwerty': '#compactkbd-k-key-2', | |
| 102 }, | |
| 84 'l' : { | 103 'l' : { |
| 85 'us' : '101kbd-k-37', | 104 'us' : '#\\31 01kbd-k-37', |
| 86 'us.compact' : 'compactkbd-k-key-18', | 105 'us.compact.qwerty' : '#compactkbd-k-key-19', |
| 87 | 106 |
| 88 }, | 107 }, |
| 89 'p' : { | 108 'p' : { |
| 90 'us' : '101kbd-k-24', | 109 'us' : '#\\31 01kbd-k-24', |
| 91 'us.compact' : 'compactkbd-k-key-9', | 110 'us.compact.qwerty' : '#compactkbd-k-key-9', |
| 92 }, | 111 }, |
| 93 'leftshift' : { | 112 'leftshift' : { |
| 94 'us' : '101kbd-k-41', | 113 'us' : '#\\31 01kbd-k-41', |
| 95 'us.compact' : 'compactkbd-k-21', | 114 'us.compact.qwerty' : '#compactkbd-k-21', |
| 96 }, | 115 }, |
| 97 "capslock" : { | 116 "capslock" : { |
| 98 'us' : '101kbd-k-28', | 117 'us' : '#\\31 01kbd-k-28', |
| 99 } | 118 } |
| 100 }; | 119 }; |
| 101 | 120 |
| 102 /** | 121 /** |
| 103 * Gets the key id of the specified character. | 122 * Gets the key id of the specified character. |
| 104 * @param {string} layout The current keyboard layout. | 123 * @param {string} layout The current keyboard layout. |
| 105 * @param {char} char The character to press. | 124 * @param {char} char The character to press. |
| 106 */ | 125 */ |
| 107 var getKeyId_ = function(layout, char) { | 126 var getKeyId_ = function(layout, char) { |
| 108 var lower = char.toLowerCase(); | 127 var lower = char.toLowerCase(); |
| 109 assertTrue(!!KEY_IDS[lower], "Cannot find cached key id: " + char); | 128 assertTrue(!!KEY_IDS[lower], "Cannot find cached key id: " + char); |
| 110 assertTrue(!!KEY_IDS[lower][layout], | 129 assertTrue(!!KEY_IDS[lower][layout], |
| 111 "Cannot find cached key id: " + char + " in " + layout); | 130 "Cannot find cached key id: " + char + " in " + layout); |
| 112 return KEY_IDS[lower][layout]; | 131 return KEY_IDS[lower][layout]; |
| 113 } | 132 } |
| 114 | 133 |
| 115 /** | 134 /** |
| 116 * Returns the current layout id. | 135 * Returns the current layout id. |
| 117 * @return {string} | 136 * @return {string} |
| 118 */ | 137 */ |
| 119 var getLayoutId_ = function() { | 138 var getLayoutId_ = function() { |
| 120 // TODO(rsadam@): Generalize this. | 139 // TODO(rsadam@): Generalize this. |
| 121 var id = window.location.search.split("id=")[1]; | 140 var id = window.location.search.split("id=")[1]; |
| 122 assertTrue(!!id, "No layout found."); | 141 assertTrue(!!id, "No layout found."); |
| 123 return id; | 142 return id; |
| 124 } | 143 } |
| 125 | 144 |
| 126 /** | 145 /** |
| 146 * Returns the layout with the id provided. Periods in the id are replaced by | |
| 147 * hyphens. | |
| 148 * @param id {string} id The layout id. | |
| 149 * @return {object} | |
| 150 */ | |
| 151 | |
| 152 var getLayout_ = function(id) { | |
| 153 // Escape periods to hyphens. | |
| 154 var layoutId = id.replace(/\./g, '-'); | |
| 155 var layout = document.querySelector('#' + layoutId); | |
| 156 assertTrue(!!layout, "Cannot find layout with id: " + layoutId); | |
| 157 return layout; | |
| 158 } | |
| 159 | |
| 160 /** | |
| 127 * Returns the key object corresponding to the character. | 161 * Returns the key object corresponding to the character. |
| 128 * @return {string} char The character. | 162 * @return {string} char The character. |
| 129 */ | 163 */ |
| 130 var getKey_ = function(char) { | 164 var getKey_ = function(char) { |
| 131 var layoutId = getLayoutId(); | 165 var layoutId = getLayoutId(); |
| 132 var key = document.getElementById(getKeyId_(layoutId, char)); | 166 var layout = getLayout_(layoutId); |
| 133 assertTrue(!!key, "Key not present in layout: " + char); | 167 |
| 134 return key; | 168 // All keys in the layout that are in the target keys position. |
| 169 var candidates = layout.querySelectorAll(getKeyId_(layoutId, char)); | |
| 170 assertTrue(candidates.length > 0, "Cannot find key: " + char); | |
| 171 var visible = Array.prototype.filter.call(candidates, isActive); | |
| 172 assertEquals(1, visible.length, | |
| 173 "Expect exactly one visible key for char: " + char); | |
| 174 return visible[0]; | |
| 135 } | 175 } |
| 136 | 176 |
| 137 exports.getKey = getKey_; | 177 exports.getKey = getKey_; |
| 138 exports.getLayoutId = getLayoutId_; | 178 exports.getLayoutId = getLayoutId_; |
| 139 })(this); | 179 })(this); |
| 140 | 180 |
| 141 /** | 181 /** |
| 142 * Generates a mouse event and dispatches it on the target. | 182 * Generates a mouse event and dispatches it on the target. |
| 143 * @param target {Object} The target of the event. | 183 * @param target {Object} The target of the event. |
| 144 * @param type {String} The type of the mouse event. | 184 * @param type {String} The type of the mouse event. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 175 var key = getKey(char); | 215 var key = getKey(char); |
| 176 mockMouseTypeOnKey(key); | 216 mockMouseTypeOnKey(key); |
| 177 } | 217 } |
| 178 | 218 |
| 179 /** | 219 /** |
| 180 * Generates a touch event and dispatches it on the target. | 220 * Generates a touch event and dispatches it on the target. |
| 181 * @param target {Object} The target of the event. | 221 * @param target {Object} The target of the event. |
| 182 * @param type {String} The type of the touch event. | 222 * @param type {String} The type of the touch event. |
| 183 */ | 223 */ |
| 184 function generateTouchEvent(target, type) { | 224 function generateTouchEvent(target, type) { |
| 185 var e = document.createEvent('UIEvents'); | 225 // UIEvent does not allow mocking pageX pageY of the event, so we use the |
| 226 // parent Event class. | |
| 227 var e = document.createEvent('Event'); | |
| 186 e.initEvent(type, true, true); | 228 e.initEvent(type, true, true); |
| 229 var rect = target.getBoundingClientRect(); | |
| 230 e.pageX = rect.left; | |
| 231 e.pageY = rect.top; | |
| 187 target.dispatchEvent(e); | 232 target.dispatchEvent(e); |
| 188 } | 233 } |
| 189 | 234 |
| 190 /** | 235 /** |
| 191 * Mocks a character type using touch. | 236 * Mocks a character type using touch. |
| 192 * @param {String} char The expected character. | 237 * @param {String} char The expected character. |
| 193 */ | 238 */ |
| 194 function mockTouchType(char) { | 239 function mockTouchType(char) { |
| 195 var send = chrome.input.ime.commitText; | 240 var send = chrome.input.ime.commitText; |
| 196 send.addExpectation({ | 241 send.addExpectation({ |
| 197 contextId: DEFAULT_CONTEXT_ID, | 242 contextId: DEFAULT_CONTEXT_ID, |
| 198 text: char, | 243 text: char, |
| 199 }); | 244 }); |
| 200 var key = getKey(char); | 245 var key = getKey(char); |
| 201 generateTouchEvent(key, 'touchstart'); | 246 generateTouchEvent(key, 'touchstart'); |
| 202 generateTouchEvent(key, 'touchend'); | 247 generateTouchEvent(key, 'touchend'); |
| 203 } | 248 } |
| OLD | NEW |