UNPKG

box-ui-elements-mlh

Version:
243 lines (193 loc) 7.69 kB
import { OrderedSet } from 'immutable'; import sinon from 'sinon'; import Mousetrap from 'mousetrap'; import HotkeyService from '../HotkeyService'; import HotkeyRecord from '../HotkeyRecord'; import HotkeyManager from '../HotkeyManager'; jest.mock('../HotkeyManager', () => ({ getActiveLayerID: jest.fn(), setActiveLayer: jest.fn(), removeLayer: jest.fn(), })); jest.mock('mousetrap'); const sandbox = sinon.sandbox.create(); describe('components/hotkeys/HotkeyService', () => { let instance; let callbackSpy; beforeEach(() => { callbackSpy = jest.fn(); const MousetrapMock = el => { el.addEventListener('keydown', callbackSpy); return { bind: sandbox.spy(), unbind: sandbox.spy(), reset: sandbox.spy(), }; }; Mousetrap.mockImplementation(MousetrapMock); instance = new HotkeyService(); }); afterEach(() => { sandbox.verifyAndRestore(); jest.resetModules(); jest.resetAllMocks(); }); describe('constructor()', () => { test('should instantiate Mousetrap object and set event listener', () => { expect(instance.mousetrap).toBeTruthy(); expect(instance.mousetrapEventHandler).toBeTruthy(); }); test('should add event listeners', () => { sandbox .mock(window) .expects('addEventListener') .thrice(); instance = new HotkeyService(); }); test('should set this layer as active layer in hotkey manager', () => { expect(HotkeyManager.setActiveLayer).toHaveBeenCalledWith(instance.layerID); }); }); describe('mousetrapEventHandler()', () => { test('should call stopPropagation and callback when this layer is currently active', () => { HotkeyManager.getActiveLayerID.mockReturnValueOnce(instance.layerID); const stopPropagation = jest.fn(); instance.mousetrapEventHandler({ stopPropagation }); expect(stopPropagation).toHaveBeenCalled(); expect(callbackSpy).toHaveBeenCalled(); }); test('should immediately return when this layer is not currently active', () => { HotkeyManager.getActiveLayerID.mockReturnValueOnce(`${instance.layerID}-not-this-layer`); const stopPropagation = jest.fn(); instance.mousetrapEventHandler({ stopPropagation }); expect(stopPropagation).not.toHaveBeenCalled(); }); }); describe('destroyLayer()', () => { test('should remove event listeners', () => { sandbox .mock(window) .expects('removeEventListener') .thrice(); instance.destroyLayer(); }); test('should remove layer from hotkey manager', () => { instance.destroyLayer(); expect(HotkeyManager.setActiveLayer).toHaveBeenCalledWith(instance.layerID); }); }); describe('reset()', () => { test('should reset hotkeys and call mousetrap.reset() when called', () => { instance.hotkeys = new OrderedSet(['hi', 'hello']); instance.reset(); expect(instance.hotkeys.size).toEqual(0); // called twice bc this.reset() is called in the constructor expect(instance.mousetrap.reset.calledTwice).toBe(true); }); }); describe('getActiveHotkeys()', () => { test('should return object with active hotkeys sorted into "buckets" by type', () => { const navigationHotkey = new HotkeyRecord({ key: 'a', type: 'navigation', }); const otherHotkey = new HotkeyRecord({ key: 'b', type: 'other', }); const previewHotkey = new HotkeyRecord({ key: 'c', type: 'preview', }); const hotkeys = new OrderedSet([navigationHotkey, otherHotkey, previewHotkey]); instance.hotkeys = hotkeys; const expected = { navigation: [navigationHotkey], other: [otherHotkey], preview: [previewHotkey], }; expect(instance.getActiveHotkeys()).toEqual(expected); }); }); describe('getActiveTypes()', () => { test('should return a list of the unique types of the currently active hotkeys', () => { const navigationHotkey = new HotkeyRecord({ key: 'a', type: 'navigation', }); const otherHotkey = new HotkeyRecord({ key: 'b', type: 'other', }); const previewHotkey = new HotkeyRecord({ key: 'c', type: 'preview', }); const hotkeys = new OrderedSet([navigationHotkey, otherHotkey, previewHotkey, navigationHotkey]); instance.hotkeys = hotkeys; const expected = ['navigation', 'other', 'preview']; expect(instance.getActiveTypes()).toEqual(expected); }); }); describe('registerHotkey()', () => { test('should add hotkey config and call mousetrap.bind', () => { const config = new HotkeyRecord({ key: 'b', }); instance.registerHotkey(config); expect(instance.hotkeys.contains(config)).toBe(true); expect(instance.mousetrap.bind.calledOnce).toBe(true); }); test('should ignore the request to register if the config was already registered', () => { const config = new HotkeyRecord({ key: 'b', }); instance.registerHotkey(config); instance.registerHotkey(config); expect(instance.mousetrap.bind.calledOnce).toBe(true); }); test('should throw an exception if a key is already in use by another config', () => { const config1 = new HotkeyRecord({ key: 'b', }); const config2 = new HotkeyRecord({ key: 'b', }); instance.registerHotkey(config1); expect(() => instance.registerHotkey(config2)).toThrow( 'This app is trying to bind multiple actions to the hot keys: b', ); }); }); describe('deregisterHotkey()', () => { let hotkeyConfigA; let hotkeyConfigB; let hotkeyConfigC; beforeEach(() => { hotkeyConfigA = new HotkeyRecord({ key: 'a', }); hotkeyConfigB = new HotkeyRecord({ key: 'b', }); hotkeyConfigC = new HotkeyRecord({ key: 'c', }); instance.registerHotkey(hotkeyConfigA); instance.registerHotkey(hotkeyConfigB); instance.registerHotkey(hotkeyConfigC); }); test('should remove hotkey config when called', () => { instance.deregisterHotkey(hotkeyConfigB); const { hotkeys } = instance; expect(hotkeys.size).toEqual(2); expect(hotkeys.includes(hotkeyConfigB)).toBe(false); }); test('should report no error if asked to remove a config that is not registered', () => { const newConfig = new HotkeyRecord({ key: 'd', }); expect(() => instance.deregisterHotkey(newConfig)).not.toThrow(); }); }); });