]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16008 Fix keyboad navigation conflict
authorJay <jeremy.davis@sonarsource.com>
Fri, 25 Feb 2022 10:23:01 +0000 (11:23 +0100)
committersonartech <sonartech@sonarsource.com>
Fri, 25 Feb 2022 20:02:55 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx

index 637789623377f131ed270a4476cd6e5eec908f67..4d335618427fdb71d741c6487d0edae1b944542a 100644 (file)
@@ -18,9 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import classNames from 'classnames';
-import key from 'keymaster';
 import * as React from 'react';
 import BoxedTabs from '../../../components/controls/BoxedTabs';
+import { KeyboardCodes } from '../../../helpers/keycodes';
 import { translate } from '../../../helpers/l10n';
 import { sanitizeString } from '../../../helpers/sanitize';
 import { Hotspot } from '../../../types/security-hotspots';
@@ -49,8 +49,6 @@ export enum TabKeys {
   FixRecommendation = 'fix'
 }
 
-const HOTSPOT_KEYMASTER_SCOPE = 'hotspots-list';
-
 export default class HotspotViewerTabs extends React.PureComponent<Props, State> {
   constructor(props: Props) {
     super(props);
@@ -87,20 +85,22 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State>
     this.unregisterKeyboardEvents();
   }
 
-  registerKeyboardEvents() {
-    key.setScope(HOTSPOT_KEYMASTER_SCOPE);
-    key('left', HOTSPOT_KEYMASTER_SCOPE, () => {
+  handleKeyboardNavigation = (event: KeyboardEvent) => {
+    if (event.code === KeyboardCodes.LeftArrow) {
+      event.preventDefault();
       this.selectNeighboringTab(-1);
-      return false;
-    });
-    key('right', HOTSPOT_KEYMASTER_SCOPE, () => {
+    } else if (event.code === KeyboardCodes.RightArrow) {
+      event.preventDefault();
       this.selectNeighboringTab(+1);
-      return false;
-    });
+    }
+  };
+
+  registerKeyboardEvents() {
+    window.addEventListener('keydown', this.handleKeyboardNavigation);
   }
 
   unregisterKeyboardEvents() {
-    key.deleteScope(HOTSPOT_KEYMASTER_SCOPE);
+    window.removeEventListener('keydown', this.handleKeyboardNavigation);
   }
 
   handleSelectTabs = (tabKey: TabKeys) => {
index ffbc475c3dadc79815b0ebabd3e767449cc188d1..50fbf5f43922b06ee72ee234a524fe23542ee31e 100644 (file)
@@ -22,29 +22,28 @@ import * as React from 'react';
 import BoxedTabs, { BoxedTabsProps } from '../../../../components/controls/BoxedTabs';
 import { KeyboardCodes } from '../../../../helpers/keycodes';
 import { mockHotspot, mockHotspotRule } from '../../../../helpers/mocks/security-hotspots';
-import { mockUser } from '../../../../helpers/testMocks';
-import { KEYCODE_MAP, keydown } from '../../../../helpers/testUtils';
+import { mockEvent, mockUser } from '../../../../helpers/testMocks';
 import HotspotViewerTabs, { TabKeys } from '../HotspotViewerTabs';
 
-jest.mock('keymaster', () => {
-  const key: any = (bindKey: string, _: string, callback: Function) => {
-    document.addEventListener('keydown', (event: KeyboardEvent) => {
-      const keymasterCode = event.code && KEYCODE_MAP[event.code as KeyboardCodes];
-      if (keymasterCode && bindKey.split(',').includes(keymasterCode)) {
-        return callback();
-      }
-      return true;
-    });
-  };
-  let scope = 'hotspots-list';
-
-  key.getScope = () => scope;
-  key.setScope = (newScope: string) => {
-    scope = newScope;
-  };
-  key.deleteScope = jest.fn();
-
-  return key;
+const originalAddEventListener = window.addEventListener;
+const originalRemoveEventListener = window.removeEventListener;
+
+beforeEach(() => {
+  Object.defineProperty(window, 'addEventListener', {
+    value: jest.fn()
+  });
+  Object.defineProperty(window, 'removeEventListener', {
+    value: jest.fn()
+  });
+});
+
+afterEach(() => {
+  Object.defineProperty(window, 'addEventListener', {
+    value: originalAddEventListener
+  });
+  Object.defineProperty(window, 'removeEventListener', {
+    value: originalRemoveEventListener
+  });
 });
 
 it('should render correctly', () => {
@@ -146,13 +145,13 @@ describe('keyboard navigation', () => {
   const wrapper = shallowRender();
 
   it.each([
-    ['selecting next', 0, 1, 1],
-    ['selecting previous', 1, -1, 0],
-    ['selecting previous, non-existent', 0, -1, 0],
-    ['selecting next, non-existent', 3, 1, 3]
-  ])('should work when %s', (_, start, shift, expected) => {
+    ['selecting next', 0, KeyboardCodes.RightArrow, 1],
+    ['selecting previous', 1, KeyboardCodes.LeftArrow, 0],
+    ['selecting previous, non-existent', 0, KeyboardCodes.LeftArrow, 0],
+    ['selecting next, non-existent', 3, KeyboardCodes.RightArrow, 3]
+  ])('should work when %s', (_, start, code, expected) => {
     wrapper.setState({ currentTab: wrapper.state().tabs[start] });
-    wrapper.instance().selectNeighboringTab(shift);
+    wrapper.instance().handleKeyboardNavigation(mockEvent({ code }));
 
     expect(wrapper.state().currentTab.key).toBe(tabList[expected]);
   });
@@ -163,13 +162,11 @@ it('should navigate when up and down key are pressed', () => {
     <HotspotViewerTabs codeTabContent={<div>CodeTabContent</div>} hotspot={mockHotspot()} />
   );
 
-  const selectNeighboringTab = jest.spyOn(wrapper.instance(), 'selectNeighboringTab');
+  expect(window.addEventListener).toBeCalled();
 
-  keydown({ code: KeyboardCodes.LeftArrow });
-  expect(selectNeighboringTab).toBeCalledWith(-1);
+  wrapper.unmount();
 
-  keydown({ code: KeyboardCodes.RightArrow });
-  expect(selectNeighboringTab).toBeCalledWith(1);
+  expect(window.removeEventListener).toBeCalled();
 });
 
 function shallowRender(props?: Partial<HotspotViewerTabs['props']>) {