diff --git a/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx b/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx index a28f6be69c..5f3b0b61d7 100644 --- a/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx +++ b/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx @@ -49,6 +49,7 @@ const MonitorConfig = ({ retryDelay = 10000 } : IProps) => { const newSocket = io(`${getBaseApiUrl()}/monitor`, { forceNew: true, query: { instanceId }, + rejectUnauthorized: false, }) dispatch(setSocket(newSocket)) let payloads: IMonitorDataPayload[] = [] diff --git a/redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx b/redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx index 51c46fe9be..92a2dd0005 100644 --- a/redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx +++ b/redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx @@ -62,7 +62,7 @@ const Monitor = (props: Props) => { /> - + Running Profiler will decrease throughput, avoid running it in production databases diff --git a/tests/e2e/helpers/conf.ts b/tests/e2e/helpers/conf.ts index 949cd09ee9..47e5c8d48f 100644 --- a/tests/e2e/helpers/conf.ts +++ b/tests/e2e/helpers/conf.ts @@ -1,3 +1,6 @@ +import { Chance } from 'chance'; +const chance = new Chance(); + // Urls for using in the tests export const commonUrl = process.env.COMMON_URL || 'https://localhost:5000'; @@ -52,3 +55,10 @@ export const invalidOssStandaloneConfig = { databaseUsername: process.env.OSS_STANDALONE_USERNAME, databasePassword: process.env.OSS_STANDALONE_PASSWORD }; +export const ossBigStandaloneConfig = { + host: process.env.OSS_STANDALONE_BIG_HOST || 'oss-standalone-big', + port: process.env.OSS_STANDALONE_BIG_PORT || '6379', + databaseName: process.env.OSS_STANDALONE_BIG_DATABASE_NAME || chance.string({ length: 20 }), + databaseUsername: process.env.OSS_STANDALONE_BIG_USERNAME, + databasePassword: process.env.OSS_STANDALONE_BIG_PASSWORD +}; diff --git a/tests/e2e/pageObjects/cli-page.ts b/tests/e2e/pageObjects/cli-page.ts index 455acf78ba..5fcaa9440e 100644 --- a/tests/e2e/pageObjects/cli-page.ts +++ b/tests/e2e/pageObjects/cli-page.ts @@ -91,11 +91,11 @@ export class CliPage { } /** - * Add keys from CLI - * @param keyCommand The command from cli to add key - * @param amount The amount of the keys - * @param keyName The name of the keys. The default value is keyName - */ + * Add keys from CLI + * @param keyCommand The command from cli to add key + * @param amount The amount of the keys + * @param keyName The name of the keys. The default value is keyName + */ async addKeysFromCli(keyCommand: string, amount: number, keyName = 'keyName'): Promise{ //Open CLI await t.click(this.cliExpandButton); @@ -105,4 +105,18 @@ export class CliPage { await t.pressKey('enter'); await t.click(this.cliCollapseButton); } + /** + * Get command result execution + * @param command The command for send in CLI + */ + async getSuccessCommandResultFromCli(command: string): Promise{ + //Open CLI + await t.click(this.cliExpandButton); + //Add keys + await t.typeText(this.cliCommandInput, command, { paste: true }); + await t.pressKey('enter'); + const commandResult = await this.cliOutputResponseSuccess.innerText; + await t.click(this.cliCollapseButton); + return commandResult; + } } diff --git a/tests/e2e/pageObjects/index.ts b/tests/e2e/pageObjects/index.ts index e77f470a2a..1810472707 100644 --- a/tests/e2e/pageObjects/index.ts +++ b/tests/e2e/pageObjects/index.ts @@ -9,6 +9,7 @@ import { WorkbenchPage } from './workbench-page'; import { DatabaseOverviewPage } from './database-overview-page'; import { HelpCenterPage } from './help-center-page'; import { ShortcutsPage } from './shortcuts-page'; +import { MonitorPage } from './monitor-page'; export { AddRedisDatabasePage, @@ -21,5 +22,6 @@ export { WorkbenchPage, DatabaseOverviewPage, HelpCenterPage, - ShortcutsPage + ShortcutsPage, + MonitorPage } diff --git a/tests/e2e/pageObjects/monitor-page.ts b/tests/e2e/pageObjects/monitor-page.ts new file mode 100644 index 0000000000..a2b24380d4 --- /dev/null +++ b/tests/e2e/pageObjects/monitor-page.ts @@ -0,0 +1,76 @@ +import {Selector, t} from 'testcafe'; + +export class MonitorPage { + + //------------------------------------------------------------------------------------------ + //DECLARATION OF TYPES: DOM ELEMENTS and UI COMPONENTS + //*Assign the 'Selector' type to any element/component nested within the constructor. + //------------------------------------------------------------------------------------------ + + expandMonitor: Selector + monitorArea: Selector + runMonitorToggle: Selector + startMonitorButton: Selector + clearMonitorButton: Selector + monitorIsStoppedText: Selector + monitorIsStartedText: Selector + hideMonitor: Selector + closeMonitor: Selector + monitorWarningMessage: Selector + monitorCommandLinePart: Selector + monitorCommandLineTimestamp: Selector + + constructor() { + //------------------------------------------------------------------------------------------- + //DECLARATION OF SELECTORS + //*Declare all elements/components of the relevant page. + //*Target any element/component via data-id, if possible! + //*The following categories are ordered alphabetically (Alerts, Buttons, Checkboxes, etc.). + //------------------------------------------------------------------------------------------- + //BUTTONS + this.expandMonitor = Selector('[data-testid=expand-monitor]'); + this.monitorArea = Selector('[data-testid=monitor]'); + this.runMonitorToggle = Selector('[data-testid=toggle-run-monitor]'); + this.startMonitorButton = Selector('[data-testid=start-monitor]'); + this.clearMonitorButton = Selector('[data-testid=clear-monitor]'); + this.monitorIsStoppedText = Selector('[data-testid=monitor-stopped]'); + this.monitorIsStartedText = Selector('[data-testid=monitor-started]'); + this.hideMonitor = Selector('[data-testid=hide-monitor]'); + this.closeMonitor = Selector('[data-testid=close-monitor]'); + this.monitorWarningMessage = Selector('[data-testid=monitor-warning-message]'); + this.monitorCommandLinePart = Selector('[data-testid=monitor] span'); + this.monitorCommandLineTimestamp = Selector('[data-testid=monitor] span').withText(/[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}/); + } + /** + * Check specific command in Monitor + * @param command A command which should be displayed in monitor + * @param parameters An arguments which should be displayed in monitor + */ + async checkCommandInMonitorResults(command: string, parameters?: string[]): Promise { + const commandArray = command.split(' '); + for (const value of commandArray) { + await t.expect(this.monitorCommandLinePart.withText(value).exists).ok({timeout: 6000}); + } + if (!!parameters) { + for (const argument of parameters) { + await t.expect(this.monitorCommandLinePart.withText(argument).exists).ok({timeout: 6000}); + } + } + } + /** + * Start monitor function + */ + async startMonitor(): Promise { + await t.click(this.expandMonitor); + await t.click(this.startMonitorButton); + //Check for "info" command that is sent automatically every 5 seconds from BE side + await this.checkCommandInMonitorResults('info'); + } + /** + * Stop monitor function + */ + async stopMonitor(): Promise { + await t.click(this.runMonitorToggle); + await t.expect(this.monitorIsStoppedText.exists).ok('Profiler is stopped text'); + } +} diff --git a/tests/e2e/pageObjects/my-redis-databases-page.ts b/tests/e2e/pageObjects/my-redis-databases-page.ts index 30737ccbb4..ef92de99cb 100644 --- a/tests/e2e/pageObjects/my-redis-databases-page.ts +++ b/tests/e2e/pageObjects/my-redis-databases-page.ts @@ -83,7 +83,7 @@ export class MyRedisDatabasePage { const count = await dbNames.count; for(let i = 0; i < count; i++) { - if((await dbNames.nth(1).innerText || '').includes(dbName)) { + if((await dbNames.nth(i).innerText || '').includes(dbName)) { await t.click(this.deleteDatabaseButton.nth(i)); await t.click(this.confirmDeleteButton); break; diff --git a/tests/e2e/tests/critical-path/cli/cli-command-helper.e2e.ts b/tests/e2e/tests/critical-path/cli/cli-command-helper.e2e.ts index 6f98978098..be3a83a72e 100644 --- a/tests/e2e/tests/critical-path/cli/cli-command-helper.e2e.ts +++ b/tests/e2e/tests/critical-path/cli/cli-command-helper.e2e.ts @@ -124,7 +124,7 @@ test('Verify that user can type TS. in Command helper and see commands from Redi //Select group from list and remeber commands await cliPage.selectFilterGroupType(COMMAND_GROUP_TIMESERIES); const commandsFilterCount = await cliPage.cliHelperOutputTitles.count; - let timeSeriesCommands = []; + const timeSeriesCommands = []; for(let i = 0; i < commandsFilterCount; i++) { timeSeriesCommands.push(await cliPage.cliHelperOutputTitles.nth(i).textContent); } @@ -146,7 +146,7 @@ test('Verify that user can type GRAPH. in Command helper and see auto-suggestion //Select group from list and remeber commands await cliPage.selectFilterGroupType(COMMAND_GROUP_GRAPH); const commandsFilterCount = await cliPage.cliHelperOutputTitles.count; - let graphCommands = []; + const graphCommands = []; for(let i = 0; i < commandsFilterCount; i++) { graphCommands.push(await cliPage.cliHelperOutputTitles.nth(i).textContent); } diff --git a/tests/e2e/tests/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/critical-path/monitor/monitor.e2e.ts new file mode 100644 index 0000000000..fa99f49fac --- /dev/null +++ b/tests/e2e/tests/critical-path/monitor/monitor.e2e.ts @@ -0,0 +1,90 @@ +import { addNewStandaloneDatabase } from '../../../helpers/database'; +import { + MyRedisDatabasePage, + UserAgreementPage, + AddRedisDatabasePage, + CliPage, + MonitorPage, + WorkbenchPage, + BrowserPage +} from '../../../pageObjects'; +import { + commonUrl, + ossStandaloneConfig +} from '../../../helpers/conf'; +import { getRandomKeyName } from '../../../helpers/keys'; + +const myRedisDatabasePage = new MyRedisDatabasePage(); +const userAgreementPage = new UserAgreementPage(); +const addRedisDatabasePage = new AddRedisDatabasePage(); +const cliPage = new CliPage(); +const monitorPage = new MonitorPage(); +const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); +const keyName = `${getRandomKeyName(10)}-key`; +const keyValue = `${getRandomKeyName(10)}-value`; + +fixture.only `Monitor` + .meta({ type: 'critical_path' }) + .page(commonUrl) + .beforeEach(async t => { + await t.maximizeWindow(); + await userAgreementPage.acceptLicenseTerms(); + await t.expect(addRedisDatabasePage.addDatabaseButton.exists).ok('The add redis database view', { timeout: 20000 }); + await addNewStandaloneDatabase(ossStandaloneConfig); + await myRedisDatabasePage.clickOnDBByName(ossStandaloneConfig.databaseName); + }) + .afterEach(async t => { + await t.click(myRedisDatabasePage.myRedisDBButton); + await myRedisDatabasePage.deleteDatabaseByName(ossStandaloneConfig.databaseName); + }) +test + .after(async t => { + await browserPage.deleteKeyByName(keyName); + await t.click(myRedisDatabasePage.myRedisDBButton); + await myRedisDatabasePage.deleteDatabaseByName(ossStandaloneConfig.databaseName); + }) + ('Verify that user can work with Monitor', async t => { + const command = 'set'; + //Verify that user can open Monitor + await t.click(monitorPage.expandMonitor); + //Check that monitor is opened + await t.expect(monitorPage.monitorArea.exists).ok('Profiler area'); + await t.expect(monitorPage.startMonitorButton.exists).ok('Start profiler button'); + //Verify that user can see message inside Monitor "Running Monitor will decrease throughput, avoid running it in production databases." when opens it for the first time + await t.expect(monitorPage.monitorWarningMessage.exists).ok('Profiler warning message'); + await monitorPage.monitorWarningMessage.withText('Running Profiler will decrease throughput, avoid running it in production databases'); + //Verify that user can run Monitor by clicking "Run" command in the message inside Monitor + await t.click(monitorPage.startMonitorButton); + await t.expect(monitorPage.monitorIsStartedText.innerText).eql('Profiler is started.'); + //Verify that user can see run commands in monitor + await cliPage.getSuccessCommandResultFromCli(`${command} ${keyName} ${keyValue}`); + await monitorPage.checkCommandInMonitorResults(command, [keyName, keyValue]); + }); +test('Verify that user can see the list of all commands from all clients ran for this Redis database in the list of results in Monitor', async t => { + //Define commands in different clients + const cli_command = 'command'; + const workbench_command = 'hello'; + const common_command = 'info'; + const browser_command = 'dbsize'; + //Expand Monitor panel + await t.click(monitorPage.expandMonitor); + //Start monitor (using run button in header) + await t.click(monitorPage.runMonitorToggle); + //Send command in CLI + await cliPage.getSuccessCommandResultFromCli(cli_command); + //Check that command from CLI is displayed in monitor + await monitorPage.checkCommandInMonitorResults(cli_command); + //Refresh the page to send command from Browser client + await t.click(browserPage.refreshKeysButton); + //Check the command from browser client + await monitorPage.checkCommandInMonitorResults(browser_command); + //Open Workbench page to create new client + await t.click(myRedisDatabasePage.workbenchButton); + //Send command in Workbench + await workbenchPage.sendCommandInWorkbench(workbench_command); + //Check that command from Workbench is displayed in monitor + await monitorPage.checkCommandInMonitorResults(workbench_command); + //Check the command from common client + await monitorPage.checkCommandInMonitorResults(common_command); +}); diff --git a/tests/e2e/tests/regression/cli/cli-command-helper.e2e.ts b/tests/e2e/tests/regression/cli/cli-command-helper.e2e.ts index af68bced4e..6994a7486b 100644 --- a/tests/e2e/tests/regression/cli/cli-command-helper.e2e.ts +++ b/tests/e2e/tests/regression/cli/cli-command-helper.e2e.ts @@ -16,7 +16,7 @@ const COMMAND_GROUP_HyperLogLog = 'HyperLogLog'; fixture `CLI Command helper` .meta({ type: 'regression' }) .page(commonUrl) - .beforeEach(async t => { + .beforeEach(async() => { await acceptLicenseTermsAndAddDatabase(ossStandaloneConfig, ossStandaloneConfig.databaseName); }) diff --git a/tests/e2e/tests/regression/cli/cli.e2e.ts b/tests/e2e/tests/regression/cli/cli.e2e.ts index 2e745a2d19..a35ad551c2 100644 --- a/tests/e2e/tests/regression/cli/cli.e2e.ts +++ b/tests/e2e/tests/regression/cli/cli.e2e.ts @@ -12,7 +12,7 @@ const common = new Common(); fixture `CLI` .meta({ type: 'regression' }) .page(commonUrl) - .beforeEach(async t => { + .beforeEach(async() => { await acceptLicenseTermsAndAddDatabase(ossStandaloneConfig, ossStandaloneConfig.databaseName); }) test('Verify that user can see CLI is minimized when he clicks the "minimize" button', async t => { diff --git a/tests/e2e/tests/regression/monitor/monitor.e2e.ts b/tests/e2e/tests/regression/monitor/monitor.e2e.ts new file mode 100644 index 0000000000..eeaf905a8d --- /dev/null +++ b/tests/e2e/tests/regression/monitor/monitor.e2e.ts @@ -0,0 +1,112 @@ +import { Chance } from 'chance'; +import { addNewStandaloneDatabase } from '../../../helpers/database'; +import { + MyRedisDatabasePage, + UserAgreementPage, + AddRedisDatabasePage, + MonitorPage, + SettingsPage, + BrowserPage +} from '../../../pageObjects'; +import { + commonUrl, ossBigStandaloneConfig, + ossStandaloneConfig +} from '../../../helpers/conf'; + +const myRedisDatabasePage = new MyRedisDatabasePage(); +const userAgreementPage = new UserAgreementPage(); +const addRedisDatabasePage = new AddRedisDatabasePage(); +const monitorPage = new MonitorPage(); +const settingsPage = new SettingsPage(); +const browserPage = new BrowserPage(); +const chance = new Chance(); + +fixture.only `Monitor` + .meta({ type: 'regression' }) + .page(commonUrl) + .beforeEach(async t => { + await t.maximizeWindow(); + await userAgreementPage.acceptLicenseTerms(); + await t.expect(addRedisDatabasePage.addDatabaseButton.exists).ok('The add redis database view', { timeout: 20000 }); + await addNewStandaloneDatabase(ossStandaloneConfig); + await myRedisDatabasePage.clickOnDBByName(ossStandaloneConfig.databaseName); + }) + .afterEach(async t => { + await t.click(myRedisDatabasePage.myRedisDBButton); + await myRedisDatabasePage.deleteDatabaseByName(ossStandaloneConfig.databaseName); + }) +test('Verify that when user closes the Monitor by clicking on "Close Monitor" button Monitor stopped', async t => { + //Run monitor + await monitorPage.startMonitor(); + //Close Monitor + await t.click(monitorPage.closeMonitor); + //Verify that monitor is not displayed + await t.expect(monitorPage.monitorArea.visible).notOk('Profiler area'); + //Verify that user open monitor again + await t.click(monitorPage.expandMonitor); + //Verify that when user reopens Monitor history is not displayed + await t.expect(monitorPage.startMonitorButton.visible).ok('Start profiler button'); +}); +test('Verify that Monitor is stopped when user clicks on "Stop" button', async t => { + //Run monitor + await monitorPage.startMonitor(); + //Click on Stop Monitor button + await t.click(monitorPage.runMonitorToggle); + //Check for "Monitor is stopped." text + await t.expect(monitorPage.monitorIsStoppedText.innerText).eql('Profiler is stopped.'); + //Check that no commands are displayed after "Monitor is stopped" text + await t.expect(monitorPage.monitorIsStoppedText.nextSibling().exists).notOk('No commands in monitor'); +}); +test('Verify that when user refreshes the page the list of results in Monitor is not saved', async t => { + //Run monitor + await monitorPage.startMonitor(); + //Refresh the page + await t.eval(() => location.reload(true)); + //Check that monitor is closed + await t.expect(monitorPage.monitorArea.exists).notOk('Monitor area'); + //Check that monitor area doesn't have any saved results + await t.click(monitorPage.expandMonitor); + await t.expect(monitorPage.monitorWarningMessage.exists).ok('Warning message in monitor'); +}); +test('Verify that when user clicks on "Clear" button in Monitor, all commands history is removed', async t => { + //Run monitor + await monitorPage.startMonitor(); + //Stop Monitor + await monitorPage.stopMonitor(); + //Click on Clear button + await t.click(monitorPage.clearMonitorButton); + //Check that monitor has start screen + await t.expect(monitorPage.startMonitorButton.exists).ok('Start monitor button'); +}); +test + .before(async t => { + await t.maximizeWindow(); + await userAgreementPage.acceptLicenseTerms(); + await t.expect(addRedisDatabasePage.addDatabaseButton.exists).ok('Add Redis database view', { timeout: 20000 }); + await addNewStandaloneDatabase(ossBigStandaloneConfig); + await t.click(myRedisDatabasePage.settingsButton); + await t.click(settingsPage.accordionAdvancedSettings); + await settingsPage.changeKeysToScanValue('20000000'); + await t.click(myRedisDatabasePage.myRedisDBButton); + await myRedisDatabasePage.clickOnDBByName(ossBigStandaloneConfig.databaseName); + }) + .after(async t => { + await t.click(myRedisDatabasePage.settingsButton); + await t.click(settingsPage.accordionAdvancedSettings); + await settingsPage.changeKeysToScanValue('10000'); + await t.click(myRedisDatabasePage.myRedisDBButton); + await myRedisDatabasePage.deleteDatabaseByName(ossBigStandaloneConfig.databaseName); + }) + ('Verify that user can see monitor results in high DB load', async t => { + //Run monitor + await monitorPage.startMonitor(); + //Search by not existed key pattern + await browserPage.searchByKeyName(`${chance.string({ length:10 })}*`); + //Check that the last child is updated + for (let i = 0; i <= 10; i++) { + const previousTimestamp = await monitorPage.monitorCommandLineTimestamp.nth(-1).textContent; + await t.wait(5500); + const nextTimestamp = await monitorPage.monitorCommandLineTimestamp.nth(-1).textContent; + await t.expect(previousTimestamp).notEql(nextTimestamp); + } + }); diff --git a/tests/e2e/tests/regression/workbench/default-scripts-area.e2e.ts b/tests/e2e/tests/regression/workbench/default-scripts-area.e2e.ts index ccdfd45014..e7e88ac4ce 100644 --- a/tests/e2e/tests/regression/workbench/default-scripts-area.e2e.ts +++ b/tests/e2e/tests/regression/workbench/default-scripts-area.e2e.ts @@ -109,8 +109,8 @@ test('Verify that user can see the siblings menu by clicking on page counter ele await t.expect(workbenchPage.enablementAreaPaginationPopover.visible).ok('The siblings menu is displayed'); const countOfButtons = await workbenchPage.paginationPopoverButtons.count; for (let i = 0; i < countOfButtons; i++) { - let popoverButton = workbenchPage.paginationPopoverButtons.nth(i); - await t.expect(popoverButton.textContent).eql(popoverButtons[i], `The siblings menu button ${popoverButtons[i]} is displayed`); + const popoverButton = workbenchPage.paginationPopoverButtons.nth(i); + await t.expect(popoverButton.textContent).eql(popoverButtons[i], `The siblings menu button ${popoverButtons[i]} is displayed`); } }); test('Verify that user can see the quick navigation section to navigate between siblings under the scrolling content', async t => { diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index 5bc2a9b1a3..d80bc2eef2 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -1034,7 +1034,7 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" -"@types/chance@^1.1.3": +"@types/chance@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.1.3.tgz#d19fe9391288d60fdccd87632bfc9ab2b4523fea" integrity sha512-X6c6ghhe4/sQh4XzcZWSFaTAUOda38GQHmq9BUanYkOE/EO7ZrkazwKmtsj3xzTjkLWmwULE++23g3d3CCWaWw== @@ -1608,7 +1608,7 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chance@^1.1.8: +chance@1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.8.tgz#5d6c2b78c9170bf6eb9df7acdda04363085be909" integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg==