blob: 16b115c3ac3ebc045e8009902c14c0a2c48bb81d [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 Scandolo812aa5a2016-04-19 18:12:45 -070020xdescribe('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, [
Simon Hunt639dc662015-02-18 14:19:20 -080054 'bindQhs', 'installOn', 'keyBindings', 'gestureNotes', 'enableKeys'
Simon Hunt36fc15c2015-02-12 17:02:58 -080055 ])).toBeTruthy();
56 });
57
Bri Prebilic Coleef091902015-04-28 16:53:47 -070058 // This no longer works because 'initKeyboardEvent' has been depreciated.
59 // Now there is a constructor for 'KeyboardEvent' where you can modify
60 // the new event with a dictionary(?) 'KeyboardEventInit'.
61 // However, the below code has been so recently depreciated, there are no
62 // examples online of how to use the new interface, and some browsers
63 // don't support it still. These tests will have to be put off for a
64 // while more. (Investigated 4/28/15)
65 // Also tried was Angular's triggerHandler() function, but it doesn't seem
66 // that it can take arguments about the event.
67 // Using jQuery in tests might be a good idea, for triggering test events.
Simon Hunt420691a2014-12-16 20:16:28 -080068 function jsKeyDown(element, code) {
69 var ev = document.createEvent('KeyboardEvent');
70
71 // Chromium Hack
72 if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
73 Object.defineProperty(ev, 'keyCode', {
74 get: function () { return this.keyCodeVal; }
75 });
76 Object.defineProperty(ev, 'which', {
77 get: function () { return this.keyCodeVal; }
78 });
79 }
80
81 if (ev.initKeyboardEvent) {
82 ev.initKeyboardEvent('keydown', true, true, document.defaultView,
83 false, false, false, false, code, code);
84 } else {
85 ev.initKeyEvent('keydown', true, true, document.defaultView,
86 false, false, false, false, code, 0);
87 }
88
89 ev.keyCodeVal = code;
90
91 if (ev.keyCode !== code) {
92 console.warn("keyCode mismatch " + ev.keyCode +
93 "(" + ev.which + ") -> "+ code);
94 }
95 element.dispatchEvent(ev);
96 }
97
Simon Hunt59df0b22014-12-17 10:32:25 -080098 // === Key binding related tests
99 it('should start with default key bindings', function () {
100 var state = ks.keyBindings(),
101 gk = state.globalKeys,
102 mk = state.maskedKeys,
103 vk = state.viewKeys,
104 vf = state.viewFunction;
105
106 expect(gk.length).toEqual(4);
107 ['backSlash', 'slash', 'esc', 'T'].forEach(function (k) {
108 expect(fs.contains(gk, k)).toBeTruthy();
109 });
110
111 expect(mk.length).toEqual(3);
112 ['backSlash', 'slash', 'T'].forEach(function (k) {
113 expect(fs.contains(mk, k)).toBeTruthy();
114 });
115
116 expect(vk.length).toEqual(0);
117 expect(vf).toBeFalsy();
Simon Hunt420691a2014-12-16 20:16:28 -0800118 });
Simon Hunt59df0b22014-12-17 10:32:25 -0800119
120 function bindTestKeys(withDescs) {
121 var keys = ['A', '1', 'F5', 'equals'],
122 kb = {};
123
124 function cb(view, key, code, ev) {
125 last.view = view;
126 last.key = key;
127 last.code = code;
128 last.ev = ev;
129 }
130
131 function bind(k) {
132 return withDescs ? [cb, 'desc for key ' + k] : cb;
133 }
134
135 keys.forEach(function (k) {
136 kb[k] = bind(k);
137 });
138
139 ks.keyBindings(kb);
140 }
141
142 function verifyCall(key, code) {
143 // TODO: update expectation, when view tokens are implemented
144 expect(last.view).toEqual('NotYetAViewToken');
145 last.view = null;
146
147 expect(last.key).toEqual(key);
148 last.key = null;
149
150 expect(last.code).toEqual(code);
151 last.code = null;
152
153 expect(last.ev).toBeTruthy();
154 last.ev = null;
155 }
156
157 function verifyNoCall() {
158 expect(last.view).toBeNull();
159 expect(last.key).toBeNull();
160 expect(last.code).toBeNull();
161 expect(last.ev).toBeNull();
162 }
163
164 function verifyTestKeys() {
165 jsKeyDown(elem, 65); // 'A'
166 verifyCall('A', 65);
167 jsKeyDown(elem, 66); // 'B'
168 verifyNoCall();
169
170 jsKeyDown(elem, 49); // '1'
171 verifyCall('1', 49);
172 jsKeyDown(elem, 50); // '2'
173 verifyNoCall();
174
175 jsKeyDown(elem, 116); // 'F5'
176 verifyCall('F5', 116);
177 jsKeyDown(elem, 117); // 'F6'
178 verifyNoCall();
179
180 jsKeyDown(elem, 187); // 'equals'
181 verifyCall('equals', 187);
182 jsKeyDown(elem, 189); // 'dash'
183 verifyNoCall();
184
185 var vk = ks.keyBindings().viewKeys;
186
187 expect(vk.length).toEqual(4);
188 ['A', '1', 'F5', 'equals'].forEach(function (k) {
189 expect(fs.contains(vk, k)).toBeTruthy();
190 });
191
192 expect(ks.keyBindings().viewFunction).toBeFalsy();
193 }
194
Bri Prebilic Coleef091902015-04-28 16:53:47 -0700195 // TODO: jsKeyDown(...) no longer emulates key presses ?! :(
Simon Hunt2d16fc82015-03-10 20:19:52 -0700196 // The following four unit tests ignored until we can figure this out.
Bri Prebilic Coleef091902015-04-28 16:53:47 -0700197 // INVESTIGATED: see jsKeyDown for details...
Simon Hunt2d16fc82015-03-10 20:19:52 -0700198
199 xit('should allow specific key bindings', function () {
Simon Hunt59df0b22014-12-17 10:32:25 -0800200 bindTestKeys();
201 verifyTestKeys();
Simon Hunt420691a2014-12-16 20:16:28 -0800202 });
Simon Hunt59df0b22014-12-17 10:32:25 -0800203
Simon Hunt2d16fc82015-03-10 20:19:52 -0700204 xit('should allow specific key bindings with descriptions', function () {
Simon Hunt59df0b22014-12-17 10:32:25 -0800205 bindTestKeys(true);
206 verifyTestKeys();
Simon Hunt420691a2014-12-16 20:16:28 -0800207 });
208
Simon Hunt2d16fc82015-03-10 20:19:52 -0700209 xit('should warn about masked keys', function () {
Simon Huntaf322072014-12-18 13:23:40 -0800210 var k = {'space': cb, 'T': cb},
211 count = 0;
Simon Hunt7aeffa02014-12-18 14:58:26 -0800212
Simon Huntdc6362a2014-12-18 19:55:23 -0800213 function cb(token, key, code, ev) {
214 count++;
215 //console.debug('count = ' + count, token, key, code);
216 }
Simon Huntaf322072014-12-18 13:23:40 -0800217
Simon Hunt7aeffa02014-12-18 14:58:26 -0800218 spyOn($log, 'warn');
219
Simon Huntaf322072014-12-18 13:23:40 -0800220 ks.keyBindings(k);
221
Simon Hunt7aeffa02014-12-18 14:58:26 -0800222 expect($log.warn).toHaveBeenCalledWith('setKeyBindings(): Key "T" is reserved');
Simon Huntaf322072014-12-18 13:23:40 -0800223
224 // the 'T' key should NOT invoke our callback
225 expect(count).toEqual(0);
226 jsKeyDown(elem, 84); // 'T'
227 expect(count).toEqual(0);
228
229 // but the 'space' key SHOULD invoke our callback
230 jsKeyDown(elem, 32); // 'space'
231 expect(count).toEqual(1);
232 });
233
Simon Hunt2d16fc82015-03-10 20:19:52 -0700234 xit('should block keys when disabled', function () {
Simon Hunt36fc15c2015-02-12 17:02:58 -0800235 var cbCount = 0;
236
237 function cb() { cbCount++; }
238
239 function pressA() { jsKeyDown(elem, 65); } // 65 == 'A' keycode
240
241 ks.keyBindings({ A: cb });
242
243 expect(cbCount).toBe(0);
244
245 pressA();
246 expect(cbCount).toBe(1);
247
248 ks.enableKeys(false);
249 pressA();
250 expect(cbCount).toBe(1);
251
252 ks.enableKeys(true);
253 pressA();
254 expect(cbCount).toBe(2);
255 });
256
Simon Huntaf322072014-12-18 13:23:40 -0800257 // === Gesture notes related tests
258 it('should start with no notes', function () {
259 expect(ks.gestureNotes()).toEqual([]);
260 });
261
262 it('should allow us to add nodes', function () {
263 var notes = [
264 ['one', 'something about one'],
265 ['two', 'description of two']
266 ];
267 ks.gestureNotes(notes);
268
269 expect(ks.gestureNotes()).toEqual(notes);
270 });
271
272 it('should ignore non-arrays', function () {
273 ks.gestureNotes({foo:4});
274 expect(ks.gestureNotes()).toEqual([]);
275 });
276
277 // Consider adding test to ensure array contains 2-tuples of strings
Simon Hunt420691a2014-12-16 20:16:28 -0800278});