diff --git a/redisinsight/ui/src/constants/keys.ts b/redisinsight/ui/src/constants/keys.ts index 18a8bc856f..cf4a1264c2 100644 --- a/redisinsight/ui/src/constants/keys.ts +++ b/redisinsight/ui/src/constants/keys.ts @@ -1,4 +1,5 @@ import { StreamViewType } from 'uiSrc/slices/interfaces/stream' +import { ApiEndpoints } from 'uiSrc/constants' import { CommandGroup } from './commands' export enum KeyTypes { @@ -180,6 +181,17 @@ export enum KeyValueFormat { Pickle = 'Pickle', } +export const ENDPOINT_BASED_ON_KEY_TYPE = Object.freeze({ + [KeyTypes.ZSet]: ApiEndpoints.ZSET, + [KeyTypes.Set]: ApiEndpoints.SET, + [KeyTypes.String]: ApiEndpoints.STRING, + [KeyTypes.Hash]: ApiEndpoints.HASH, + [KeyTypes.List]: ApiEndpoints.LIST, + [KeyTypes.ReJSON]: ApiEndpoints.REJSON, + [KeyTypes.Stream]: ApiEndpoints.STREAMS, +}) + +export type EndpointBasedOnKeyType = keyof (typeof ENDPOINT_BASED_ON_KEY_TYPE) export enum SearchHistoryMode { Pattern = 'pattern', Redisearch = 'redisearch' diff --git a/redisinsight/ui/src/slices/browser/keys.ts b/redisinsight/ui/src/slices/browser/keys.ts index cb8a320e16..647ddf169c 100644 --- a/redisinsight/ui/src/slices/browser/keys.ts +++ b/redisinsight/ui/src/slices/browser/keys.ts @@ -7,6 +7,8 @@ import { BrowserStorageItem, KeyTypes, KeyValueFormat, + EndpointBasedOnKeyType, + ENDPOINT_BASED_ON_KEY_TYPE, SearchHistoryMode, SortOrder } from 'uiSrc/constants' @@ -26,6 +28,7 @@ import { DEFAULT_SEARCH_MATCH, SCAN_COUNT_DEFAULT } from 'uiSrc/constants/api' import { getBasedOnViewTypeEvent, sendEventTelemetry, TelemetryEvent, getAdditionalAddedEventData, getMatchType } from 'uiSrc/telemetry' import successMessages from 'uiSrc/components/notifications/success-messages' import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys' +import { resetBrowserTree } from 'uiSrc/slices/app/context' import { CreateListWithExpireDto, @@ -304,6 +307,16 @@ const keysSlice = createSlice({ state.addKey = { ...state.addKey, loading: false, + error: '', + } + }, + updateKeyList: (state, { payload }) => { + state.data?.keys.unshift({ name: payload.keyName }) + + state.data = { + ...state.data, + total: state.data.total + 1, + scanned: state.data.scanned + 1, } }, addKeyFailure: (state, { payload }) => { @@ -409,8 +422,9 @@ export const { defaultSelectedKeyActionFailure, setLastBatchPatternKeys, addKey, - addKeySuccess, + updateKeyList, addKeyFailure, + addKeySuccess, resetAddKey, deleteKey, deleteKeySuccess, @@ -715,12 +729,14 @@ export function refreshKeyInfoAction(key: RedisResponseBuffer) { function addTypedKey( data: any, - endpoint: ApiEndpoints, + keyType: KeyTypes, onSuccessAction?: () => void, onFailAction?: () => void ) { return async (dispatch: AppDispatch, stateInit: () => RootState) => { dispatch(addKey()) + const endpoint = ENDPOINT_BASED_ON_KEY_TYPE[keyType as EndpointBasedOnKeyType] + try { const state = stateInit() const { encoding } = state.app.info @@ -735,6 +751,7 @@ function addTypedKey( onSuccessAction() } dispatch(addKeySuccess()) + dispatch(addKeyIntoList({ key: data.keyName, keyType })) dispatch( addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)) ) @@ -767,8 +784,7 @@ export function addHashKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.HASH - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.Hash, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -777,8 +793,7 @@ export function addZsetKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.ZSET - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.ZSet, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -787,8 +802,7 @@ export function addSetKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.SET - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.Set, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -797,8 +811,7 @@ export function addStringKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.STRING - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.String, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -807,8 +820,7 @@ export function addListKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.LIST - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.List, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -817,8 +829,7 @@ export function addReJSONKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.REJSON - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.ReJSON, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -827,8 +838,7 @@ export function addStreamKey( onSuccessAction?: () => void, onFailAction?: () => void ) { - const endpoint = ApiEndpoints.STREAMS - return addTypedKey(data, endpoint, onSuccessAction, onFailAction) + return addTypedKey(data, KeyTypes.Stream, onSuccessAction, onFailAction) } // Asynchronous thunk action @@ -1147,6 +1157,25 @@ export function editKeyFromList(data: { key: RedisResponseBuffer, newKey: RedisR } } +export function addKeyIntoList({ key, keyType }: { key: RedisString, keyType: KeyTypes }) { + return async (dispatch: AppDispatch, stateInit: () => RootState) => { + const state = stateInit() + const { viewType, filter, search } = state.browser.keys + + if (search && search !== '*') { + return null + } + + if (!filter || filter === keyType) { + if (viewType !== KeyViewType.Tree) { + dispatch(resetBrowserTree()) + } + return dispatch(updateKeyList({ keyName: key, keyType })) + } + return null + } +} + export function editKeyTTLFromList(data: [RedisResponseBuffer, number]) { return async (dispatch: AppDispatch, stateInit: () => RootState) => { const state = stateInit() diff --git a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts index aa03b88809..3888fc4649 100644 --- a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts +++ b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts @@ -7,6 +7,7 @@ import { cleanup, initialStateDefault, mockedStore } from 'uiSrc/utils/test-util import { addErrorNotification, addMessageNotification } from 'uiSrc/slices/app/notifications' import successMessages from 'uiSrc/components/notifications/success-messages' import { SearchHistoryItem, SearchMode } from 'uiSrc/slices/interfaces/keys' +import { resetBrowserTree } from 'uiSrc/slices/app/context' import { CreateHashWithExpireDto, CreateListWithExpireDto, @@ -63,6 +64,8 @@ import reducer, { loadSearchHistorySuccess, refreshKeyInfo, refreshKeyInfoAction, + updateKeyList, + addKeyIntoList, refreshKeyInfoFail, refreshKeyInfoSuccess, resetAddKey, @@ -520,19 +523,21 @@ describe('keys slice', () => { }) }) - describe('addKeySuccess', () => { + describe('updateKeyList', () => { it('should properly set the state after successfully added key', () => { // Arrange const state = { ...initialState, - addKey: { - ...initialState.addKey, - loading: false, - }, + data: { + ...initialState.data, + keys: [{ name: 'name' }], + scanned: 1, + total: 1, + } } // Act - const nextState = reducer(initialState, addKeySuccess()) + const nextState = reducer(initialState, updateKeyList({ keyName: 'name', keyType: 'hash' })) // Assert const rootState = Object.assign(initialStateDefault, { @@ -1262,6 +1267,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'hash' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1286,6 +1293,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'zset' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1310,6 +1319,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'set' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1334,6 +1345,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'string' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1359,6 +1372,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'list' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1383,6 +1398,8 @@ describe('keys slice', () => { const expectedActions = [ addKey(), addKeySuccess(), + resetBrowserTree(), + updateKeyList({ keyName: data.keyName, keyType: 'ReJSON-RL' }), addMessageNotification(successMessages.ADDED_NEW_KEY(data.keyName)), ] expect(store.getActions()).toEqual(expectedActions) @@ -1532,177 +1549,193 @@ describe('keys slice', () => { }) }) - describe('fetchPatternHistoryAction', () => { - it('success fetch history', async () => { - // Arrange - const data: SearchHistoryItem[] = [ - { id: '1', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, - { id: '2', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, - ] - const responsePayload = { data, status: 200 } - - apiService.get = jest.fn().mockResolvedValue(responsePayload) - + describe('addKeyIntoList', () => { + it('updateKeyList should be called', async () => { // Act - await store.dispatch(fetchPatternHistoryAction()) + await store.dispatch( + addKeyIntoList({ key: 'key', keyType: 'hash' }) + ) // Assert const expectedActions = [ - loadSearchHistory(), - loadSearchHistorySuccess(data), + resetBrowserTree(), + updateKeyList({ keyName: 'key', keyType: 'hash' }) ] expect(store.getActions()).toEqual(expectedActions) }) - it('failed to load history', async () => { - // Arrange - const errorMessage = 'some error' - const responsePayload = { - response: { - status: 500, - data: { message: errorMessage }, - }, - } - apiService.get = jest.fn().mockRejectedValue(responsePayload) + describe('fetchPatternHistoryAction', () => { + it('success fetch history', async () => { + // Arrange + const data: SearchHistoryItem[] = [ + { id: '1', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, + { id: '2', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, + ] + const responsePayload = { data, status: 200 } - // Act - await store.dispatch(fetchPatternHistoryAction()) + apiService.get = jest.fn().mockResolvedValue(responsePayload) - // Assert - const expectedActions = [ - loadSearchHistory(), - loadSearchHistoryFailure(), - ] - expect(store.getActions()).toEqual(expectedActions) - }) - }) + // Act + await store.dispatch(fetchPatternHistoryAction()) - describe('fetchSearchHistoryAction', () => { - it('success fetch history', async () => { - // Arrange - const data: SearchHistoryItem[] = [ - { id: '1', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, - { id: '2', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, - ] - const responsePayload = { data, status: 200 } + // Assert + const expectedActions = [ + loadSearchHistory(), + loadSearchHistorySuccess(data), + ] + expect(store.getActions()).toEqual(expectedActions) + }) + it('failed to load history', async () => { + // Arrange + const errorMessage = 'some error' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } - apiService.get = jest.fn().mockResolvedValue(responsePayload) + apiService.get = jest.fn().mockRejectedValue(responsePayload) - // Act - await store.dispatch(fetchSearchHistoryAction(SearchMode.Pattern)) + // Act + await store.dispatch(fetchPatternHistoryAction()) - // Assert - const expectedActions = [ - loadSearchHistory(), - loadSearchHistorySuccess(data), - ] - expect(store.getActions()).toEqual(expectedActions) + // Assert + const expectedActions = [ + loadSearchHistory(), + loadSearchHistoryFailure(), + ] + expect(store.getActions()).toEqual(expectedActions) + }) }) - it('failed to load history', async () => { - // Arrange - const errorMessage = 'some error' - const responsePayload = { - response: { - status: 500, - data: { message: errorMessage }, - }, - } - apiService.get = jest.fn().mockRejectedValue(responsePayload) + describe('fetchSearchHistoryAction', () => { + it('success fetch history', async () => { + // Arrange + const data: SearchHistoryItem[] = [ + { id: '1', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, + { id: '2', mode: SearchMode.Pattern, filter: { type: 'list', match: '*' } }, + ] + const responsePayload = { data, status: 200 } - // Act - await store.dispatch(fetchSearchHistoryAction(SearchMode.Pattern)) + apiService.get = jest.fn().mockResolvedValue(responsePayload) - // Assert - const expectedActions = [ - loadSearchHistory(), - loadSearchHistoryFailure(), - ] - expect(store.getActions()).toEqual(expectedActions) - }) - }) + // Act + await store.dispatch(fetchSearchHistoryAction(SearchMode.Pattern)) - describe('deletePatternHistoryAction', () => { - it('success delete history', async () => { - // Arrange - const responsePayload = { status: 200 } + // Assert + const expectedActions = [ + loadSearchHistory(), + loadSearchHistorySuccess(data), + ] + expect(store.getActions()).toEqual(expectedActions) + }) + it('failed to load history', async () => { + // Arrange + const errorMessage = 'some error' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } - apiService.delete = jest.fn().mockResolvedValue(responsePayload) + apiService.get = jest.fn().mockRejectedValue(responsePayload) - // Act - await store.dispatch(deletePatternHistoryAction(['1'])) + // Act + await store.dispatch(fetchSearchHistoryAction(SearchMode.Pattern)) - // Assert - const expectedActions = [ - deleteSearchHistory(), - deleteSearchHistorySuccess(['1']), - ] - expect(store.getActions()).toEqual(expectedActions) + // Assert + const expectedActions = [ + loadSearchHistory(), + loadSearchHistoryFailure(), + ] + expect(store.getActions()).toEqual(expectedActions) + }) }) - it('failed to delete history', async () => { - // Arrange - const errorMessage = 'some error' - const responsePayload = { - response: { - status: 500, - data: { message: errorMessage }, - }, - } - - apiService.delete = jest.fn().mockRejectedValue(responsePayload) + describe('deletePatternHistoryAction', () => { + it('success delete history', async () => { + // Arrange + const responsePayload = { status: 200 } - // Act - await store.dispatch(deletePatternHistoryAction(['1'])) + apiService.delete = jest.fn().mockResolvedValue(responsePayload) - // Assert - const expectedActions = [ - deleteSearchHistory(), - deleteSearchHistoryFailure(), - ] - expect(store.getActions()).toEqual(expectedActions) - }) - }) + // Act + await store.dispatch(deletePatternHistoryAction(['1'])) - describe('deleteSearchHistoryAction', () => { - it('success delete history', async () => { - // Arrange - const responsePayload = { status: 200 } + // Assert + const expectedActions = [ + deleteSearchHistory(), + deleteSearchHistorySuccess(['1']), + ] + expect(store.getActions()).toEqual(expectedActions) + }) + + it('failed to delete history', async () => { + // Arrange + const errorMessage = 'some error' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } - apiService.delete = jest.fn().mockResolvedValue(responsePayload) + apiService.delete = jest.fn().mockRejectedValue(responsePayload) - // Act - await store.dispatch(deleteSearchHistoryAction(SearchMode.Pattern, ['1'])) + // Act + await store.dispatch(deletePatternHistoryAction(['1'])) - // Assert - const expectedActions = [ - deleteSearchHistory(), - deleteSearchHistorySuccess(['1']), - ] - expect(store.getActions()).toEqual(expectedActions) + // Assert + const expectedActions = [ + deleteSearchHistory(), + deleteSearchHistoryFailure(), + ] + expect(store.getActions()).toEqual(expectedActions) + }) }) - it('failed to delete history', async () => { - // Arrange - const errorMessage = 'some error' - const responsePayload = { - response: { - status: 500, - data: { message: errorMessage }, - }, - } + describe('deleteSearchHistoryAction', () => { + it('success delete history', async () => { + // Arrange + const responsePayload = { status: 200 } - apiService.delete = jest.fn().mockRejectedValue(responsePayload) + apiService.delete = jest.fn().mockResolvedValue(responsePayload) - // Act - await store.dispatch(deleteSearchHistoryAction(SearchMode.Pattern, ['1'])) + // Act + await store.dispatch(deleteSearchHistoryAction(SearchMode.Pattern, ['1'])) - // Assert - const expectedActions = [ - deleteSearchHistory(), - deleteSearchHistoryFailure(), - ] - expect(store.getActions()).toEqual(expectedActions) + // Assert + const expectedActions = [ + deleteSearchHistory(), + deleteSearchHistorySuccess(['1']), + ] + expect(store.getActions()).toEqual(expectedActions) + }) + + it('failed to delete history', async () => { + // Arrange + const errorMessage = 'some error' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } + + apiService.delete = jest.fn().mockRejectedValue(responsePayload) + + // Act + await store.dispatch(deleteSearchHistoryAction(SearchMode.Pattern, ['1'])) + + // Assert + const expectedActions = [ + deleteSearchHistory(), + deleteSearchHistoryFailure(), + ] + expect(store.getActions()).toEqual(expectedActions) + }) }) }) }) diff --git a/redisinsight/ui/src/slices/tests/instances/instances.spec.ts b/redisinsight/ui/src/slices/tests/instances/instances.spec.ts index 9391f2a6bb..bf36c5fa10 100644 --- a/redisinsight/ui/src/slices/tests/instances/instances.spec.ts +++ b/redisinsight/ui/src/slices/tests/instances/instances.spec.ts @@ -70,7 +70,6 @@ import { loadMastersSentinel } from '../../instances/sentinel' jest.mock('uiSrc/services', () => ({ ...jest.requireActual('uiSrc/services'), })) -jest.mock('uiSrc/constants') let store: typeof mockedStore let instances: Instance[] diff --git a/tests/e2e/common-actions/browser-actions.ts b/tests/e2e/common-actions/browser-actions.ts index 0462bb95f2..4eb63aacc5 100644 --- a/tests/e2e/common-actions/browser-actions.ts +++ b/tests/e2e/common-actions/browser-actions.ts @@ -1,4 +1,4 @@ -import { t } from 'testcafe'; +import {Selector, t} from 'testcafe'; import { BrowserPage } from '../pageObjects'; const browserPage = new BrowserPage(); @@ -29,9 +29,8 @@ export class BrowserActions { } } } - /** - * Verify toolip contains text + * Verify tooltip contains text * @param expectedText Expected link that is compared with actual * @param contains Should this tooltip contains or not contains text */ @@ -40,4 +39,17 @@ export class BrowserActions { ? await t.expect(browserPage.tooltip.textContent).contains(expectedText, `"${expectedText}" Text is incorrect in tooltip`) : await t.expect(browserPage.tooltip.textContent).notContains(expectedText, `Tooltip still contains text "${expectedText}"`); } + /** + * Verify that the new key is displayed at the top of the list of keys and opened and pre-selected in List view + * */ + async verifyKeyDisplayedTopAndOpened(keyName: string): Promise { + await t.expect(Selector('[aria-rowindex="1"]').withText(keyName).visible).ok(`element with ${keyName} is not visible in the top of list`); + await t.expect(browserPage.keyNameFormDetails.withText(keyName).visible).ok(`element with ${keyName} is not opened`); + } + /** + * Verify that the new key is not displayed at the top of the list of keys and opened and pre-selected in List view + * */ + async verifyKeyIsNotDisplayedTop(keyName: string): Promise { + await t.expect(Selector('[aria-rowindex="1"]').withText(keyName).exists).notOk(`element with ${keyName} is not visible in the top of list`); + } } diff --git a/tests/e2e/tests/regression/browser/add-keys.e2e.ts b/tests/e2e/tests/regression/browser/add-keys.e2e.ts index 991628a3ed..477352ce49 100644 --- a/tests/e2e/tests/regression/browser/add-keys.e2e.ts +++ b/tests/e2e/tests/regression/browser/add-keys.e2e.ts @@ -1,14 +1,20 @@ -import { rte } from '../../../helpers/constants'; +import {rte} from '../../../helpers/constants'; import { acceptLicenseTermsAndAddDatabaseApi } from '../../../helpers/database'; import { BrowserPage, CliPage } from '../../../pageObjects'; -import { commonUrl, ossStandaloneConfig } from '../../../helpers/conf'; +import {commonUrl, ossStandaloneBigConfig, ossStandaloneConfig} from '../../../helpers/conf'; import { deleteStandaloneDatabaseApi } from '../../../helpers/api/api-database'; +import {Common} from '../../../helpers/common'; +import {BrowserActions} from '../../../common-actions/browser-actions'; const browserPage = new BrowserPage(); +const browserActions = new BrowserActions(); +const common = new Common(); const cliPage = new CliPage(); const jsonKeys = [['JSON-string', '"test"'], ['JSON-number', '782364'], ['JSON-boolean', 'true'], ['JSON-null', 'null'], ['JSON-array', '[1, 2, 3]']]; +let keyNames: string[]; +let indexName: string; -fixture `Different JSON types creation` +fixture `Add keys` .meta({ type: 'regression', rte: rte.standalone @@ -44,3 +50,56 @@ test('Verify that user can create different types(string, number, null, array, b } } }); +// https://redislabs.atlassian.net/browse/RI-3995 +test + .before(async() => { + await acceptLicenseTermsAndAddDatabaseApi(ossStandaloneBigConfig, ossStandaloneBigConfig.databaseName); + }) + .after(async() => { + let commandString = 'DEL'; + for (const key of keyNames) { + commandString = commandString.concat(` ${key}`); + } + const commands = [`FT.DROPINDEX ${indexName}`, commandString]; + await cliPage.sendCommandsInCli(commands); + await deleteStandaloneDatabaseApi(ossStandaloneBigConfig); + })('Verify that the new key is displayed at the top of the list', async t => { + const keyName = common.generateWord(12); + const keyName1 = common.generateWord(12); + const keyName2 = common.generateWord(36); + const keyName3 = common.generateWord(10); + const keyName4 = `${common.generateWord(10)}-test`; + const keyName5 = `hash-${common.generateWord(12)}`; + keyNames = [keyName, keyName1, keyName2, keyName3, keyName4, keyName5]; + indexName = `idx:${keyName5}`; + const command = `FT.CREATE ${indexName} ON HASH PREFIX 1 hash- SCHEMA name TEXT`; + await cliPage.sendCommandInCli(command); + + await browserPage.addStringKey(keyName); + await browserActions.verifyKeyDisplayedTopAndOpened(keyName); + // Verify displaying added multiple keys + await browserPage.addSetKey(keyName1); + await browserActions.verifyKeyDisplayedTopAndOpened(keyName1); + + await browserPage.addHashKey(keyName2); + await browserActions.verifyKeyDisplayedTopAndOpened(keyName2); + // Verify that user can see the key removed from the top when refresh List view + await t.click(browserPage.refreshKeysButton); + await browserActions.verifyKeyIsNotDisplayedTop(keyName1); + // Verify that the new key is not displayed at the top when filter per key name applied + await browserPage.searchByKeyName('*test'); + await browserPage.addHashKey(keyName4); + await browserActions.verifyKeyIsNotDisplayedTop(keyName4); + + await t.click(browserPage.clearFilterButton); + await t.click(browserPage.treeViewButton); + await browserPage.addHashKey(keyName3); + // Verify that user can see Tree view recalculated when new key is added in Tree view + await browserActions.verifyKeyDisplayedTopAndOpened(keyName3); + + await t.click(browserPage.redisearchModeBtn); + await browserPage.selectIndexByName(indexName); + await browserPage.addHashKey(keyName5, '100000', 'name', 'value'); + // Verify that the new key is not displayed at the top for the Search capability + await browserActions.verifyKeyIsNotDisplayedTop(keyName3); + });