blob: dfae70f5d522037ad6769858636ec466e4574a36 [file] [log] [blame]
Simon Hunt420691a2014-12-16 20:16:28 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Simon Hunt420691a2014-12-16 20:16:28 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- Key Handler Service - Unit Tests
Simon Hunt420691a2014-12-16 20:16:28 -080019 */
Matteo Scandolo209c6c62016-05-21 10:08:57 -070020describe('factory: fw/util/keys.js', function() {
Simon Hunt639dc662015-02-18 14:19:20 -080021 var $log, ks, fs, qhs,
Simon Hunt7aeffa02014-12-18 14:58:26 -080022 d3Elem, elem, last;
Simon Huntdc6362a2014-12-18 19:55:23 -080023
Simon Hunt420691a2014-12-16 20:16:28 -080024
Matteo Scandolo812aa5a2016-04-19 18:12:45 -070025 beforeEach(module('onosUtil', 'onosSvg', 'onosLayer', 'onosNav', 'onosRemote'));
Simon Hunt420691a2014-12-16 20:16:28 -080026
Simon Hunt639dc662015-02-18 14:19:20 -080027 beforeEach(inject(function (_$log_, KeyService, FnService, QuickHelpService) {
Simon Hunt7aeffa02014-12-18 14:58:26 -080028 $log = _$log_;
Simon Hunt420691a2014-12-16 20:16:28 -080029 ks = KeyService;
30 fs = FnService;
Simon Hunt639dc662015-02-18 14:19:20 -080031 qhs = QuickHelpService;
Simon Hunt420691a2014-12-16 20:16:28 -080032 d3Elem = d3.select('body').append('p').attr('id', 'ptest');
Simon Hunt59df0b22014-12-17 10:32:25 -080033 elem = d3Elem.node();
Simon Hunt420691a2014-12-16 20:16:28 -080034 ks.installOn(d3Elem);
Simon Hunt639dc662015-02-18 14:19:20 -080035 ks.bindQhs(qhs);
Simon Hunt59df0b22014-12-17 10:32:25 -080036 last = {
37 view: null,
38 key: null,
39 code: null,
40 ev: null
41 };
Simon Hunt420691a2014-12-16 20:16:28 -080042 }));
43
44 afterEach(function () {
45 d3.select('#ptest').remove();
46 });
47
Simon Hunt36fc15c2015-02-12 17:02:58 -080048 it('should define the key service', function () {
49 expect(ks).toBeDefined();
50 });
51
52 it('should define api functions', function () {
53 expect(fs.areFunctions(ks, [
Matteo Scandolo209c6c62016-05-21 10:08:57 -070054 'bindQhs', 'installOn', 'keyBindings', 'unbindKeys', 'dialogKeys',
55 'addSeq', 'remSeq', 'gestureNotes', 'enableKeys', 'enableGlobalKeys', 'checkNotGlobal'
Simon Hunt36fc15c2015-02-12 17:02:58 -080056 ])).toBeTruthy();
57 });
58
Bri Prebilic Coleef091902015-04-28 16:53:47 -070059 // This no longer works because 'initKeyboardEvent' has been depreciated.
60 // Now there is a constructor for 'KeyboardEvent' where you can modify
61 // the new event with a dictionary(?) 'KeyboardEventInit'.
62 // However, the below code has been so recently depreciated, there are no
63 // examples online of how to use the new interface, and some browsers
64 // don't support it still. These tests will have to be put off for a
65 // while more. (Investigated 4/28/15)
66 // Also tried was Angular's triggerHandler() function, but it doesn't seem
67 // that it can take arguments about the event.
68 // Using jQuery in tests might be a good idea, for triggering test events.
Simon Hunt420691a2014-12-16 20:16:28 -080069 function jsKeyDown(element, code) {
70 var ev = document.createEvent('KeyboardEvent');
71
72 // Chromium Hack
73 if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
74 Object.defineProperty(ev, 'keyCode', {
75 get: function () { return this.keyCodeVal; }
76 });
77 Object.defineProperty(ev, 'which', {
78 get: function () { return this.keyCodeVal; }
79 });
80 }
81
82 if (ev.initKeyboardEvent) {
83 ev.initKeyboardEvent('keydown', true, true, document.defaultView,
84 false, false, false, false, code, code);
85 } else {
86 ev.initKeyEvent('keydown', true, true, document.defaultView,
87 false, false, false, false, code, 0);
88 }
89
90 ev.keyCodeVal = code;
91
92 if (ev.keyCode !== code) {
93 console.warn("keyCode mismatch " + ev.keyCode +
94 "(" + ev.which + ") -> "+ code);
95 }
96 element.dispatchEvent(ev);
97 }
98
Simon Hunt59df0b22014-12-17 10:32:25 -080099 // === Key binding related tests
100 it('should start with default key bindings', function () {
101 var state = ks.keyBindings(),
102 gk = state.globalKeys,
103 mk = state.maskedKeys,
104 vk = state.viewKeys,
105 vf = state.viewFunction;
106
107 expect(gk.length).toEqual(4);
108 ['backSlash', 'slash', 'esc', 'T'].forEach(function (k) {
109 expect(fs.contains(gk, k)).toBeTruthy();
110 });
111
112 expect(mk.length).toEqual(3);
113 ['backSlash', 'slash', 'T'].forEach(function (k) {
114 expect(fs.contains(mk, k)).toBeTruthy();
115 });
116
117 expect(vk.length).toEqual(0);
118 expect(vf).toBeFalsy();
Simon Hunt420691a2014-12-16 20:16:28 -0800119 });
Simon Hunt59df0b22014-12-17 10:32:25 -0800120
121 function bindTestKeys(withDescs) {
122 var keys = ['A', '1', 'F5', 'equals'],
123 kb = {};
124
125 function cb(view, key, code, ev) {
126 last.view = view;
127 last.key = key;
128 last.code = code;
129 last.ev = ev;
130 }
131
132 function bind(k) {
133 return withDescs ? [cb, 'desc for key ' + k] : cb;
134 }
135
136 keys.forEach(function (k) {
137 kb[k] = bind(k);
138 });
139
140 ks.keyBindings(kb);
141 }
142
143 function verifyCall(key, code) {
144 // TODO: update expectation, when view tokens are implemented
145 expect(last.view).toEqual('NotYetAViewToken');
146 last.view = null;
147
148 expect(last.key).toEqual(key);
149 last.key = null;
150
151 expect(last.code).toEqual(code);
152 last.code = null;
153
154 expect(last.ev).toBeTruthy();
155 last.ev = null;
156 }
157
158 function verifyNoCall() {
159 expect(last.view).toBeNull();
160 expect(last.key).toBeNull();
161 expect(last.code).toBeNull();
162 expect(last.ev).toBeNull();
163 }
164
165 function verifyTestKeys() {
166 jsKeyDown(elem, 65); // 'A'
167 verifyCall('A', 65);
168 jsKeyDown(elem, 66); // 'B'
169 verifyNoCall();
170
171 jsKeyDown(elem, 49); // '1'
172 verifyCall('1', 49);
173 jsKeyDown(elem, 50); // '2'
174 verifyNoCall();
175
176 jsKeyDown(elem, 116); // 'F5'
177 verifyCall('F5', 116);
178 jsKeyDown(elem, 117); // 'F6'
179 verifyNoCall();
180
181 jsKeyDown(elem, 187); // 'equals'
182 verifyCall('equals', 187);
183 jsKeyDown(elem, 189); // 'dash'
184 verifyNoCall();
185
186 var vk = ks.keyBindings().viewKeys;
187
188 expect(vk.length).toEqual(4);
189 ['A', '1', 'F5', 'equals'].forEach(function (k) {
190 expect(fs.contains(vk, k)).toBeTruthy();
191 });
192
193 expect(ks.keyBindings().viewFunction).toBeFalsy();
194 }
195
Bri Prebilic Coleef091902015-04-28 16:53:47 -0700196 // TODO: jsKeyDown(...) no longer emulates key presses ?! :(
Simon Hunt2d16fc82015-03-10 20:19:52 -0700197 // The following four unit tests ignored until we can figure this out.
Bri Prebilic Coleef091902015-04-28 16:53:47 -0700198 // INVESTIGATED: see jsKeyDown for details...
Simon Hunt2d16fc82015-03-10 20:19:52 -0700199
200 xit('should allow specific key bindings', function () {
Simon Hunt59df0b22014-12-17 10:32:25 -0800201 bindTestKeys();
202 verifyTestKeys();
Simon Hunt420691a2014-12-16 20:16:28 -0800203 });
Simon Hunt59df0b22014-12-17 10:32:25 -0800204
Simon Hunt2d16fc82015-03-10 20:19:52 -0700205 xit('should allow specific key bindings with descriptions', function () {
Simon Hunt59df0b22014-12-17 10:32:25 -0800206 bindTestKeys(true);
207 verifyTestKeys();
Simon Hunt420691a2014-12-16 20:16:28 -0800208 });
209
Simon Hunt2d16fc82015-03-10 20:19:52 -0700210 xit('should warn about masked keys', function () {
Simon Huntaf322072014-12-18 13:23:40 -0800211 var k = {'space': cb, 'T': cb},
212 count = 0;
Simon Hunt7aeffa02014-12-18 14:58:26 -0800213
Simon Huntdc6362a2014-12-18 19:55:23 -0800214 function cb(token, key, code, ev) {
215 count++;
216 //console.debug('count = ' + count, token, key, code);
217 }
Simon Huntaf322072014-12-18 13:23:40 -0800218
Simon Hunt7aeffa02014-12-18 14:58:26 -0800219 spyOn($log, 'warn');
220
Simon Huntaf322072014-12-18 13:23:40 -0800221 ks.keyBindings(k);
222
Simon Hunt7aeffa02014-12-18 14:58:26 -0800223 expect($log.warn).toHaveBeenCalledWith('setKeyBindings(): Key "T" is reserved');
Simon Huntaf322072014-12-18 13:23:40 -0800224
225 // the 'T' key should NOT invoke our callback
226 expect(count).toEqual(0);
227 jsKeyDown(elem, 84); // 'T'
228 expect(count).toEqual(0);
229
230 // but the 'space' key SHOULD invoke our callback
231 jsKeyDown(elem, 32); // 'space'
232 expect(count).toEqual(1);
233 });
234
Simon Hunt2d16fc82015-03-10 20:19:52 -0700235 xit('should block keys when disabled', function () {
Simon Hunt36fc15c2015-02-12 17:02:58 -0800236 var cbCount = 0;
237
238 function cb() { cbCount++; }
239
240 function pressA() { jsKeyDown(elem, 65); } // 65 == 'A' keycode
241
242 ks.keyBindings({ A: cb });
243
244 expect(cbCount).toBe(0);
245
246 pressA();
247 expect(cbCount).toBe(1);
248
249 ks.enableKeys(false);
250 pressA();
251 expect(cbCount).toBe(1);
252
253 ks.enableKeys(true);
254 pressA();
255 expect(cbCount).toBe(2);
256 });
257
Simon Huntaf322072014-12-18 13:23:40 -0800258 // === Gesture notes related tests
259 it('should start with no notes', function () {
260 expect(ks.gestureNotes()).toEqual([]);
261 });
262
263 it('should allow us to add nodes', function () {
264 var notes = [
265 ['one', 'something about one'],
266 ['two', 'description of two']
267 ];
268 ks.gestureNotes(notes);
269
270 expect(ks.gestureNotes()).toEqual(notes);
271 });
272
273 it('should ignore non-arrays', function () {
274 ks.gestureNotes({foo:4});
275 expect(ks.gestureNotes()).toEqual([]);
276 });
277
278 // Consider adding test to ensure array contains 2-tuples of strings
Simon Hunt420691a2014-12-16 20:16:28 -0800279});