diff options
Diffstat (limited to 'framework/src/onos/web/gui/src/main/webapp/tests/app/fw/util/keys-spec.js')
-rw-r--r-- | framework/src/onos/web/gui/src/main/webapp/tests/app/fw/util/keys-spec.js | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/framework/src/onos/web/gui/src/main/webapp/tests/app/fw/util/keys-spec.js b/framework/src/onos/web/gui/src/main/webapp/tests/app/fw/util/keys-spec.js new file mode 100644 index 00000000..227d7904 --- /dev/null +++ b/framework/src/onos/web/gui/src/main/webapp/tests/app/fw/util/keys-spec.js @@ -0,0 +1,278 @@ +/* + * Copyright 2014,2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + ONOS GUI -- Key Handler Service - Unit Tests + */ +describe('factory: fw/util/keys.js', function() { + var $log, ks, fs, qhs, + d3Elem, elem, last; + + + beforeEach(module('onosUtil', 'onosSvg', 'onosLayer', 'onosNav')); + + beforeEach(inject(function (_$log_, KeyService, FnService, QuickHelpService) { + $log = _$log_; + ks = KeyService; + fs = FnService; + qhs = QuickHelpService; + d3Elem = d3.select('body').append('p').attr('id', 'ptest'); + elem = d3Elem.node(); + ks.installOn(d3Elem); + ks.bindQhs(qhs); + last = { + view: null, + key: null, + code: null, + ev: null + }; + })); + + afterEach(function () { + d3.select('#ptest').remove(); + }); + + it('should define the key service', function () { + expect(ks).toBeDefined(); + }); + + it('should define api functions', function () { + expect(fs.areFunctions(ks, [ + 'bindQhs', 'installOn', 'keyBindings', 'gestureNotes', 'enableKeys' + ])).toBeTruthy(); + }); + + // This no longer works because 'initKeyboardEvent' has been depreciated. + // Now there is a constructor for 'KeyboardEvent' where you can modify + // the new event with a dictionary(?) 'KeyboardEventInit'. + // However, the below code has been so recently depreciated, there are no + // examples online of how to use the new interface, and some browsers + // don't support it still. These tests will have to be put off for a + // while more. (Investigated 4/28/15) + // Also tried was Angular's triggerHandler() function, but it doesn't seem + // that it can take arguments about the event. + // Using jQuery in tests might be a good idea, for triggering test events. + function jsKeyDown(element, code) { + var ev = document.createEvent('KeyboardEvent'); + + // Chromium Hack + if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { + Object.defineProperty(ev, 'keyCode', { + get: function () { return this.keyCodeVal; } + }); + Object.defineProperty(ev, 'which', { + get: function () { return this.keyCodeVal; } + }); + } + + if (ev.initKeyboardEvent) { + ev.initKeyboardEvent('keydown', true, true, document.defaultView, + false, false, false, false, code, code); + } else { + ev.initKeyEvent('keydown', true, true, document.defaultView, + false, false, false, false, code, 0); + } + + ev.keyCodeVal = code; + + if (ev.keyCode !== code) { + console.warn("keyCode mismatch " + ev.keyCode + + "(" + ev.which + ") -> "+ code); + } + element.dispatchEvent(ev); + } + + // === Key binding related tests + it('should start with default key bindings', function () { + var state = ks.keyBindings(), + gk = state.globalKeys, + mk = state.maskedKeys, + vk = state.viewKeys, + vf = state.viewFunction; + + expect(gk.length).toEqual(4); + ['backSlash', 'slash', 'esc', 'T'].forEach(function (k) { + expect(fs.contains(gk, k)).toBeTruthy(); + }); + + expect(mk.length).toEqual(3); + ['backSlash', 'slash', 'T'].forEach(function (k) { + expect(fs.contains(mk, k)).toBeTruthy(); + }); + + expect(vk.length).toEqual(0); + expect(vf).toBeFalsy(); + }); + + function bindTestKeys(withDescs) { + var keys = ['A', '1', 'F5', 'equals'], + kb = {}; + + function cb(view, key, code, ev) { + last.view = view; + last.key = key; + last.code = code; + last.ev = ev; + } + + function bind(k) { + return withDescs ? [cb, 'desc for key ' + k] : cb; + } + + keys.forEach(function (k) { + kb[k] = bind(k); + }); + + ks.keyBindings(kb); + } + + function verifyCall(key, code) { + // TODO: update expectation, when view tokens are implemented + expect(last.view).toEqual('NotYetAViewToken'); + last.view = null; + + expect(last.key).toEqual(key); + last.key = null; + + expect(last.code).toEqual(code); + last.code = null; + + expect(last.ev).toBeTruthy(); + last.ev = null; + } + + function verifyNoCall() { + expect(last.view).toBeNull(); + expect(last.key).toBeNull(); + expect(last.code).toBeNull(); + expect(last.ev).toBeNull(); + } + + function verifyTestKeys() { + jsKeyDown(elem, 65); // 'A' + verifyCall('A', 65); + jsKeyDown(elem, 66); // 'B' + verifyNoCall(); + + jsKeyDown(elem, 49); // '1' + verifyCall('1', 49); + jsKeyDown(elem, 50); // '2' + verifyNoCall(); + + jsKeyDown(elem, 116); // 'F5' + verifyCall('F5', 116); + jsKeyDown(elem, 117); // 'F6' + verifyNoCall(); + + jsKeyDown(elem, 187); // 'equals' + verifyCall('equals', 187); + jsKeyDown(elem, 189); // 'dash' + verifyNoCall(); + + var vk = ks.keyBindings().viewKeys; + + expect(vk.length).toEqual(4); + ['A', '1', 'F5', 'equals'].forEach(function (k) { + expect(fs.contains(vk, k)).toBeTruthy(); + }); + + expect(ks.keyBindings().viewFunction).toBeFalsy(); + } + + // TODO: jsKeyDown(...) no longer emulates key presses ?! :( + // The following four unit tests ignored until we can figure this out. + // INVESTIGATED: see jsKeyDown for details... + + xit('should allow specific key bindings', function () { + bindTestKeys(); + verifyTestKeys(); + }); + + xit('should allow specific key bindings with descriptions', function () { + bindTestKeys(true); + verifyTestKeys(); + }); + + xit('should warn about masked keys', function () { + var k = {'space': cb, 'T': cb}, + count = 0; + + function cb(token, key, code, ev) { + count++; + //console.debug('count = ' + count, token, key, code); + } + + spyOn($log, 'warn'); + + ks.keyBindings(k); + + expect($log.warn).toHaveBeenCalledWith('setKeyBindings(): Key "T" is reserved'); + + // the 'T' key should NOT invoke our callback + expect(count).toEqual(0); + jsKeyDown(elem, 84); // 'T' + expect(count).toEqual(0); + + // but the 'space' key SHOULD invoke our callback + jsKeyDown(elem, 32); // 'space' + expect(count).toEqual(1); + }); + + xit('should block keys when disabled', function () { + var cbCount = 0; + + function cb() { cbCount++; } + + function pressA() { jsKeyDown(elem, 65); } // 65 == 'A' keycode + + ks.keyBindings({ A: cb }); + + expect(cbCount).toBe(0); + + pressA(); + expect(cbCount).toBe(1); + + ks.enableKeys(false); + pressA(); + expect(cbCount).toBe(1); + + ks.enableKeys(true); + pressA(); + expect(cbCount).toBe(2); + }); + + // === Gesture notes related tests + it('should start with no notes', function () { + expect(ks.gestureNotes()).toEqual([]); + }); + + it('should allow us to add nodes', function () { + var notes = [ + ['one', 'something about one'], + ['two', 'description of two'] + ]; + ks.gestureNotes(notes); + + expect(ks.gestureNotes()).toEqual(notes); + }); + + it('should ignore non-arrays', function () { + ks.gestureNotes({foo:4}); + expect(ks.gestureNotes()).toEqual([]); + }); + + // Consider adding test to ensure array contains 2-tuples of strings +}); |