123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import {reactHooks} from 'sentry-test/reactTestingLibrary';
- import {getKeyCode} from 'sentry/utils/getKeyCode';
- import {useHotkeys} from 'sentry/utils/useHotkeys';
- describe('useHotkeys', function () {
- let events: Record<string, (evt: EventListenerOrEventListenerObject) => void> = {};
- function makeKeyEventFixture(keyCode, options) {
- return {
- keyCode: getKeyCode(keyCode),
- preventDefault: jest.fn(),
- ...options,
- };
- }
- beforeEach(() => {
- // Empty our events before each test case
- events = {};
- // Define the addEventListener method with a Jest mock function
- // @ts-expect-error we are overriding the global document object
- document.addEventListener = jest.fn((event: string, callback: () => any) => {
- events[event] = callback;
- });
- document.removeEventListener = jest.fn(event => {
- delete events[event];
- });
- });
- it('handles a simple match', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: 'ctrl+s', callback}],
- });
- expect(events.keydown).toBeDefined();
- expect(callback).not.toHaveBeenCalled();
- const evt = makeKeyEventFixture('s', {ctrlKey: true});
- events.keydown(evt);
- expect(evt.preventDefault).toHaveBeenCalled();
- expect(callback).toHaveBeenCalled();
- });
- it('handles multiple matches', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: ['ctrl+s', 'command+m'], callback}],
- });
- expect(events.keydown).toBeDefined();
- expect(callback).not.toHaveBeenCalled();
- events.keydown(makeKeyEventFixture('s', {ctrlKey: true}));
- expect(callback).toHaveBeenCalled();
- callback.mockClear();
- events.keydown(makeKeyEventFixture('m', {metaKey: true}));
- expect(callback).toHaveBeenCalled();
- });
- it('handles a complex match', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: ['command+ctrl+alt+shift+x'], callback}],
- });
- expect(events.keydown).toBeDefined();
- expect(callback).not.toHaveBeenCalled();
- events.keydown(
- makeKeyEventFixture('x', {
- altKey: true,
- metaKey: true,
- shiftKey: true,
- ctrlKey: true,
- })
- );
- expect(callback).toHaveBeenCalled();
- });
- it('does not match when extra modifiers are pressed', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: ['command+shift+x'], callback}],
- });
- expect(events.keydown).toBeDefined();
- expect(callback).not.toHaveBeenCalled();
- events.keydown(
- makeKeyEventFixture('x', {
- altKey: true,
- metaKey: true,
- shiftKey: true,
- ctrlKey: true,
- })
- );
- expect(callback).not.toHaveBeenCalled();
- });
- it('updates with rerender', function () {
- const callback = jest.fn();
- const {rerender} = reactHooks.renderHook(
- p => useHotkeys([{match: p.match, callback}], [p]),
- {
- initialProps: {match: 'ctrl+s'},
- }
- );
- expect(events.keydown).toBeDefined();
- expect(callback).not.toHaveBeenCalled();
- events.keydown(makeKeyEventFixture('s', {ctrlKey: true}));
- expect(callback).toHaveBeenCalled();
- callback.mockClear();
- rerender({match: 'command+m'});
- events.keydown(makeKeyEventFixture('s', {ctrlKey: true}));
- expect(callback).not.toHaveBeenCalled();
- events.keydown(makeKeyEventFixture('m', {metaKey: true}));
- expect(callback).toHaveBeenCalled();
- });
- it('skips input and textarea', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: ['/'], callback}],
- });
- events.keydown(makeKeyEventFixture('/', {target: document.createElement('input')}));
- expect(callback).not.toHaveBeenCalled();
- });
- it('does not skips input and textarea with includesInputs', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: ['/'], callback, includeInputs: true}],
- });
- events.keydown(makeKeyEventFixture('/', {target: document.createElement('input')}));
- expect(callback).toHaveBeenCalled();
- });
- it('skips preventDefault', function () {
- const callback = jest.fn();
- reactHooks.renderHook(p => useHotkeys(p, []), {
- initialProps: [{match: 'ctrl+s', callback, skipPreventDefault: true}],
- });
- const evt = makeKeyEventFixture('s', {ctrlKey: true});
- events.keydown(evt);
- expect(evt.preventDefault).not.toHaveBeenCalled();
- expect(callback).toHaveBeenCalled();
- });
- });
|