////////////////////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////////////////// import * as keyboardShortcuts from 'sources/keyboard_shortcuts'; import {queryToolActions} from 'sources/sqleditor/query_tool_actions'; import gettext from 'sources/gettext'; describe('the keyboard shortcuts', () => { const F1_KEY = 112, F5_KEY = 116, F6_KEY = 117, F7_KEY = 118, F8_KEY = 119, PERIOD_KEY = 190, FWD_SLASH_KEY = 191, C1_KEY = 49; let sqlEditorControllerSpy, event, queryToolActionsSpy; beforeEach(() => { event = { shift: false, which: undefined, preventDefault: jasmine.createSpy('preventDefault'), cancelBubble: false, stopPropagation: jasmine.createSpy('stopPropagation'), stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation'), }; let gridView = { query_tool_obj: { getSelection: jasmine.createSpy('getSelection'), getValue: jasmine.createSpy('getValue'), }, }; sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ 'isQueryRunning', 'execute', ]); sqlEditorControllerSpy.gridView = gridView; sqlEditorControllerSpy.preferences = { execute_query: { alt: false, shift: false, control: false, key: { key_code: F5_KEY, }, }, explain_query: { alt: false, shift: false, control: false, key: { key_code: F7_KEY, }, }, explain_analyze_query: { alt: false, shift: true, control: false, key: { key_code: F7_KEY, }, }, download_results: { alt: false, shift: false, control: false, key: { key_code: F8_KEY, }, }, move_next: { alt: false, shift: false, control: false, key: { key_code: null, }, }, move_previous: { alt: false, shift: false, control: false, key: { key_code: null, }, }, commit_transaction: { alt: false, shift: true, control: true, key: { key_code: 'm', }, }, rollback_transaction: { alt: false, shift: true, control: true, key: { key_code: 'r', }, }, save_data: { alt : false, shift: false, control: false, key: { key_code: F6_KEY, }, }, }; sqlEditorControllerSpy.macros = [ { alt: false, control: true, id: 1, key: '1', key_code: C1_KEY, key_label: 'Ctrl + 1', name: 'C1', sql: 'Select 1;', }, ]; queryToolActionsSpy = jasmine.createSpyObj(queryToolActions, [ 'explainAnalyze', 'explain', 'download', 'commentBlockCode', 'commentLineCode', 'uncommentLineCode', 'executeQuery', 'executeCommit', 'executeRollback', 'saveDataChanges', 'executeMacro', ]); }); describe('when the key is not handled by the function', function () { beforeEach(() => { event.which = F1_KEY; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should allow event to propagate', () => { expect(event.preventDefault).not.toHaveBeenCalled(); }); }); describe('F5', () => { describe('when there is no query already running', () => { beforeEach(() => { event.keyCode = F5_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should execute the query', () => { expect(queryToolActionsSpy.executeQuery).toHaveBeenCalledWith(sqlEditorControllerSpy); }); it('should stop event propagation', () => { expect(event.preventDefault).toHaveBeenCalled(); }); }); describe('when the query is already running', () => { it('does nothing', () => { event.keyCode = F5_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeQuery).not.toHaveBeenCalled(); }); }); }); describe('F6', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.which = F6_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should save the changed data', () => { expect(queryToolActionsSpy.saveDataChanges).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('when the query is already running', () => { it('does nothing', () => { event.keyCode = F6_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.saveDataChanges).not.toHaveBeenCalled(); }); }); }); describe('F7', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.which = F7_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should explain the query plan', () => { expect(queryToolActionsSpy.explain).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('when the query is already running', () => { it('does nothing', () => { event.keyCode = F7_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explain).not.toHaveBeenCalled(); }); }); }); describe('Shift+F7', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.shiftKey = true; event.which = F7_KEY; event.altKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should analyze explain the query plan', () => { expect(queryToolActionsSpy.explainAnalyze).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('when the query is already running', () => { it('does nothing', () => { event.shiftKey = true; event.which = F7_KEY; event.altKey = false; event.ctrlKey = false; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explainAnalyze).not.toHaveBeenCalled(); }); }); }); describe('F8', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.which = F8_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should download the query results as a CSV', () => { expect(queryToolActionsSpy.download).toHaveBeenCalled(); }); it('should stop event propagation', () => { expect(event.preventDefault).toHaveBeenCalled(); }); }); describe('when the query is already running', () => { it('does nothing', () => { event.keyCode = F8_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = false; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.download).not.toHaveBeenCalled(); }); }); }); describe('inlineComment', () => { describe('when there is not a query already running', () => { describe('and the system is a Mac', () => { beforeEach(() => { macKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should comment the line', () => { expect(queryToolActionsSpy.commentLineCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('and the system is Windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should comment the line', () => { expect(queryToolActionsSpy.commentLineCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); }); describe('when the query is already running', () => { beforeEach(() => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); }); describe('and the system is a Mac', () => { beforeEach(() => { macKeysSetup(); event.which = FWD_SLASH_KEY; }); it('does nothing', () => { keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); }); }); describe('and the system is a Windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; }); it('does nothing', () => { keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); }); }); }); }); describe('inlineUncomment', () => { describe('when there is not a query already running', () => { describe('and the system is a mac', () => { beforeEach(() => { macKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should uncomment the line', () => { expect(queryToolActionsSpy.uncommentLineCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('and the system is a windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should uncomment the line', () => { expect(queryToolActionsSpy.uncommentLineCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); }); describe('when the query is already running', () => { beforeEach(() => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); }); describe('and the system is a Mac', () => { beforeEach(() => { macKeysSetup(); event.which = PERIOD_KEY; }); it('does nothing', () => { keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); }); }); describe('and the system is a Windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = PERIOD_KEY; }); it('does nothing', () => { keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); }); }); }); }); describe('blockComment', () => { describe('when there is not a query already running', () => { describe('and the system is a Mac', () => { beforeEach(() => { macKeysSetup(); event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should comment out the block selection', () => { expect(queryToolActionsSpy.commentBlockCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); }); describe('when there is not a query already running', () => { describe('and the system is a Windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should comment out the block selection', () => { expect(queryToolActionsSpy.commentBlockCode).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); }); describe('when there is a query already running', () => { beforeEach(() => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); }); describe('and the system is a Mac', () => { beforeEach(() => { macKeysSetup(); event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { expect(queryToolActionsSpy.commentBlockCode).not.toHaveBeenCalled(); }); }); describe('and the system is a Windows', () => { beforeEach(() => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { expect(queryToolActionsSpy.commentBlockCode).not.toHaveBeenCalled(); }); }); }); }); describe('shortcut to text converters', ()=> { var shortcut = { alt: false, shift: false, control: false, key: { char: 'a', key_code: 65, }, }; it('shortcut_key',()=>{ expect(keyboardShortcuts.shortcut_key(shortcut)).toEqual('A'); }); it('shortcut_accesskey_title',()=>{ expect(keyboardShortcuts.shortcut_accesskey_title( 'Title', shortcut)).toEqual(gettext('Title (accesskey + A)')); }); it('shortcut_title',()=>{ shortcut.alt = true; shortcut.shift = false; shortcut.control = false; expect(keyboardShortcuts.shortcut_title( 'Title', shortcut)).toEqual(gettext('Title (Alt+A)')); shortcut.alt = false; shortcut.shift = true; shortcut.control = false; expect(keyboardShortcuts.shortcut_title( 'Title', shortcut)).toEqual(gettext('Title (Shift+A)')); shortcut.alt = false; shortcut.shift = false; shortcut.control = true; expect(keyboardShortcuts.shortcut_title( 'Title', shortcut)).toEqual(gettext('Title (Ctrl+A)')); shortcut.alt = true; shortcut.shift = true; shortcut.control = true; expect(keyboardShortcuts.shortcut_title( 'Title', shortcut)).toEqual(gettext('Title (Alt+Shift+Ctrl+A)')); }); }); describe('Shift+Ctrl+C', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.shiftKey = true; event.which = 'm'; event.altKey = false; event.ctrlKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should commit the transaction', () => { expect(queryToolActionsSpy.executeCommit).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('when the query is already running', () => { it('does nothing', () => { event.shiftKey = true; event.which = 'm'; event.altKey = false; event.ctrlKey = true; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeCommit).not.toHaveBeenCalled(); }); }); }); describe('Shift+Ctrl+R', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.shiftKey = true; event.which = 'r'; event.altKey = false; event.ctrlKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should rollback the transaction', () => { expect(queryToolActionsSpy.executeRollback).toHaveBeenCalledWith(sqlEditorControllerSpy); }); expectEventPropagationToStop(); }); describe('when the query is already running', () => { it('does nothing', () => { event.shiftKey = true; event.which = 'r'; event.altKey = false; event.ctrlKey = true; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeRollback).not.toHaveBeenCalled(); }); }); }); describe('Macro Ctrl + 1', () => { describe('when there is not a query already running', () => { beforeEach(() => { event.which = C1_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = true; keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('should execute the macro', () => { expect(queryToolActionsSpy.executeMacro).toHaveBeenCalledWith(sqlEditorControllerSpy, sqlEditorControllerSpy.macros[0].id); }); it('should stop event propagation', () => { expect(event.preventDefault).toHaveBeenCalled(); }); }); describe('when the query is already running', () => { it('does nothing', () => { event.keyCode = C1_KEY; event.altKey = false; event.shiftKey = false; event.ctrlKey = true; sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeMacro).not.toHaveBeenCalled(); }); }); }); function expectEventPropagationToStop() { describe('stops all event propogation', () => { it('should cancel the bubble', () => { expect(event.cancelBubble).toEqual(true); }); it('should prevent the default behavior', () => { expect(event.preventDefault).toHaveBeenCalled(); }); it('should stop event propagation', () => { expect(event.stopPropagation).toHaveBeenCalled(); expect(event.stopImmediatePropagation).toHaveBeenCalled(); }); }); } function windowsKeysSetup() { spyOn(keyboardShortcuts, 'isMac').and.returnValue(false); event.ctrlKey = true; event.metaKey = false; } function macKeysSetup() { spyOn(keyboardShortcuts, 'isMac').and.returnValue(true); event.ctrlKey = false; event.metaKey = true; } });