diff --git a/redisinsight/ui/src/pages/browser/BrowserPage.tsx b/redisinsight/ui/src/pages/browser/BrowserPage.tsx index a05f8097f5..f87e868291 100644 --- a/redisinsight/ui/src/pages/browser/BrowserPage.tsx +++ b/redisinsight/ui/src/pages/browser/BrowserPage.tsx @@ -190,7 +190,7 @@ const BrowserPage = () => { } const selectKey = ({ rowData }: { rowData: any }) => { - if (!isEqualBuffers(rowData.name, selectedKey)) { + if (!isEqualBuffers(rowData.name, selectedKeyRef.current)) { dispatch(toggleBrowserFullScreen(false)) dispatch(setInitialStateByType(prevSelectedType.current)) diff --git a/redisinsight/ui/src/pages/browser/components/key-tree/KeyTree.tsx b/redisinsight/ui/src/pages/browser/components/key-tree/KeyTree.tsx index 9e9d2d10d7..76a1552393 100644 --- a/redisinsight/ui/src/pages/browser/components/key-tree/KeyTree.tsx +++ b/redisinsight/ui/src/pages/browser/components/key-tree/KeyTree.tsx @@ -126,7 +126,7 @@ const KeyTree = forwardRef((props: Props, ref) => { openSelectedKey(selectedKeyName) } - const handleStatusOpen = (name: string, value:boolean) => { + const handleStatusOpen = (name: string, value: boolean) => { setStatusOpen((prevState) => { const newState = { ...prevState } // add or remove opened node diff --git a/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.spec.tsx b/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.spec.tsx index b869123dd7..77ab0073a2 100644 --- a/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.spec.tsx @@ -15,33 +15,36 @@ const mockedItems = [ }, ] -export const mockVirtualTreeResult = [{ - children: [{ +export const mockVirtualTreeResult = [ + { + children: [{ + children: [], + fullName: 'car:110:', + id: '0.snc1rc3zwgo', + keyApproximate: 0.01, + keyCount: 1, + name: '110', + }], + fullName: 'car:', + id: '0.sz1ie1koqi8', + keyApproximate: 47.18, + keyCount: 4718, + name: 'car', + }, + { children: [], - fullName: 'car:110:', - id: '0.snc1rc3zwgo', + fullName: 'test', + id: '0.snc1rc3zwg1o', keyApproximate: 0.01, keyCount: 1, - name: '110', - }], - fullName: 'car:', - id: '0.sz1ie1koqi8', - keyApproximate: 47.18, - keyCount: 4718, - name: 'car', -}, -{ - children: [], - fullName: 'test', - id: '0.snc1rc3zwg1o', - keyApproximate: 0.01, - keyCount: 1, - name: 'test', -}] + name: 'test', + } +] jest.mock('uiSrc/services', () => ({ + __esModule: true, ...jest.requireActual('uiSrc/services'), - useDisposableWebworker: () => ({ result: mockVirtualTreeResult, run: jest.fn() }), + useDisposableWebworker: () => ({ result: mockVirtualTreeResult, run: jest.fn() }) })) describe('VirtualTree', () => { @@ -74,4 +77,19 @@ describe('VirtualTree', () => { expect(queryByTestId('node-item_test')).toBeInTheDocument() }) + + it('should not call onStatusOpen if more than one folder is exist', () => { + const mockFn = jest.fn() + const mockOnStatusOpen = jest.fn() + + render( + + ) + + expect(mockOnStatusOpen).not.toHaveBeenCalled() + }) }) diff --git a/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.tsx b/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.tsx index 552873d9b2..5092080298 100644 --- a/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.tsx +++ b/redisinsight/ui/src/pages/browser/components/virtual-tree/VirtualTree.tsx @@ -63,7 +63,7 @@ const VirtualTree = (props: Props) => { onStatusOpen, onStatusSelected, setConstructingTree, - webworkerFn = () => {}, + webworkerFn = () => { }, onDeleteClicked, onDeleteLeaf, } = props @@ -94,6 +94,8 @@ const VirtualTree = (props: Props) => { nodes.current = result rerender({}) setConstructingTree?.(false) + + openSingleFolderNode(nodes.current) }, [result]) useEffect(() => { @@ -205,6 +207,15 @@ const VirtualTree = (props: Props) => { node, }) + const openSingleFolderNode = useCallback((treeNodes?: TreeNode[]) => { + let nodes = treeNodes + while (nodes?.length === 1) { + const singleNode = nodes[0] + onStatusOpen?.(singleNode.fullName, true) + nodes = singleNode.children + } + }, [onStatusOpen]) + // The `treeWalker` function runs only on tree re-build which is performed // whenever the `treeWalker` prop is changed. const treeWalker = useCallback( diff --git a/redisinsight/ui/src/pages/browser/components/virtual-tree/components/Node/Node.tsx b/redisinsight/ui/src/pages/browser/components/virtual-tree/components/Node/Node.tsx index 8739c9c7a8..597fe86359 100644 --- a/redisinsight/ui/src/pages/browser/components/virtual-tree/components/Node/Node.tsx +++ b/redisinsight/ui/src/pages/browser/components/virtual-tree/components/Node/Node.tsx @@ -66,7 +66,7 @@ const Node = ({ }, []) const handleClick = () => { - if (isLeaf && !isSelected) { + if (isLeaf) { updateStatusSelected?.(nameBuffer) } @@ -154,7 +154,7 @@ const Node = ({ onKeyDown={handleKeyDown} tabIndex={0} onFocus={() => {}} - data-testid={`node-item_${fullName}`} + data-testid={`node-item_${fullName}${isOpen && !isLeaf ? '--expanded' : ''}`} > {!isLeaf && } {isLeaf && } diff --git a/tests/e2e/common-actions/browser-actions.ts b/tests/e2e/common-actions/browser-actions.ts index 836fa6235e..fcc6aceaaf 100644 --- a/tests/e2e/common-actions/browser-actions.ts +++ b/tests/e2e/common-actions/browser-actions.ts @@ -87,7 +87,7 @@ export class BrowserActions { * @param name node name */ getNodeSelector(name: string): Selector { - return Selector(`[data-testid="node-item_${name}"]`); + return Selector(`[data-testid^="node-item_${name}"]`); } /** @@ -108,7 +108,10 @@ export class BrowserActions { for (let j = 0; j < innerFoldersNumber; j++) { const nodeName = this.getNodeName(prevNodeSelector, folders[i][j], delimiter); const node = this.getNodeSelector(nodeName); - await t.click(node); + const fullTestIdSelector = await node.getAttribute('data-testid'); + if (!fullTestIdSelector?.includes('expanded')) { + await t.click(node); + } prevNodeSelector = nodeName; } diff --git a/tests/e2e/docker.web.docker-compose.yml b/tests/e2e/docker.web.docker-compose.yml index 99d2099406..9cd09a2e2f 100644 --- a/tests/e2e/docker.web.docker-compose.yml +++ b/tests/e2e/docker.web.docker-compose.yml @@ -33,7 +33,7 @@ services: command: [ './wait-for-it.sh', 'redis-enterprise:12000', '-s', '-t', '120', '--', - 'npx', 'yarn', 'test:chrome:ci' + 'npm', 'run', 'test:chrome:ci' ] # Built image diff --git a/tests/e2e/local.web.docker-compose.yml b/tests/e2e/local.web.docker-compose.yml index 554821fdc9..361f8a0acd 100644 --- a/tests/e2e/local.web.docker-compose.yml +++ b/tests/e2e/local.web.docker-compose.yml @@ -33,7 +33,7 @@ services: command: [ './wait-for-it.sh', 'redis-enterprise:12000', '-s', '-t', '120', '--', - 'npx', 'yarn', 'test:chrome:ci' + 'npm', 'run', 'test:chrome:ci' ] # Redisinsight API + UI build diff --git a/tests/e2e/pageObjects/components/browser/tree-view.ts b/tests/e2e/pageObjects/components/browser/tree-view.ts index d3fd5c75ae..1a5c7d473c 100644 --- a/tests/e2e/pageObjects/components/browser/tree-view.ts +++ b/tests/e2e/pageObjects/components/browser/tree-view.ts @@ -71,8 +71,8 @@ export class TreeView { await t.click(this.treeViewSettingsBtn); await t.click(this.sortingBtn); order === 'ASC' - ? await t.click(this.sortingASCoption) - : await t.click(this.sortingDESCoption) + ? await t.click(this.sortingASCoption) + : await t.click(this.sortingDESCoption); // Click on save button await t.click(this.treeViewDelimiterValueSave); @@ -93,11 +93,11 @@ export class TreeView { */ async openTreeFolders(names: string[]): Promise { let base = `node-item_${names[0]}:`; - await t.click(Selector(`[data-testid="${base}"]`)); + await this.clickElementIfNotExpanded(base); if (names.length > 1) { for (let i = 1; i < names.length; i++) { base = `${base }${names[i]}:`; - await t.click(Selector(`[data-testid="${base}"]`)); + await this.clickElementIfNotExpanded(base); } } } @@ -120,4 +120,16 @@ export class TreeView { return textArray; } + + /** + * click on the folder element if it is not expanded + * @param base the base element + */ + private async clickElementIfNotExpanded(base: string): Promise { + const baseSelector = Selector(`[data-testid^="${base}"]`); + const elementSelector = await baseSelector.getAttribute('data-testid'); + if (!elementSelector?.includes('expanded')) { + await t.click(Selector(`[data-testid^="${base}"]`)); + } + } } diff --git a/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts b/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts index 75db76c555..1a34378be8 100644 --- a/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts +++ b/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts @@ -3,6 +3,7 @@ import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneBigConfig, + ossStandaloneConfig, ossStandaloneConfigEmpty, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -10,6 +11,7 @@ import { KeyTypesTexts, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; import { Common } from '../../../../helpers/common'; +import { verifyKeysDisplayingInTheList } from '../../../../helpers/keys'; const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); @@ -145,3 +147,37 @@ test actualItemsArray = await browserPage.TreeView.getAllItemsArray(); await t.expect(actualItemsArray).eql(expectedSortedByDESC); }); + +https://redislabs.atlassian.net/browse/RI-5131 +test + .before(async() => { + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); + }) + .after(async() => { + await browserPage.Cli.sendCommandInCli('flushdb'); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + })('Verify that if filtering results has only 1 folder, the folder will be expanded', async t => { + const name = Common.generateWord(10); + const additionalCharacter = Common.generateWord(1); + const keyName1 = Common.generateWord(3); + const keyName2 = Common.generateWord(3); + keyNames = [`${name}${additionalCharacter}:${keyName1}`, `${name}${additionalCharacter}:${keyName2}`, name]; + + const commands = [ + 'flushdb', + `HSET ${keyNames[0]} field value`, + `HSET ${keyNames[1]} field value`, + `HSET ${keyNames[2]} field value` + ]; + await browserPage.Cli.sendCommandsInCli(commands); + await t.click(browserPage.treeViewButton); + + // Verify if there is only folder, a user can see keys inside + await browserPage.searchByKeyName(`${name}${additionalCharacter}*`); + await verifyKeysDisplayingInTheList([keyName1, keyName2], true); + + // Verify if there are folder and key, a user can't see keys inside the folder + await browserPage.searchByKeyName(`${name}*`); + await verifyKeysDisplayingInTheList([keyName1, keyName2], false); + }); +