pgadmin4/web/regression/javascript/history/query_history_spec.js
2021-01-04 15:34:45 +05:30

406 lines
14 KiB
JavaScript

/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
/* eslint-disable react/no-find-dom-node */
import QueryHistory from 'sources/sqleditor/history/query_history';
import HistoryCollection from 'sources/sqleditor/history/history_collection';
import clipboard from 'sources/selection/clipboard';
import $ from 'jquery';
import moment from 'moment';
describe('QueryHistory', () => {
let historyCollection;
let historyWrapper;
let historyComponent;
beforeEach(() => {
historyWrapper = $('<div id="history_grid"></div>').appendTo('body');
});
describe('when there is no history', () => {
beforeEach(() => {
historyCollection = new HistoryCollection([]);
historyComponent = new QueryHistory(historyWrapper, historyCollection);
historyComponent.render();
});
it('has no entries', (done) => {
let foundChildren = historyWrapper.find('#query_list');
expect(foundChildren.length).toBe(0);
done();
});
it('No history found is displayed', (done) => {
expect(historyWrapper.find('.pg-panel-message').html()).toBe('No history found');
done();
});
});
describe('when there is history', () => {
let queryEntries;
let queryDetail;
describe('when two SQL queries were executed', () => {
beforeEach(() => {
const historyObjects = [{
query: 'first sql statement',
start_time: new Date(2017, 5, 3, 14, 3, 15, 150),
status: true,
row_affected: 12345,
total_time: '14 msec',
message: 'something important ERROR: message from first sql query',
}, {
query: 'second sql statement',
start_time: new Date(2016, 11, 11, 1, 33, 5, 99),
status: false,
row_affected: 1,
total_time: '234 msec',
message: 'something important ERROR: message from second sql query',
}];
historyCollection = new HistoryCollection(historyObjects);
historyComponent = new QueryHistory(historyWrapper, historyCollection);
historyComponent.onCopyToEditorClick(()=>{});
historyComponent.render();
queryEntries = historyWrapper.find('#query_list .list-item');
queryDetail = historyWrapper.find('#query_detail');
});
describe('the history entries panel', () => {
it('has two query history entries', (done) => {
expect(queryEntries.length).toBe(2);
done();
});
it('displays the query history entries in order', () => {
expect($(queryEntries[0]).text()).toContain('first sql statement');
expect($(queryEntries[1]).text()).toContain('second sql statement');
});
it('displays the formatted timestamp of the queries in chronological order by most recent first', () => {
expect($(queryEntries[0]).find('.timestamp').text()).toBe('14:03:15');
expect($(queryEntries[1]).find('.timestamp').text()).toBe('01:33:05');
});
it('renders the most recent query as selected', (done) => {
expect($(queryEntries[0]).hasClass('selected')).toBeTruthy();
done();
});
it('renders the older query as not selected', () => {
expect($(queryEntries[1]).hasClass('selected')).toBeFalsy();
expect($(queryEntries[1]).find('.entry').hasClass('error')).toBeTruthy();
});
});
describe('the historydetails panel', () => {
let copyAllButton, copyEditorButton;
beforeEach(() => {
copyAllButton = () => queryDetail.find('#history-detail-query .btn-copy');
copyEditorButton = () => queryDetail.find('#history-detail-query .btn-copy-editor');
});
it('should change preference font size', ()=>{
historyComponent.setEditorPref({sql_font_size: '1.5em'});
expect(queryDetail.find('#history-detail-query .CodeMirror').attr('style')).toBe('font-size: 1.5em;');
});
it('should change preference copy to editor false', ()=>{
historyComponent.setEditorPref({copy_to_editor: false});
expect($(queryDetail.find('#history-detail-query .btn-copy-editor')).hasClass('d-none')).toBe(true);
});
it('displays the formatted timestamp', () => {
let firstDate = new Date(2017, 5, 3, 14, 3, 15, 150);
expect(queryDetail.text()).toContain(firstDate.toLocaleDateString() + ' ' + firstDate.toLocaleTimeString());
});
it('displays the number of rows affected', () => {
if (/PhantomJS/.test(window.navigator.userAgent)) {
expect(queryDetail.text()).toContain('12345');
} else {
expect(queryDetail.text()).toContain('12,345');
}
});
it('displays the total time', () => {
expect(queryDetail.text()).toContain('14 msec');
});
it('displays the full message', () => {
expect(queryDetail.text()).toContain('message from first sql query');
});
it('displays first query SQL', (done) => {
setTimeout(() => {
expect(queryDetail.text()).toContain('first sql statement');
done();
}, 1000);
});
describe('when the "Copy" button is clicked', () => {
beforeEach(() => {
spyOn(clipboard, 'copyTextToClipboard');
copyAllButton().trigger('click');
});
it('copies the query to the clipboard', () => {
expect(clipboard.copyTextToClipboard).toHaveBeenCalledWith('first sql statement');
});
});
describe('Copy button', () => {
beforeEach(() => {
jasmine.clock().install();
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('should have text \'Copy\'', () => {
expect(copyAllButton().text()).toBe('Copy');
});
it('should not have the class \'was-copied\'', () => {
expect(copyAllButton().hasClass('was-copied')).toBe(false);
});
describe('when the copy button is clicked', () => {
beforeEach(() => {
copyAllButton().trigger('click');
});
describe('before 1.5 seconds', () => {
beforeEach(() => {
jasmine.clock().tick(1499);
});
it('should change the button text to \'Copied!\'', () => {
expect(copyAllButton().text()).toBe('Copied!');
});
it('should have the class \'was-copied\'', () => {
expect(copyAllButton().hasClass('was-copied')).toBe(true);
});
});
describe('after 1.5 seconds', () => {
beforeEach(() => {
jasmine.clock().tick(1501);
});
it('should change the button text back to \'Copy\'', () => {
expect(copyAllButton().text()).toBe('Copy');
});
});
describe('when is clicked again after 1s', () => {
beforeEach(() => {
jasmine.clock().tick(1000);
copyAllButton().trigger('click');
});
describe('before 2.5 seconds', () => {
beforeEach(() => {
jasmine.clock().tick(1499);
});
it('should change the button text to \'Copied!\'', () => {
expect(copyAllButton().text()).toBe('Copied!');
});
it('should have the class \'was-copied\'', () => {
expect(copyAllButton().hasClass('was-copied')).toBe(true);
});
});
describe('after 2.5 seconds', () => {
beforeEach(() => {
jasmine.clock().tick(1501);
});
it('should change the button text back to \'Copy\'', () => {
expect(copyAllButton().text()).toBe('Copy');
});
});
});
});
});
describe('when the "Copy to query editor" button is clicked', () => {
beforeEach(() => {
spyOn(historyComponent.queryHistDetails, 'onCopyToEditorHandler').and.callThrough();
copyEditorButton().trigger('click');
});
it('sends the query to the onCopyToEditorHandler', () => {
expect(historyComponent.queryHistDetails.onCopyToEditorHandler).toHaveBeenCalledWith('first sql statement');
});
});
describe('when the query failed', () => {
let failedEntry;
beforeEach(() => {
failedEntry = $(queryEntries[1]);
failedEntry.trigger('click');
});
it('displays the error message on top of the details pane', () => {
expect(queryDetail.text()).toContain('Error Message message from second sql query');
});
});
});
describe('when the older query is clicked on', () => {
let firstEntry, secondEntry;
beforeEach(() => {
firstEntry = $(queryEntries[0]);
secondEntry = $(queryEntries[1]);
secondEntry.trigger('click');
});
it('displays the query in the right pane', () => {
expect(queryDetail.text()).toContain('second sql statement');
});
it('deselects the first history entry', () => {
expect(firstEntry.hasClass('selected')).toBeFalsy();
});
it('selects the second history entry', () => {
expect(secondEntry.hasClass('selected')).toBeTruthy();
});
});
describe('when a third SQL query is executed', () => {
beforeEach(() => {
historyCollection.add({
query: 'third sql statement',
start_time: new Date(2017, 11, 11, 1, 33, 5, 99),
status: false,
row_affected: 5,
total_time: '26 msec',
message: 'pretext ERROR: third sql message',
});
queryEntries = historyWrapper.find('#query_list .list-item');
});
it('displays third query SQL in the right pane', () => {
expect(queryDetail.text()).toContain('third sql statement');
});
});
describe('when a fourth SQL query is executed', () => {
beforeEach(() => {
historyCollection.add({
query: 'fourth sql statement',
start_time: new Date(2017, 12, 12, 1, 33, 5, 99),
status: false,
row_affected: 0,
total_time: '26 msec',
message: 'ERROR: unexpected error from fourth sql message',
});
queryEntries = historyWrapper.find('#query_list .list-item');
});
it('displays fourth query SQL in the right pane', () => {
expect(queryDetail.text()).toContain('Error Message unexpected error from fourth sql message');
});
});
});
describe('when several days of queries were executed', () => {
let queryEntryDateGroups;
let dateToday, dateYest, dateBeforeYest;
beforeEach(() => {
jasmine.clock().install();
const mockedCurrentDate = moment('2017-07-01 13:30:00');
jasmine.clock().mockDate(mockedCurrentDate.toDate());
dateToday = mockedCurrentDate.toDate();
dateYest = mockedCurrentDate.clone().subtract(1, 'days').toDate();
dateBeforeYest = mockedCurrentDate.clone().subtract(3, 'days').toDate();
const historyObjects = [{
query: 'first today sql statement',
start_time: mockedCurrentDate.toDate(),
status: true,
row_affected: 12345,
total_time: '14 msec',
message: 'message from first today sql query',
}, {
query: 'second today sql statement',
start_time: mockedCurrentDate.clone().subtract(1, 'hours').toDate(),
status: false,
row_affected: 1,
total_time: '234 msec',
message: 'message from second today sql query',
}, {
query: 'first yesterday sql statement',
start_time: mockedCurrentDate.clone().subtract(1, 'days').toDate(),
status: true,
row_affected: 12345,
total_time: '14 msec',
message: 'message from first yesterday sql query',
}, {
query: 'second yesterday sql statement',
start_time: mockedCurrentDate.clone().subtract(1, 'days').subtract(1, 'hours').toDate(),
status: false,
row_affected: 1,
total_time: '234 msec',
message: 'message from second yesterday sql query',
}, {
query: 'older than yesterday sql statement',
start_time: mockedCurrentDate.clone().subtract(3, 'days').toDate(),
status: true,
row_affected: 12345,
total_time: '14 msec',
message: 'message from older than yesterday sql query',
}];
historyCollection = new HistoryCollection(historyObjects);
historyComponent = new QueryHistory(historyWrapper, historyCollection);
historyComponent.render();
queryEntries = historyWrapper.find('#query_list .list-item');
queryEntryDateGroups = historyWrapper.find('#query_list .query-group');
});
afterEach(() => {
jasmine.clock().uninstall();
});
describe('the history entries panel', () => {
it('has three query history entry data groups', () => {
expect(queryEntryDateGroups.length).toBe(3);
});
it('has title above', () => {
expect($(queryEntryDateGroups[0]).find('.date-label').text()).toBe('Today - ' + dateToday.toLocaleDateString());
expect($(queryEntryDateGroups[1]).find('.date-label').text()).toBe('Yesterday - ' + dateYest.toLocaleDateString());
expect($(queryEntryDateGroups[2]).find('.date-label').text()).toBe(dateBeforeYest.toLocaleDateString());
});
});
});
});
});