aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2022-01-20 18:20:23 +0100
committersonartech <sonartech@sonarsource.com>2022-01-24 20:02:53 +0000
commit7aadbd0c9d08df36f21f31be759357cebf439a13 (patch)
tree6294c8972fb441ddd659a907dc415a9cc4fd174d /server/sonar-web
parentcda8e273cbce69ea0831055e622d5e2185de98d1 (diff)
downloadsonarqube-7aadbd0c9d08df36f21f31be759357cebf439a13.tar.gz
sonarqube-7aadbd0c9d08df36f21f31be759357cebf439a13.zip
SONAR-15942 Remove deprecated keycode
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx10
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/Menu-test.tsx10
-rw-r--r--server/sonar-web/src/main/js/app/components/search/Search.tsx9
-rw-r--r--server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/ProjectModal.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx20
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Search.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/Definition.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/SettingsSearch.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx17
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Definition-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx66
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelect.tsx41
-rw-r--r--server/sonar-web/src/main/js/components/common/SelectList.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/SelectList-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap96
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/SelectList-test.tsx.snap26
-rw-r--r--server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/controls/SearchBox.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/EscKeydownHandler-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/hoc/__tests__/withKeyboardNavigation-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/CommentPopup.tsx19
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/__tests__/CommentPopup-test.tsx74
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/CommentPopup-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/helpers/keycodes.ts67
-rw-r--r--server/sonar-web/src/main/js/helpers/testUtils.ts38
32 files changed, 397 insertions, 404 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx
index eb2e08e8395..e9d079c80c6 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx
@@ -28,7 +28,7 @@ import {
isPullRequest,
isSameBranchLike
} from '../../../../../helpers/branch-like';
-import { KeyCodes } from '../../../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../../../helpers/keycodes';
import { translate } from '../../../../../helpers/l10n';
import { getBranchLikeUrl } from '../../../../../helpers/urls';
import { BranchLike, BranchLikeTree } from '../../../../../types/branch-like';
@@ -109,16 +109,16 @@ export class Menu extends React.PureComponent<Props, State> {
};
handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.keyCode) {
- case KeyCodes.Enter:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
event.preventDefault();
this.openHighlightedBranchLike();
break;
- case KeyCodes.UpArrow:
+ case KeyboardCodes.UpArrow:
event.preventDefault();
this.highlightSiblingBranchlike(-1);
break;
- case KeyCodes.DownArrow:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
this.highlightSiblingBranchlike(+1);
break;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/Menu-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/Menu-test.tsx
index f0ca9926d3c..788febe0ecb 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/Menu-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/Menu-test.tsx
@@ -21,7 +21,7 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { Link } from 'react-router';
import SearchBox from '../../../../../../components/controls/SearchBox';
-import { KeyCodes } from '../../../../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../../../../helpers/keycodes';
import {
mockPullRequest,
mockSetOfBranchAndPullRequest
@@ -93,14 +93,14 @@ it('should handle keyboard shortcut correctly', () => {
const { onKeyDown } = wrapper.find(SearchBox).props();
- onKeyDown!(mockEvent({ keyCode: KeyCodes.UpArrow }));
+ onKeyDown!(mockEvent({ nativeEvent: { code: KeyboardCodes.UpArrow } }));
expect(wrapper.state().selectedBranchLike).toBe(branchLikes[5]);
- onKeyDown!(mockEvent({ keyCode: KeyCodes.DownArrow }));
- onKeyDown!(mockEvent({ keyCode: KeyCodes.DownArrow }));
+ onKeyDown!(mockEvent({ nativeEvent: { code: KeyboardCodes.DownArrow } }));
+ onKeyDown!(mockEvent({ nativeEvent: { code: KeyboardCodes.DownArrow } }));
expect(wrapper.state().selectedBranchLike).toBe(branchLikes[0]);
- onKeyDown!(mockEvent({ keyCode: KeyCodes.Enter }));
+ onKeyDown!(mockEvent({ nativeEvent: { code: KeyboardCodes.Enter } }));
expect(push).toHaveBeenCalled();
});
diff --git a/server/sonar-web/src/main/js/app/components/search/Search.tsx b/server/sonar-web/src/main/js/app/components/search/Search.tsx
index 6818bdabe43..5bcfd07fec5 100644
--- a/server/sonar-web/src/main/js/app/components/search/Search.tsx
+++ b/server/sonar-web/src/main/js/app/components/search/Search.tsx
@@ -29,6 +29,7 @@ import SearchBox from '../../../components/controls/SearchBox';
import ClockIcon from '../../../components/icons/ClockIcon';
import { lazyLoadComponent } from '../../../components/lazyLoadComponent';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { scrollToElement } from '../../../helpers/scrolling';
import { getComponentOverviewUrl } from '../../../helpers/urls';
@@ -286,16 +287,16 @@ export class Search extends React.PureComponent<Props, State> {
};
handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.keyCode) {
- case 13:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
event.preventDefault();
this.openSelected();
return;
- case 38:
+ case KeyboardCodes.UpArrow:
event.preventDefault();
this.selectPrevious();
return;
- case 40:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
this.selectNext();
// keep this return to prevent fall-through in case more cases will be adder later
diff --git a/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx b/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx
index d7ab82e39d1..67d98023a44 100644
--- a/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/search/__tests__/Search-test.tsx
@@ -19,6 +19,7 @@
*/
import { shallow, ShallowWrapper } from 'enzyme';
import * as React from 'react';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
import { mockRouter } from '../../../../helpers/testMocks';
import { elementKeydown } from '../../../../helpers/testUtils';
import { ComponentQualifier } from '../../../../types/component';
@@ -56,7 +57,7 @@ it('opens selected project on enter', () => {
selected: selectedKey
});
- elementKeydown(form.find('SearchBox'), 13);
+ elementKeydown(form.find('SearchBox'), KeyboardCodes.Enter);
expect(router.push).toBeCalledWith({ pathname: '/dashboard', query: { id: selectedKey } });
});
@@ -72,7 +73,7 @@ it('opens selected portfolio on enter', () => {
selected: selectedKey
});
- elementKeydown(form.find('SearchBox'), 13);
+ elementKeydown(form.find('SearchBox'), KeyboardCodes.Enter);
expect(router.push).toBeCalledWith({ pathname: '/portfolio', query: { id: selectedKey } });
});
@@ -88,7 +89,7 @@ it('opens selected subportfolio on enter', () => {
selected: selectedKey
});
- elementKeydown(form.find('SearchBox'), 13);
+ elementKeydown(form.find('SearchBox'), KeyboardCodes.Enter);
expect(router.push).toBeCalledWith({ pathname: '/portfolio', query: { id: selectedKey } });
});
@@ -112,12 +113,12 @@ function component(key: string, qualifier = ComponentQualifier.Project) {
}
function next(form: ShallowWrapper<Search['props'], Search['state']>, expected: string) {
- elementKeydown(form.find('SearchBox'), 40);
+ elementKeydown(form.find('SearchBox'), KeyboardCodes.DownArrow);
expect(form.state().selected).toBe(expected);
}
function prev(form: ShallowWrapper<Search['props'], Search['state']>, expected: string) {
- elementKeydown(form.find('SearchBox'), 38);
+ elementKeydown(form.find('SearchBox'), KeyboardCodes.UpArrow);
expect(form.state().selected).toBe(expected);
}
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/ProjectModal.tsx b/server/sonar-web/src/main/js/apps/account/notifications/ProjectModal.tsx
index 7a0060f4569..b83d7555ff6 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/ProjectModal.tsx
+++ b/server/sonar-web/src/main/js/apps/account/notifications/ProjectModal.tsx
@@ -25,6 +25,7 @@ import { ResetButtonLink, SubmitButton } from '../../../components/controls/butt
import { DropdownOverlay } from '../../../components/controls/Dropdown';
import SearchBox from '../../../components/controls/SearchBox';
import SimpleModal from '../../../components/controls/SimpleModal';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -61,16 +62,16 @@ export default class ProjectModal extends React.PureComponent<Props, State> {
}
handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.keyCode) {
- case 13:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
event.preventDefault();
this.handleSelectHighlighted();
break;
- case 38:
+ case KeyboardCodes.UpArrow:
event.preventDefault();
this.handleHighlightPrevious();
break;
- case 40:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
this.handleHighlightNext();
break;
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx
index e8707186222..9d47ebc3a1d 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/ProjectModal-test.tsx
@@ -20,6 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { getSuggestions } from '../../../../api/components';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
import { change, elementKeydown, submit, waitAndUpdate } from '../../../../helpers/testUtils';
import ProjectModal from '../ProjectModal';
@@ -102,27 +103,24 @@ it('should handle up and down keys', async () => {
});
await waitAndUpdate(wrapper);
- // Down.
- elementKeydown(wrapper.dive().find('SearchBox'), 40);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.DownArrow);
expect(wrapper.state('highlighted')).toEqual(foo);
- elementKeydown(wrapper.dive().find('SearchBox'), 40);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.DownArrow);
expect(wrapper.state('highlighted')).toEqual(bar);
- elementKeydown(wrapper.dive().find('SearchBox'), 40);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.DownArrow);
expect(wrapper.state('highlighted')).toEqual(foo);
- // Up.
- elementKeydown(wrapper.dive().find('SearchBox'), 38);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.UpArrow);
expect(wrapper.state('highlighted')).toEqual(bar);
- elementKeydown(wrapper.dive().find('SearchBox'), 38);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.UpArrow);
expect(wrapper.state('highlighted')).toEqual(foo);
- elementKeydown(wrapper.dive().find('SearchBox'), 38);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.UpArrow);
expect(wrapper.state('highlighted')).toEqual(bar);
- // Enter.
- elementKeydown(wrapper.dive().find('SearchBox'), 13);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.Enter);
expect(wrapper.state('selectedProject')).toEqual(bar);
expect(onSubmit).not.toHaveBeenCalled();
- elementKeydown(wrapper.dive().find('SearchBox'), 13);
+ elementKeydown(wrapper.dive().find('SearchBox'), KeyboardCodes.Enter);
expect(onSubmit).toHaveBeenCalledWith(bar);
});
diff --git a/server/sonar-web/src/main/js/apps/code/components/Search.tsx b/server/sonar-web/src/main/js/apps/code/components/Search.tsx
index 90d9fbb8c83..188c4dff9c1 100644
--- a/server/sonar-web/src/main/js/apps/code/components/Search.tsx
+++ b/server/sonar-web/src/main/js/apps/code/components/Search.tsx
@@ -24,6 +24,7 @@ import SearchBox from '../../../components/controls/SearchBox';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import PortfolioNewCodeToggle from './PortfolioNewCodeToggle';
@@ -74,10 +75,10 @@ export class Search extends React.PureComponent<Props, State> {
}
handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
- switch (event.keyCode) {
- case 13:
- case 38:
- case 40:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
+ case KeyboardCodes.UpArrow:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
event.currentTarget.blur();
break;
diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
index c64244bb8f6..474aacb0a11 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
@@ -43,7 +43,7 @@ import {
isSameBranchLike
} from '../../../helpers/branch-like';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
-import { KeyCodes } from '../../../helpers/keycodes';
+import { KeyboardCodes, KeyboardKeys } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
addSideBarClass,
@@ -268,19 +268,19 @@ export default class App extends React.PureComponent<Props, State> {
if (key.getScope() !== 'issues') {
return;
}
- if (event.keyCode === KeyCodes.Alt) {
+ if (event.key === KeyboardKeys.Alt) {
event.preventDefault();
this.setState(actions.enableLocationsNavigator);
- } else if (event.keyCode === KeyCodes.DownArrow && event.altKey) {
+ } else if (event.code === KeyboardCodes.DownArrow && event.altKey) {
event.preventDefault();
this.selectNextLocation();
- } else if (event.keyCode === KeyCodes.UpArrow && event.altKey) {
+ } else if (event.code === KeyboardCodes.UpArrow && event.altKey) {
event.preventDefault();
this.selectPreviousLocation();
- } else if (event.keyCode === KeyCodes.LeftArrow && event.altKey) {
+ } else if (event.code === KeyboardCodes.LeftArrow && event.altKey) {
event.preventDefault();
this.selectPreviousFlow();
- } else if (event.keyCode === KeyCodes.RightArrow && event.altKey) {
+ } else if (event.code === KeyboardCodes.RightArrow && event.altKey) {
event.preventDefault();
this.selectNextFlow();
}
@@ -290,8 +290,7 @@ export default class App extends React.PureComponent<Props, State> {
if (key.getScope() !== 'issues') {
return;
}
- if (event.keyCode === KeyCodes.Alt) {
- // alt
+ if (event.key === KeyboardKeys.Alt) {
this.setState(actions.disableLocationsNavigator);
}
};
diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx
index ec5f4e5e767..404e5859b82 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx
@@ -21,7 +21,7 @@ import { shallow } from 'enzyme';
import key from 'keymaster';
import * as React from 'react';
import handleRequiredAuthentication from '../../../../helpers/handleRequiredAuthentication';
-import { KeyCodes } from '../../../../helpers/keycodes';
+import { KeyboardCodes, KeyboardKeys } from '../../../../helpers/keycodes';
import { mockPullRequest } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
import {
@@ -63,7 +63,8 @@ jest.mock('../../../../helpers/handleRequiredAuthentication', () => jest.fn());
jest.mock('keymaster', () => {
const key: any = (bindKey: string, _: string, callback: Function) => {
document.addEventListener('keydown', (event: KeyboardEvent) => {
- if (bindKey.split(',').includes(KEYCODE_MAP[event.keyCode])) {
+ const keymasterCode = event.code && KEYCODE_MAP[event.code as KeyboardCodes];
+ if (keymasterCode && bindKey.split(',').includes(keymasterCode)) {
return callback();
}
return true;
@@ -217,25 +218,25 @@ it('should correctly bind key events for issue navigation', async () => {
expect(wrapper.state('selected')).toBe(ISSUES[0].key);
- keydown(KeyCodes.DownArrow);
+ keydown({ code: KeyboardCodes.DownArrow });
expect(wrapper.state('selected')).toBe(ISSUES[1].key);
- keydown(KeyCodes.UpArrow);
- keydown(KeyCodes.UpArrow);
+ keydown({ code: KeyboardCodes.UpArrow });
+ keydown({ code: KeyboardCodes.UpArrow });
expect(wrapper.state('selected')).toBe(ISSUES[0].key);
- keydown(KeyCodes.DownArrow);
- keydown(KeyCodes.DownArrow);
- keydown(KeyCodes.DownArrow);
- keydown(KeyCodes.DownArrow);
- keydown(KeyCodes.DownArrow);
- keydown(KeyCodes.DownArrow);
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
expect(wrapper.state('selected')).toBe(ISSUES[3].key);
- keydown(KeyCodes.RightArrow);
+ keydown({ code: KeyboardCodes.RightArrow });
expect(push).toBeCalledTimes(1);
- keydown(KeyCodes.LeftArrow);
+ keydown({ code: KeyboardCodes.LeftArrow });
expect(push).toBeCalledTimes(2);
expect(window.addEventListener).toBeCalledTimes(2);
});
@@ -432,28 +433,28 @@ describe('keydown event handler', () => {
});
it('should handle alt', () => {
- instance.handleKeyDown(mockEvent({ keyCode: 18 }));
+ instance.handleKeyDown(mockEvent({ key: KeyboardKeys.Alt }));
expect(instance.setState).toHaveBeenCalledWith(enableLocationsNavigator);
});
it('should handle alt+↓', () => {
- instance.handleKeyDown(mockEvent({ altKey: true, keyCode: 40 }));
+ instance.handleKeyDown(mockEvent({ altKey: true, code: KeyboardCodes.DownArrow }));
expect(instance.setState).toHaveBeenCalledWith(selectNextLocation);
});
it('should handle alt+↑', () => {
- instance.handleKeyDown(mockEvent({ altKey: true, keyCode: 38 }));
+ instance.handleKeyDown(mockEvent({ altKey: true, code: KeyboardCodes.UpArrow }));
expect(instance.setState).toHaveBeenCalledWith(selectPreviousLocation);
});
it('should handle alt+←', () => {
- instance.handleKeyDown(mockEvent({ altKey: true, keyCode: 37 }));
+ instance.handleKeyDown(mockEvent({ altKey: true, code: KeyboardCodes.LeftArrow }));
expect(instance.setState).toHaveBeenCalledWith(selectPreviousFlow);
});
it('should handle alt+→', () => {
- instance.handleKeyDown(mockEvent({ altKey: true, keyCode: 39 }));
+ instance.handleKeyDown(mockEvent({ altKey: true, code: KeyboardCodes.RightArrow }));
expect(instance.setState).toHaveBeenCalledWith(selectNextFlow);
});
it('should ignore different scopes', () => {
key.setScope('notissues');
- instance.handleKeyDown(mockEvent({ keyCode: 18 }));
+ instance.handleKeyDown(mockEvent({ key: KeyboardKeys.Alt }));
expect(instance.setState).not.toHaveBeenCalled();
});
});
@@ -472,13 +473,13 @@ describe('keyup event handler', () => {
});
it('should handle alt', () => {
- instance.handleKeyUp(mockEvent({ keyCode: 18 }));
+ instance.handleKeyUp(mockEvent({ key: KeyboardKeys.Alt }));
expect(instance.setState).toHaveBeenCalledWith(disableLocationsNavigator);
});
it('should ignore different scopes', () => {
key.setScope('notissues');
- instance.handleKeyUp(mockEvent({ keyCode: 18 }));
+ instance.handleKeyUp(mockEvent({ key: KeyboardKeys.Alt }));
expect(instance.setState).not.toHaveBeenCalled();
});
});
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx
index 5a2d364fcb6..4469a4d3d6b 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx
@@ -20,7 +20,7 @@
import { debounce } from 'lodash';
import * as React from 'react';
import { searchUsers } from '../../../../api/users';
-import { KeyCodes } from '../../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
import { translate } from '../../../../helpers/l10n';
import { isUserActive } from '../../../../helpers/users';
import AssigneeSelectionRenderer from './AssigneeSelectionRenderer';
@@ -104,16 +104,16 @@ export default class AssigneeSelection extends React.PureComponent<Props, State>
};
handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.keyCode) {
- case KeyCodes.Enter:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
event.preventDefault();
this.selectHighlighted();
break;
- case KeyCodes.UpArrow:
+ case KeyboardCodes.UpArrow:
event.preventDefault();
this.highlightPrevious();
break;
- case KeyCodes.DownArrow:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
this.highlightNext();
break;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx
index 7820149048a..73fa3302350 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx
@@ -20,7 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { searchUsers } from '../../../../../api/users';
-import { KeyCodes } from '../../../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../../../helpers/keycodes';
import { mockLoggedInUser, mockUser } from '../../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../../helpers/testUtils';
import AssigneeSelection from '../AssigneeSelection';
@@ -34,7 +34,7 @@ it('should render correctly', () => {
});
it('should handle keydown', () => {
- const mockEvent = (keyCode: number) => ({ preventDefault: jest.fn(), keyCode });
+ const mockEvent = (code: KeyboardCodes) => ({ preventDefault: jest.fn(), nativeEvent: { code } });
const suggestedUsers = [
mockUser({ login: '1' }) as T.UserActive,
mockUser({ login: '2' }) as T.UserActive,
@@ -44,29 +44,29 @@ it('should handle keydown', () => {
const onSelect = jest.fn();
const wrapper = shallowRender({ onSelect });
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.UpArrow) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.UpArrow) as any);
expect(wrapper.state().highlighted).toEqual({ login: '', name: 'unassigned' });
wrapper.setState({ suggestedUsers });
// press down to highlight the first
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.DownArrow) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.DownArrow) as any);
expect(wrapper.state().highlighted).toBe(suggestedUsers[0]);
// press up to loop around to last
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.UpArrow) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.UpArrow) as any);
expect(wrapper.state().highlighted).toBe(suggestedUsers[2]);
// press down to loop around to first
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.DownArrow) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.DownArrow) as any);
expect(wrapper.state().highlighted).toBe(suggestedUsers[0]);
// press down highlight the next
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.DownArrow) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.DownArrow) as any);
expect(wrapper.state().highlighted).toBe(suggestedUsers[1]);
// press enter to select the highlighted user
- wrapper.instance().handleKeyDown(mockEvent(KeyCodes.Enter) as any);
+ wrapper.instance().handleKeyDown(mockEvent(KeyboardCodes.Enter) as any);
expect(onSelect).toBeCalledWith(suggestedUsers[1]);
});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
index f237d48a304..0bc426876f8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
@@ -62,6 +62,8 @@ interface State {
const SAFE_SET_STATE_DELAY = 3000;
+const formNoop = (e: React.FormEvent<HTMLFormElement>) => e.preventDefault();
+
export class Definition extends React.PureComponent<Props, State> {
timeout?: number;
mounted = false;
@@ -189,7 +191,7 @@ export class Definition extends React.PureComponent<Props, State> {
</span>
)}
</div>
- <form>
+ <form onSubmit={formNoop}>
<Input
hasValueChanged={hasValueChanged}
onCancel={this.handleCancel}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsSearch.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearch.tsx
index 40609c6b17a..0d3bed68fd4 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/SettingsSearch.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearch.tsx
@@ -23,7 +23,7 @@ import * as React from 'react';
import { connect } from 'react-redux';
import { InjectedRouter } from 'react-router';
import { withRouter } from '../../../components/hoc/withRouter';
-import { KeyCodes } from '../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { getSettingsAppAllDefinitions, Store } from '../../../store/rootReducer';
import { SettingCategoryDefinition } from '../../../types/settings';
import { ADDITIONAL_SETTING_DEFINITIONS, buildSettingLink } from '../utils';
@@ -118,16 +118,16 @@ export class SettingsSearch extends React.Component<Props, State> {
};
handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.keyCode) {
- case KeyCodes.Enter:
+ switch (event.nativeEvent.code) {
+ case KeyboardCodes.Enter:
event.preventDefault();
this.openSelected();
return;
- case KeyCodes.UpArrow:
+ case KeyboardCodes.UpArrow:
event.preventDefault();
this.selectPrevious();
return;
- case KeyCodes.DownArrow:
+ case KeyboardCodes.DownArrow:
event.preventDefault();
this.selectNext();
// keep this return to prevent fall-through in case more cases will be adder later
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx
index a29b3db703e..f6ea708a34d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx
@@ -19,6 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
import { mockDefinition } from '../../../../helpers/mocks/settings';
import { mockRouter } from '../../../../helpers/testMocks';
import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils';
@@ -96,11 +97,11 @@ describe('instance', () => {
it('should handle "enter" keyboard event', () => {
wrapper.setState({ selectedResult: undefined });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 13 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.Enter } }));
expect(router.push).not.toBeCalled();
wrapper.setState({ selectedResult: 'foo' });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 13 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.Enter } }));
expect(router.push).toBeCalledWith({
hash: '#foo',
@@ -111,27 +112,27 @@ describe('instance', () => {
it('should handle "down" keyboard event', () => {
wrapper.setState({ selectedResult: undefined });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 40 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.DownArrow } }));
expect(wrapper.state().selectedResult).toBeUndefined();
wrapper.setState({ selectedResult: 'foo' });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 40 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.DownArrow } }));
expect(wrapper.state().selectedResult).toBe('sonar.new_code_period');
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 40 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.DownArrow } }));
expect(wrapper.state().selectedResult).toBe('sonar.new_code_period');
});
it('should handle "up" keyboard event', () => {
wrapper.setState({ selectedResult: undefined });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 38 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.UpArrow } }));
expect(wrapper.state().selectedResult).toBeUndefined();
wrapper.setState({ selectedResult: 'sonar.new_code_period' });
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 38 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.UpArrow } }));
expect(wrapper.state().selectedResult).toBe('foo');
- wrapper.instance().handleKeyDown(mockEvent({ keyCode: 38 }));
+ wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.UpArrow } }));
expect(wrapper.state().selectedResult).toBe('foo');
});
});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Definition-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Definition-test.tsx.snap
index c7425dafd23..3bf97fc1334 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Definition-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Definition-test.tsx.snap
@@ -34,7 +34,9 @@ exports[`should render correctly 1`] = `
<div
className="settings-definition-state"
/>
- <form>
+ <form
+ onSubmit={[Function]}
+ >
<Input
hasValueChanged={false}
onCancel={[Function]}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx
index 31ad1d08118..8cb2110a064 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx
@@ -19,21 +19,22 @@
*/
import classNames from 'classnames';
import * as React from 'react';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
import { DefaultSpecializedInputProps } from '../../utils';
-interface Props extends DefaultSpecializedInputProps {
+export interface SimpleInputProps extends DefaultSpecializedInputProps {
value: string | number;
}
-export default class SimpleInput extends React.PureComponent<Props> {
+export default class SimpleInput extends React.PureComponent<SimpleInputProps> {
handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.onChange(event.currentTarget.value);
};
handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
- if (event.keyCode === 13 && this.props.onSave) {
+ if (event.nativeEvent.code === KeyboardCodes.Enter && this.props.onSave) {
this.props.onSave();
- } else if (event.keyCode === 27 && this.props.onCancel) {
+ } else if (event.nativeEvent.code === KeyboardCodes.Escape && this.props.onCancel) {
this.props.onCancel();
}
};
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
index f61a4ee4ce5..3c326c7f17c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
@@ -19,23 +19,14 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { KeyboardCodes } from '../../../../../helpers/keycodes';
import { mockSetting } from '../../../../../helpers/mocks/settings';
+import { mockEvent } from '../../../../../helpers/testMocks';
import { change } from '../../../../../helpers/testUtils';
-import SimpleInput from '../SimpleInput';
+import SimpleInput, { SimpleInputProps } from '../SimpleInput';
it('should render input', () => {
- const onChange = jest.fn();
- const input = shallow(
- <SimpleInput
- className="input-large"
- isDefault={false}
- name="foo"
- onChange={onChange}
- type="text"
- setting={mockSetting()}
- value="bar"
- />
- ).find('input');
+ const input = shallowRender().find('input');
expect(input.length).toBe(1);
expect(input.prop('type')).toBe('text');
expect(input.prop('className')).toContain('input-large');
@@ -46,20 +37,51 @@ it('should render input', () => {
it('should call onChange', () => {
const onChange = jest.fn();
- const input = shallow(
+ const input = shallowRender({ onChange }).find('input');
+ expect(input.length).toBe(1);
+ expect(input.prop('onChange')).toBeDefined();
+
+ change(input, 'qux');
+ expect(onChange).toBeCalledWith('qux');
+});
+
+it('should handle enter', () => {
+ const onSave = jest.fn();
+ shallowRender({ onSave })
+ .instance()
+ .handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.Enter } }));
+ expect(onSave).toBeCalled();
+});
+
+it('should handle esc', () => {
+ const onCancel = jest.fn();
+ shallowRender({ onCancel })
+ .instance()
+ .handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.Escape } }));
+ expect(onCancel).toBeCalled();
+});
+
+it('should ignore other keys', () => {
+ const onSave = jest.fn();
+ const onCancel = jest.fn();
+ shallowRender({ onCancel, onSave })
+ .instance()
+ .handleKeyDown(mockEvent({ nativeEvent: { code: KeyboardCodes.LeftArrow } }));
+ expect(onSave).not.toBeCalled();
+ expect(onCancel).not.toBeCalled();
+});
+
+function shallowRender(overrides: Partial<SimpleInputProps> = {}) {
+ return shallow<SimpleInput>(
<SimpleInput
className="input-large"
isDefault={false}
name="foo"
- onChange={onChange}
+ onChange={jest.fn()}
type="text"
setting={mockSetting()}
value="bar"
+ {...overrides}
/>
- ).find('input');
- expect(input.length).toBe(1);
- expect(input.prop('onChange')).toBeDefined();
-
- change(input, 'qux');
- expect(onChange).toBeCalledWith('qux');
-});
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
index 6f0aab023c8..67075ca2cc5 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
+++ b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
@@ -21,10 +21,11 @@ import classNames from 'classnames';
import { difference } from 'lodash';
import * as React from 'react';
import SearchBox from '../../components/controls/SearchBox';
+import { KeyboardCodes } from '../../helpers/keycodes';
import { translateWithParameters } from '../../helpers/l10n';
import MultiSelectOption from './MultiSelectOption';
-interface Props {
+export interface MultiSelectProps {
allowNewElements?: boolean;
allowSelection?: boolean;
elements: string[];
@@ -55,9 +56,9 @@ interface DefaultProps {
validateSearchInput: (value: string) => string;
}
-type PropsWithDefault = Props & DefaultProps;
+type PropsWithDefault = MultiSelectProps & DefaultProps;
-export default class MultiSelect extends React.PureComponent<Props, State> {
+export default class MultiSelect extends React.PureComponent<MultiSelectProps, State> {
container?: HTMLDivElement | null;
searchInput?: HTMLInputElement | null;
mounted = false;
@@ -70,7 +71,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
validateSearchInput: (value: string) => value
};
- constructor(props: Props) {
+ constructor(props: MultiSelectProps) {
super(props);
this.state = {
activeIdx: 0,
@@ -137,23 +138,23 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
});
};
- handleKeyboard = (evt: KeyboardEvent) => {
- switch (evt.keyCode) {
- case 40: // down
- evt.stopPropagation();
- evt.preventDefault();
+ handleKeyboard = (event: KeyboardEvent) => {
+ switch (event.code) {
+ case KeyboardCodes.DownArrow:
+ event.stopPropagation();
+ event.preventDefault();
this.setState(this.selectNextElement);
break;
- case 38: // up
- evt.stopPropagation();
- evt.preventDefault();
+ case KeyboardCodes.UpArrow:
+ event.stopPropagation();
+ event.preventDefault();
this.setState(this.selectPreviousElement);
break;
- case 37: // left
- case 39: // right
- evt.stopPropagation();
+ case KeyboardCodes.LeftArrow:
+ case KeyboardCodes.RightArrow:
+ event.stopPropagation();
break;
- case 13: // enter
+ case KeyboardCodes.Enter:
if (this.state.activeIdx >= 0) {
this.toggleSelect(this.getAllElements(this.props, this.state)[this.state.activeIdx]);
}
@@ -175,7 +176,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
onUnselectItem = (item: string) => this.props.onUnselect(item);
- isNewElement = (elem: string, { selectedElements, elements }: Props) =>
+ isNewElement = (elem: string, { selectedElements, elements }: MultiSelectProps) =>
elem.length > 0 && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1;
updateSelectedElements = (props: PropsWithDefault) => {
@@ -207,7 +208,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
});
};
- getAllElements = (props: Props, state: State) => {
+ getAllElements = (props: MultiSelectProps, state: State) => {
if (this.isNewElement(state.query, props)) {
return [...state.selectedElements, ...state.unselectedElements, state.query];
} else {
@@ -217,7 +218,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
setElementActive = (idx: number) => this.setState({ activeIdx: idx });
- selectNextElement = (state: State, props: Props) => {
+ selectNextElement = (state: State, props: MultiSelectProps) => {
const { activeIdx } = state;
const allElements = this.getAllElements(props, state);
if (activeIdx < 0 || activeIdx >= allElements.length - 1) {
@@ -227,7 +228,7 @@ export default class MultiSelect extends React.PureComponent<Props, State> {
}
};
- selectPreviousElement = (state: State, props: Props) => {
+ selectPreviousElement = (state: State, props: MultiSelectProps) => {
const { activeIdx } = state;
const allElements = this.getAllElements(props, state);
if (activeIdx <= 0) {
diff --git a/server/sonar-web/src/main/js/components/common/SelectList.tsx b/server/sonar-web/src/main/js/components/common/SelectList.tsx
index e27ce103f2c..cf5cc752154 100644
--- a/server/sonar-web/src/main/js/components/common/SelectList.tsx
+++ b/server/sonar-web/src/main/js/components/common/SelectList.tsx
@@ -21,6 +21,7 @@ import classNames from 'classnames';
import key from 'keymaster';
import { uniqueId } from 'lodash';
import * as React from 'react';
+import { KeyboardCodes } from '../../helpers/keycodes';
import SelectListItem from './SelectListItem';
interface Props {
@@ -76,7 +77,11 @@ export default class SelectList extends React.PureComponent<Props, State> {
filter: (event: KeyboardEvent & { target: HTMLElement }) => {
const { tagName } = event.target || event.srcElement;
const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
- return [13, 38, 40].includes(event.keyCode) || !isInput;
+ return (
+ [KeyboardCodes.Enter, KeyboardCodes.UpArrow, KeyboardCodes.DownArrow].includes(
+ event.code as KeyboardCodes
+ ) || !isInput
+ );
}
});
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
index 2915951fc2d..29cd2d8a565 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
+++ b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
@@ -19,7 +19,9 @@
*/
import { mount, shallow } from 'enzyme';
import * as React from 'react';
-import MultiSelect from '../MultiSelect';
+import { KeyboardCodes } from '../../../helpers/keycodes';
+import { mockEvent } from '../../../helpers/testUtils';
+import MultiSelect, { MultiSelectProps } from '../MultiSelect';
const props = {
selectedElements: ['bar'],
@@ -31,14 +33,10 @@ const props = {
placeholder: ''
};
-const elements = [
- { key: 'foo', label: 'foo' },
- { key: 'bar', label: 'bar' },
- { key: 'baz', label: 'baz' }
-];
+const elements = ['foo', 'bar', 'baz'];
it('should render multiselect with selected elements', () => {
- const multiselect = shallow(<MultiSelect {...props} />);
+ const multiselect = shallowRender();
// Will not only the selected element
expect(multiselect).toMatchSnapshot();
@@ -55,9 +53,53 @@ it('should render with the focus inside the search input', () => {
* Need to attach to document body to have it set to `document.activeElement`
* See: https://github.com/jsdom/jsdom/issues/2723#issuecomment-580163361
*/
- const multiselect = mount(<MultiSelect {...props} />, { attachTo: document.body });
+ const container = document.createElement('div');
+ document.body.appendChild(container);
+ const multiselect = mount(<MultiSelect {...props} />, { attachTo: container });
expect(multiselect.find('input').getDOMNode()).toBe(document.activeElement);
multiselect.unmount();
});
+
+it.each([
+ [KeyboardCodes.DownArrow, 1, 1],
+ [KeyboardCodes.UpArrow, 1, 1],
+ [KeyboardCodes.LeftArrow, 1, 0]
+])('should handle keyboard event: %s', (code, stopPropagationCalls, preventDefaultCalls) => {
+ const wrapper = shallowRender();
+
+ const stopPropagation = jest.fn();
+ const preventDefault = jest.fn();
+ const event = mockEvent({ preventDefault, stopPropagation, code });
+
+ wrapper.instance().handleKeyboard(event);
+
+ expect(stopPropagation).toBeCalledTimes(stopPropagationCalls);
+ expect(preventDefault).toBeCalledTimes(preventDefaultCalls);
+});
+
+it('should handle keyboard event: enter', () => {
+ const wrapper = shallowRender();
+
+ wrapper.instance().toggleSelect = jest.fn();
+
+ wrapper.instance().handleKeyboard(mockEvent({ code: KeyboardCodes.Enter }));
+
+ expect(wrapper.instance().toggleSelect).toBeCalled();
+});
+
+function shallowRender(overrides: Partial<MultiSelectProps> = {}) {
+ return shallow<MultiSelect>(
+ <MultiSelect
+ selectedElements={['bar']}
+ elements={[]}
+ onSearch={() => Promise.resolve()}
+ onSelect={jest.fn()}
+ onUnselect={jest.fn()}
+ renderLabel={(element: string) => element}
+ placeholder=""
+ {...overrides}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/SelectList-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/SelectList-test.tsx
index 8c4449fcf9b..1c83728fef7 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/SelectList-test.tsx
+++ b/server/sonar-web/src/main/js/components/common/__tests__/SelectList-test.tsx
@@ -19,10 +19,32 @@
*/
import { mount, shallow } from 'enzyme';
import * as React from 'react';
-import { click, keydown } from '../../../helpers/testUtils';
+import { KeyboardCodes } from '../../../helpers/keycodes';
+import { click, KEYCODE_MAP, keydown } from '../../../helpers/testUtils';
import SelectList from '../SelectList';
import SelectListItem from '../SelectListItem';
+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 = 'key-scope';
+
+ key.getScope = () => scope;
+ key.setScope = (newScope: string) => {
+ scope = newScope;
+ };
+ key.deleteScope = jest.fn();
+
+ return key;
+});
+
it('should render correctly without children', () => {
const onSelect = jest.fn();
expect(
@@ -56,7 +78,7 @@ it('should render correctly with children', () => {
it('should correclty handle user actions', () => {
const onSelect = jest.fn();
const items = ['item', 'seconditem', 'third'];
- const list = mount(
+ const list = mount<SelectList>(
<SelectList currentItem="seconditem" items={items} onSelect={onSelect}>
{items.map(item => (
<SelectListItem item={item} key={item}>
@@ -66,12 +88,15 @@ it('should correclty handle user actions', () => {
))}
</SelectList>
);
- keydown(40);
- expect(list.state()).toMatchSnapshot();
- keydown(40);
- expect(list.state()).toMatchSnapshot();
- keydown(38);
- expect(list.state()).toMatchSnapshot();
+ expect(list.state().active).toBe('seconditem');
+ keydown({ code: KeyboardCodes.DownArrow });
+ expect(list.state().active).toBe('third');
+ keydown({ code: KeyboardCodes.DownArrow });
+ expect(list.state().active).toBe('item');
+ keydown({ code: KeyboardCodes.UpArrow });
+ expect(list.state().active).toBe('third');
+ keydown({ code: KeyboardCodes.UpArrow });
+ expect(list.state().active).toBe('seconditem');
click(list.find('a').at(2));
- expect(onSelect.mock.calls).toMatchSnapshot(); // eslint-disable-linelist
+ expect(onSelect).toBeCalledWith('third');
});
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
index 87a1bfd052c..bd2ca89e1dc 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
@@ -63,13 +63,8 @@ exports[`should render multiselect with selected elements 2`] = `
<MultiSelectOption
active={false}
disabled={false}
- element={
- Object {
- "key": "foo",
- "label": "foo",
- }
- }
- key="[object Object]"
+ element="foo"
+ key="foo"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
@@ -77,27 +72,8 @@ exports[`should render multiselect with selected elements 2`] = `
<MultiSelectOption
active={false}
disabled={false}
- element={
- Object {
- "key": "bar",
- "label": "bar",
- }
- }
- key="[object Object]"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element={
- Object {
- "key": "baz",
- "label": "baz",
- }
- }
- key="[object Object]"
+ element="baz"
+ key="baz"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
@@ -137,13 +113,8 @@ exports[`should render multiselect with selected elements 3`] = `
<MultiSelectOption
active={false}
disabled={false}
- element={
- Object {
- "key": "foo",
- "label": "foo",
- }
- }
- key="[object Object]"
+ element="foo"
+ key="foo"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
@@ -151,27 +122,8 @@ exports[`should render multiselect with selected elements 3`] = `
<MultiSelectOption
active={true}
disabled={false}
- element={
- Object {
- "key": "bar",
- "label": "bar",
- }
- }
- key="[object Object]"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element={
- Object {
- "key": "baz",
- "label": "baz",
- }
- }
- key="[object Object]"
+ element="baz"
+ key="baz"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
@@ -211,13 +163,8 @@ exports[`should render multiselect with selected elements 4`] = `
<MultiSelectOption
active={false}
disabled={false}
- element={
- Object {
- "key": "foo",
- "label": "foo",
- }
- }
- key="[object Object]"
+ element="foo"
+ key="foo"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
@@ -225,27 +172,8 @@ exports[`should render multiselect with selected elements 4`] = `
<MultiSelectOption
active={true}
disabled={false}
- element={
- Object {
- "key": "bar",
- "label": "bar",
- }
- }
- key="[object Object]"
- onHover={[Function]}
- onSelectChange={[Function]}
- renderLabel={[Function]}
- />
- <MultiSelectOption
- active={false}
- disabled={false}
- element={
- Object {
- "key": "baz",
- "label": "baz",
- }
- }
- key="[object Object]"
+ element="baz"
+ key="baz"
onHover={[Function]}
onSelectChange={[Function]}
renderLabel={[Function]}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/SelectList-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/SelectList-test.tsx.snap
index c1c91a2ba8e..af2d76a8216 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/SelectList-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/SelectList-test.tsx.snap
@@ -1,31 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should correclty handle user actions 1`] = `
-Object {
- "active": "third",
-}
-`;
-
-exports[`should correclty handle user actions 2`] = `
-Object {
- "active": "item",
-}
-`;
-
-exports[`should correclty handle user actions 3`] = `
-Object {
- "active": "third",
-}
-`;
-
-exports[`should correclty handle user actions 4`] = `
-Array [
- Array [
- "third",
- ],
-]
-`;
-
exports[`should render correctly with children 1`] = `
<ul
className="menu"
diff --git a/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx b/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx
index 487bf13a6af..0c6a4ecfbd5 100644
--- a/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx
+++ b/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { KeyCodes } from '../../helpers/keycodes';
+import { KeyboardCodes } from '../../helpers/keycodes';
interface Props {
children: React.ReactNode;
@@ -37,7 +37,7 @@ export default class EscKeydownHandler extends React.Component<Props> {
}
handleKeyDown = (event: KeyboardEvent) => {
- if (event.keyCode === KeyCodes.Escape) {
+ if (event.code === KeyboardCodes.Escape) {
this.props.onKeydown();
}
};
diff --git a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx b/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
index 70c97cb3b12..d417471bae0 100644
--- a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
+++ b/server/sonar-web/src/main/js/components/controls/SearchBox.tsx
@@ -20,6 +20,7 @@
import classNames from 'classnames';
import { Cancelable, debounce } from 'lodash';
import * as React from 'react';
+import { KeyboardCodes } from '../../helpers/keycodes';
import { translate, translateWithParameters } from '../../helpers/l10n';
import SearchIcon from '../icons/SearchIcon';
import DeferredSpinner from '../ui/DeferredSpinner';
@@ -94,8 +95,7 @@ export default class SearchBox extends React.PureComponent<Props, State> {
};
handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
- if (event.keyCode === 27) {
- // escape
+ if (event.nativeEvent.code === KeyboardCodes.Escape) {
event.preventDefault();
this.handleResetClick();
}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/EscKeydownHandler-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/EscKeydownHandler-test.tsx
index 6c852477b81..de7f00a27b8 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/EscKeydownHandler-test.tsx
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/EscKeydownHandler-test.tsx
@@ -19,7 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { KeyCodes } from '../../../helpers/keycodes';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { keydown } from '../../../helpers/testUtils';
import EscKeydownHandler from '../EscKeydownHandler';
@@ -33,7 +33,7 @@ it('should correctly trigger the keydown handler when hitting Esc', () => {
const onKeydown = jest.fn();
shallowRender({ onKeydown });
jest.runAllTimers();
- keydown(KeyCodes.Escape);
+ keydown({ code: KeyboardCodes.Escape });
expect(onKeydown).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withKeyboardNavigation-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withKeyboardNavigation-test.tsx
index 22d907817b9..ac05b25a60f 100644
--- a/server/sonar-web/src/main/js/components/hoc/__tests__/withKeyboardNavigation-test.tsx
+++ b/server/sonar-web/src/main/js/components/hoc/__tests__/withKeyboardNavigation-test.tsx
@@ -19,6 +19,7 @@
*/
import { mount, shallow } from 'enzyme';
import * as React from 'react';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { mockComponent } from '../../../helpers/mocks/component';
import { KEYCODE_MAP, keydown } from '../../../helpers/testUtils';
import withKeyboardNavigation, { WithKeyboardNavigationProps } from '../withKeyboardNavigation';
@@ -43,7 +44,8 @@ const COMPONENTS = [
jest.mock('keymaster', () => {
const key: any = (bindKey: string, _: string, callback: Function) => {
document.addEventListener('keydown', (event: KeyboardEvent) => {
- if (bindKey.split(',').includes(KEYCODE_MAP[event.keyCode])) {
+ const keymasterCode = event.code && KEYCODE_MAP[event.code as KeyboardCodes];
+ if (keymasterCode && bindKey.split(',').includes(keymasterCode)) {
return callback();
}
return true;
@@ -78,28 +80,28 @@ it('should correctly bind key events for component navigation', () => {
})
);
- keydown('down');
+ keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[2]);
expect(onSelect).not.toBeCalled();
- keydown('up');
- keydown('up');
+ keydown({ code: KeyboardCodes.UpArrow });
+ keydown({ code: KeyboardCodes.UpArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[0]);
expect(onSelect).not.toBeCalled();
- keydown('up');
+ keydown({ code: KeyboardCodes.UpArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[2]);
- keydown('down');
+ keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[0]);
- keydown('right');
+ keydown({ code: KeyboardCodes.RightArrow });
expect(onSelect).toBeCalledWith(COMPONENTS[0]);
- keydown('enter');
+ keydown({ code: KeyboardCodes.Enter });
expect(onSelect).toBeCalledWith(COMPONENTS[0]);
- keydown('left');
+ keydown({ code: KeyboardCodes.LeftArrow });
expect(onGoToParent).toBeCalled();
});
@@ -116,18 +118,18 @@ it('should support not cycling through elements, and triggering a callback on re
})
);
- keydown('down');
+ keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[0]);
- keydown('down');
- keydown('down');
- keydown('down');
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
+ keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[2]);
expect(onEndOfList).toBeCalled();
- keydown('up');
- keydown('up');
- keydown('up');
- keydown('up');
+ keydown({ code: KeyboardCodes.UpArrow });
+ keydown({ code: KeyboardCodes.UpArrow });
+ keydown({ code: KeyboardCodes.UpArrow });
+ keydown({ code: KeyboardCodes.UpArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[0]);
});
@@ -148,19 +150,19 @@ it('should correctly bind key events for codeview navigation', () => {
expect(onHighlight).not.toBeCalled();
- keydown('down');
+ keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).not.toBeCalled();
- keydown('up');
+ keydown({ code: KeyboardCodes.UpArrow });
expect(onHighlight).not.toBeCalled();
- keydown('right');
+ keydown({ code: KeyboardCodes.RightArrow });
expect(onSelect).not.toBeCalled();
- keydown('enter');
+ keydown({ code: KeyboardCodes.Enter });
expect(onSelect).not.toBeCalled();
- keydown('left');
+ keydown({ code: KeyboardCodes.LeftArrow });
expect(onGoToParent).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/components/issue/popups/CommentPopup.tsx b/server/sonar-web/src/main/js/components/issue/popups/CommentPopup.tsx
index e03c28cb175..4481dacee72 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/CommentPopup.tsx
+++ b/server/sonar-web/src/main/js/components/issue/popups/CommentPopup.tsx
@@ -21,10 +21,11 @@ import * as React from 'react';
import { Button, ResetButtonLink } from '../../../components/controls/buttons';
import { DropdownOverlay } from '../../../components/controls/Dropdown';
import { PopupPlacement } from '../../../components/ui/popups';
+import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
import FormattingTips from '../../common/FormattingTips';
-interface Props {
+export interface CommentPopupProps {
comment?: Pick<T.IssueComment, 'markdown'>;
onComment: (text: string) => void;
toggleComment: (visible: boolean) => void;
@@ -37,8 +38,8 @@ interface State {
textComment: string;
}
-export default class CommentPopup extends React.PureComponent<Props, State> {
- constructor(props: Props) {
+export default class CommentPopup extends React.PureComponent<CommentPopupProps, State> {
+ constructor(props: CommentPopupProps) {
super(props);
this.state = {
textComment: props.comment ? props.comment.markdown : ''
@@ -60,10 +61,16 @@ export default class CommentPopup extends React.PureComponent<Props, State> {
};
handleKeyboard = (event: React.KeyboardEvent) => {
- if (event.keyCode === 13 && (event.metaKey || event.ctrlKey)) {
- // Ctrl + Enter
+ if (event.nativeEvent.code === KeyboardCodes.Enter && (event.metaKey || event.ctrlKey)) {
this.handleCommentClick();
- } else if ([37, 38, 39, 40].includes(event.keyCode)) {
+ } else if (
+ [
+ KeyboardCodes.UpArrow,
+ KeyboardCodes.DownArrow,
+ KeyboardCodes.LeftArrow,
+ KeyboardCodes.RightArrow
+ ].includes(event.nativeEvent.code as KeyboardCodes)
+ ) {
// Arrow keys
event.stopPropagation();
}
diff --git a/server/sonar-web/src/main/js/components/issue/popups/__tests__/CommentPopup-test.tsx b/server/sonar-web/src/main/js/components/issue/popups/__tests__/CommentPopup-test.tsx
index 3893fee0716..5de1a41accd 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/__tests__/CommentPopup-test.tsx
+++ b/server/sonar-web/src/main/js/components/issue/popups/__tests__/CommentPopup-test.tsx
@@ -19,53 +19,69 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { KeyboardCodes } from '../../../../helpers/keycodes';
+import { mockEvent } from '../../../../helpers/testMocks';
import { click } from '../../../../helpers/testUtils';
-import CommentPopup from '../CommentPopup';
+import CommentPopup, { CommentPopupProps } from '../CommentPopup';
it('should render the comment popup correctly without existing comment', () => {
- const element = shallow(
- <CommentPopup onComment={jest.fn()} placeholder="placeholder test" toggleComment={jest.fn()} />
- );
- expect(element).toMatchSnapshot();
+ expect(shallowRender()).toMatchSnapshot();
});
it('should render the comment popup correctly when changing a comment', () => {
- const element = shallow(
- <CommentPopup
- comment={{ markdown: '*test*' }}
- onComment={jest.fn()}
- placeholder=""
- toggleComment={jest.fn()}
- />
- );
- expect(element).toMatchSnapshot();
+ expect(shallowRender({ comment: { markdown: '*test*' } })).toMatchSnapshot();
});
it('should render not allow to send comment with only spaces', () => {
const onComment = jest.fn();
- const element = shallow(
- <CommentPopup onComment={onComment} placeholder="placeholder test" toggleComment={jest.fn()} />
- );
- click(element.find('.js-issue-comment-submit'));
+ const wrapper = shallowRender({ onComment });
+ click(wrapper.find('.js-issue-comment-submit'));
expect(onComment.mock.calls.length).toBe(0);
- element.setState({ textComment: 'mycomment' });
- click(element.find('.js-issue-comment-submit'));
+ wrapper.setState({ textComment: 'mycomment' });
+ click(wrapper.find('.js-issue-comment-submit'));
expect(onComment.mock.calls.length).toBe(1);
});
it('should render the alternative cancel button label', () => {
- const element = shallow(
- <CommentPopup
- autoTriggered={true}
- onComment={jest.fn()}
- placeholder=""
- toggleComment={jest.fn()}
- />
- );
+ const wrapper = shallowRender({ autoTriggered: true });
expect(
- element
+ wrapper
.find('.js-issue-comment-cancel')
.childAt(0)
.text()
).toBe('skip');
});
+
+it('should handle ctrl+enter', () => {
+ const onComment = jest.fn();
+ const wrapper = shallowRender({ comment: { markdown: 'yes' }, onComment });
+
+ wrapper
+ .instance()
+ .handleKeyboard(mockEvent({ ctrlKey: true, nativeEvent: { code: KeyboardCodes.Enter } }));
+
+ expect(onComment).toBeCalled();
+});
+
+it('should stopPropagation for arrow keys events', () => {
+ const wrapper = shallowRender();
+
+ const event = mockEvent({
+ nativeEvent: { code: KeyboardCodes.UpArrow },
+ stopPropagation: jest.fn()
+ });
+ wrapper.instance().handleKeyboard(event);
+
+ expect(event.stopPropagation).toBeCalled();
+});
+
+function shallowRender(overrides: Partial<CommentPopupProps> = {}) {
+ return shallow<CommentPopup>(
+ <CommentPopup
+ onComment={jest.fn()}
+ placeholder="placeholder test"
+ toggleComment={jest.fn()}
+ {...overrides}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/CommentPopup-test.tsx.snap b/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/CommentPopup-test.tsx.snap
index 9962424c1c3..9fc6c4cc228 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/CommentPopup-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/issue/popups/__tests__/__snapshots__/CommentPopup-test.tsx.snap
@@ -12,7 +12,7 @@ exports[`should render the comment popup correctly when changing a comment 1`] =
autoFocus={true}
onChange={[Function]}
onKeyDown={[Function]}
- placeholder=""
+ placeholder="placeholder test"
rows={2}
value="*test*"
/>
diff --git a/server/sonar-web/src/main/js/helpers/keycodes.ts b/server/sonar-web/src/main/js/helpers/keycodes.ts
index c57d397ae89..2976b56ae77 100644
--- a/server/sonar-web/src/main/js/helpers/keycodes.ts
+++ b/server/sonar-web/src/main/js/helpers/keycodes.ts
@@ -17,52 +17,25 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-export enum KeyCodes {
- LeftArrow = 37,
- UpArrow = 38,
- RightArrow = 39,
- DownArrow = 40,
-
- Alt = 18,
- Backspace = 8,
- CapsLock = 20,
- Command = 93,
- Ctrl = 17,
- Delete = 46,
- End = 35,
- Enter = 13,
- Escape = 27,
- Home = 36,
- PageDown = 34,
- PageUp = 33,
- Shift = 16,
- Space = 32,
- Tab = 9,
+export enum KeyboardCodes {
+ LeftArrow = 'ArrowLeft',
+ UpArrow = 'ArrowUp',
+ RightArrow = 'ArrowRight',
+ DownArrow = 'ArrowDown',
+ Backspace = 'Backspace',
+ CapsLock = 'CapsLock',
+ Command = 'ContextMenu',
+ Delete = 'Delete',
+ End = 'End',
+ Enter = 'Enter',
+ Escape = 'Escape',
+ Home = 'Home',
+ PageDown = 'PageDown',
+ PageUp = 'PageUp',
+ Space = 'Space',
+ Tab = 'Tab'
+}
- A = 65,
- B = 66,
- C = 67,
- D = 68,
- E = 69,
- F = 70,
- G = 71,
- H = 72,
- I = 73,
- J = 74,
- K = 75,
- L = 76,
- M = 77,
- N = 78,
- O = 79,
- P = 80,
- Q = 81,
- R = 82,
- S = 83,
- T = 84,
- U = 85,
- V = 86,
- W = 87,
- X = 88,
- Y = 89,
- Z = 90
+export enum KeyboardKeys {
+ Alt = 'Alt'
}
diff --git a/server/sonar-web/src/main/js/helpers/testUtils.ts b/server/sonar-web/src/main/js/helpers/testUtils.ts
index 9a7b019eef1..32fa9d709bd 100644
--- a/server/sonar-web/src/main/js/helpers/testUtils.ts
+++ b/server/sonar-web/src/main/js/helpers/testUtils.ts
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { ReactWrapper, ShallowWrapper } from 'enzyme';
+import { KeyboardCodes, KeyboardKeys } from './keycodes';
export function mockEvent(overrides = {}) {
return {
@@ -68,37 +69,26 @@ export function change(element: ShallowWrapper | ReactWrapper, value: string, ev
}
}
-export const KEYCODE_MAP: { [keycode: number]: string } = {
- 13: 'enter',
- 37: 'left',
- 38: 'up',
- 39: 'right',
- 40: 'down'
+export const KEYCODE_MAP: { [code in KeyboardCodes]?: string } = {
+ [KeyboardCodes.Enter]: 'enter',
+ [KeyboardCodes.LeftArrow]: 'left',
+ [KeyboardCodes.UpArrow]: 'up',
+ [KeyboardCodes.RightArrow]: 'right',
+ [KeyboardCodes.DownArrow]: 'down'
};
-export function keydown(key: number | string): void {
- let keyCode;
- if (typeof key === 'number') {
- keyCode = key;
- } else {
- // eslint-disable-next-line no-console
- console.warn('Using strings in keydown() is deprecated. Consider using the KeyCodes enum.');
- const mapped = Object.entries(KEYCODE_MAP).find(([_, value]) => value === key);
- if (!mapped) {
- throw new Error(`Cannot map key "${key}" to a keyCode!`);
- }
- keyCode = mapped[0];
- }
-
- const event = new KeyboardEvent('keydown', { keyCode, which: keyCode } as KeyboardEventInit);
+export function keydown(args: { code?: KeyboardCodes; key?: KeyboardKeys }): void {
+ const event = new KeyboardEvent('keydown', args as KeyboardEventInit);
document.dispatchEvent(event);
}
-export function elementKeydown(element: ShallowWrapper, keyCode: number): void {
+export function elementKeydown(element: ShallowWrapper, code: KeyboardCodes): void {
const event = {
currentTarget: { element },
- keyCode,
- preventDefault() {}
+ nativeEvent: { code },
+ preventDefault() {
+ /*noop*/
+ }
};
if (typeof element.type() === 'string') {