Skip to content

Commit 68b84c9

Browse files
authored
Merge pull request #2741 from RedisInsight/e2e/feature/RI-4828_rework_tree_view
E2e/feature/ri 4828 rework tree view
2 parents 84a379d + 8489f85 commit 68b84c9

File tree

22 files changed

+478
-332
lines changed

22 files changed

+478
-332
lines changed

redisinsight/ui/src/pages/browser/components/key-tree/KeyTreeSettings/KeyTreeSettings.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ const KeyTreeSettings = ({ loading }: Props) => {
151151
<EuiButton
152152
size="s"
153153
color="secondary"
154+
data-testid="tree-view-cancel-btn"
154155
onClick={closePopover}
155156
>
156157
Cancel

tests/e2e/common-actions/browser-actions.ts

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Selector, t} from 'testcafe';
1+
import { Selector, t } from 'testcafe';
22
import { BrowserPage } from '../pageObjects';
33

44
const browserPage = new BrowserPage();
@@ -29,6 +29,7 @@ export class BrowserActions {
2929
}
3030
}
3131
}
32+
3233
/**
3334
* Verify tooltip contains text
3435
* @param expectedText Expected link that is compared with actual
@@ -39,17 +40,85 @@ export class BrowserActions {
3940
? await t.expect(browserPage.tooltip.textContent).contains(expectedText, `"${expectedText}" Text is incorrect in tooltip`)
4041
: await t.expect(browserPage.tooltip.textContent).notContains(expectedText, `Tooltip still contains text "${expectedText}"`);
4142
}
43+
4244
/**
4345
* Verify that the new key is displayed at the top of the list of keys and opened and pre-selected in List view
44-
* */
46+
* @param keyName Key name
47+
*/
4548
async verifyKeyDisplayedTopAndOpened(keyName: string): Promise<void> {
4649
await t.expect(Selector('[aria-rowindex="1"]').withText(keyName).visible).ok(`element with ${keyName} is not visible in the top of list`);
4750
await t.expect(browserPage.keyNameFormDetails.withText(keyName).visible).ok(`element with ${keyName} is not opened`);
4851
}
52+
4953
/**
5054
* Verify that the new key is not displayed at the top of the list of keys and opened and pre-selected in List view
51-
* */
55+
* @param keyName Key name
56+
*/
5257
async verifyKeyIsNotDisplayedTop(keyName: string): Promise<void> {
5358
await t.expect(Selector('[aria-rowindex="1"]').withText(keyName).exists).notOk(`element with ${keyName} is not visible in the top of list`);
5459
}
60+
61+
/**
62+
* Verify that not patterned keys not visible with delimiter
63+
* @param delimiter string with delimiter value
64+
*/
65+
async verifyNotPatternedKeys(delimiter: string): Promise<void> {
66+
const notPatternedKeys = Selector('[data-testid^="badge"]').parent('[data-testid^="node-item_"]');
67+
const notPatternedKeysNumber = await notPatternedKeys.count;
68+
69+
for (let i = 0; i < notPatternedKeysNumber; i++) {
70+
await t.expect(notPatternedKeys.nth(i).withText(delimiter).exists).notOk('Not contained delimiter keys');
71+
}
72+
}
73+
74+
/**
75+
* Get node name by folders
76+
* @param startFolder start folder
77+
* @param folderName name of folder
78+
* @param delimiter string with delimiter value
79+
*/
80+
getNodeName(startFolder: string, folderName: string, delimiter: string): string {
81+
return startFolder + folderName + delimiter;
82+
83+
}
84+
85+
/**
86+
* Get node selector by name
87+
* @param name node name
88+
*/
89+
getNodeSelector(name: string): Selector {
90+
return Selector(`[data-testid="node-item_${name}"]`);
91+
}
92+
93+
/**
94+
* Check tree view structure
95+
* @param folders name of folders for tree view build
96+
* @param delimiter string with delimiter value
97+
*/
98+
async checkTreeViewFoldersStructure(folders: string[][], delimiter: string): Promise<void> {
99+
// Verify not patterned keys
100+
await this.verifyNotPatternedKeys(delimiter);
101+
102+
const foldersNumber = folders.length;
103+
104+
for (let i = 0; i < foldersNumber; i++) {
105+
const innerFoldersNumber = folders[i].length;
106+
let prevNodeSelector = '';
107+
108+
for (let j = 0; j < innerFoldersNumber; j++) {
109+
const nodeName = this.getNodeName(prevNodeSelector, folders[i][j], delimiter);
110+
const node = this.getNodeSelector(nodeName);
111+
await t.click(node);
112+
prevNodeSelector = nodeName;
113+
}
114+
115+
// Verify that the last folder level contains required keys
116+
const foundKeyName = `${folders[i].join(delimiter)}`;
117+
const firstFolderName = this.getNodeName('', folders[i][0], delimiter);
118+
const firstFolder = this.getNodeSelector(firstFolderName);
119+
await t
120+
.expect(Selector(`[data-testid*="node-item_${foundKeyName}"]`).find('[data-testid^="key-"]').exists).ok('Specific key not found')
121+
.click(firstFolder);
122+
}
123+
}
55124
}

tests/e2e/desktop.runner.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import testcafe from 'testcafe';
3838
selectorTimeout: 5000,
3939
assertionTimeout: 5000,
4040
speed: 1,
41+
quarantineMode: { successThreshold: 1, attemptLimit: 3 },
4142
});
4243
})
4344
.then((failedCount) => {

tests/e2e/desktop.runner.win.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import testcafe from 'testcafe';
3838
selectorTimeout: 5000,
3939
assertionTimeout: 5000,
4040
speed: 1,
41+
quarantineMode: { successThreshold: 1, attemptLimit: 3 },
4142
});
4243
})
4344
.then((failedCount) => {

tests/e2e/helpers/keys.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -249,29 +249,20 @@ export async function deleteAllKeysFromDB(host: string, port: string): Promise<v
249249
/**
250250
* Verifying if the Keys are in the List of keys
251251
* @param keyNames The names of the keys
252+
* @param isDisplayed True if keys should be displayed
252253
*/
253-
export async function verifyKeysDisplayedInTheList(keyNames: string[]): Promise<void> {
254+
export async function verifyKeysDisplayingInTheList(keyNames: string[], isDisplayed: boolean): Promise<void> {
254255
for (const keyName of keyNames) {
255-
await t.expect(browserPage.getKeySelectorByName(keyName).exists).ok(`The key ${keyName} not found`);
256-
}
257-
}
258-
259-
/**
260-
* Verifying if the Keys are not in the List of keys
261-
* @param keyNames The names of the keys
262-
*/
263-
264-
export async function verifyKeysNotDisplayedInTheList(keyNames: string[]): Promise<void> {
265-
for (const keyName of keyNames) {
266-
await t.expect(await browserPage.isKeyIsDisplayedInTheList(keyName)).notOk(`The key ${keyName} found`);
256+
isDisplayed
257+
? await t.expect(browserPage.getKeySelectorByName(keyName).exists).ok(`The key ${keyName} not found`)
258+
: await t.expect(await browserPage.isKeyIsDisplayedInTheList(keyName)).notOk(`The key ${keyName} found`);
267259
}
268260
}
269261

270262
/**
271263
* Verify search/filter value
272264
* @param value The value in search/filter input
273265
*/
274-
275266
export async function verifySearchFilterValue(value: string): Promise<void> {
276267
await t.expect(browserPage.filterByPatterSearchInput.withAttribute('value', value).exists).ok(`Filter per key name ${value} is not applied/correct`);
277268
}

tests/e2e/pageObjects/browser-page.ts

Lines changed: 12 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { t, Selector } from 'testcafe';
22
import { Common } from '../helpers/common';
33
import { InstancePage } from './instance-page';
4-
import { BulkActions } from './components/browser';
4+
import { BulkActions, TreeView } from './components/browser';
55

66
export class BrowserPage extends InstancePage {
77
BulkActions = new BulkActions();
8+
TreeView = new TreeView();
89

910
//CSS Selectors
1011
cssSelectorGrid = '[aria-label="grid"]';
@@ -71,13 +72,9 @@ export class BrowserPage extends InstancePage {
7172
databaseInfoIcon = Selector('[data-testid=db-info-icon]');
7273
treeViewButton = Selector('[data-testid=view-type-list-btn]');
7374
browserViewButton = Selector('[data-testid=view-type-browser-btn]');
74-
treeViewSeparator = Selector('[data-testid=tree-view-delimiter-btn]');
7575
searchButton = Selector('[data-testid=search-btn]');
7676
clearFilterButton = Selector('[data-testid=reset-filter-btn]');
7777
clearSelectionButton = Selector('[data-testid=clear-selection-btn]');
78-
treeViewDelimiterButton = Selector('[data-testid=tree-view-delimiter-btn]');
79-
treeViewDelimiterValueSave = Selector('[data-testid=apply-btn]');
80-
treeViewDelimiterValueCancel = Selector('[data-testid=cancel-btn]');
8178
fullScreenModeButton = Selector('[data-testid=toggle-full-screen]');
8279
closeRightPanel = Selector('[data-testid=close-right-panel-btn]');
8380
addNewStreamEntry = Selector('[data-testid=add-key-value-items-btn]');
@@ -177,7 +174,6 @@ export class BrowserPage extends InstancePage {
177174
jsonKeyInput = Selector('[data-testid=json-key]');
178175
jsonValueInput = Selector('[data-testid=json-value]');
179176
countInput = Selector('[data-testid=count-input]');
180-
treeViewDelimiterInput = Selector('[data-testid=tree-view-delimiter-input]');
181177
streamEntryId = Selector('[data-testid=entryId]');
182178
streamField = Selector('[data-testid=field-name]');
183179
streamValue = Selector('[data-testid=field-value]');
@@ -212,27 +208,19 @@ export class BrowserPage extends InstancePage {
212208
jsonError = Selector('[data-testid=edit-json-error]');
213209
tooltip = Selector('[role=tooltip]');
214210
noResultsFound = Selector('[data-test-subj=no-result-found]');
211+
noResultsFoundOnly = Selector('[data-testid=no-result-found-only]');
215212
searchAdvices = Selector('[data-test-subj=search-advices]');
216213
keysNumberOfResults = Selector('[data-testid=keys-number-of-results]');
217214
keysTotalNumber = Selector('[data-testid=keys-total]');
218215
overviewConnectedClients = Selector('[data-test-subj=overview-connected-clients]');
219216
overviewCommandsSec = Selector('[data-test-subj=overview-commands-sec]');
220217
overviewCpu = Selector('[data-test-subj=overview-cpu]');
221-
treeViewArea = Selector('[data-test-subj=tree-view-panel]');
222218
scannedValue = Selector('[data-testid=keys-number-of-scanned]');
223-
treeViewKeysNumber = Selector('[data-testid^=count_]');
224-
treeViewPercentage = Selector('[data-testid^=percentage_]');
225-
treeViewFolders = Selector('[data-test-subj^=node-arrow-icon_]');
226219
totalKeysNumber = Selector('[data-testid=keys-total]');
227220
databaseInfoToolTip = Selector('[data-testid=db-info-tooltip]');
228-
treeViewDeviceFolder = Selector('[data-testid^=node-item_device] div');
229-
treeViewDeviceKyesCount = Selector('[data-testid^=count_device] span');
230221
ttlValueInKeysTable = Selector('[data-testid^=ttl-]');
231222
stringKeyValue = Selector('.key-details-body pre');
232223
keyDetailsBadge = Selector('.key-details-header .euiBadge__text');
233-
treeViewKeysItem = Selector('[data-testid*="keys:keys:"]');
234-
treeViewNotPatternedKeys = Selector('[data-testid*="node-item_keys"]');
235-
treeViewNodeArrowIcon = Selector('[data-test-subj^=node-arrow-icon_]');
236224
modulesTypeDetails = Selector('[data-testid=modules-type-details]');
237225
filteringLabel = Selector('[data-testid^=badge-]');
238226
keysSummary = Selector('[data-testid=keys-summary]');
@@ -590,6 +578,7 @@ export class BrowserPage extends InstancePage {
590578

591579
/**
592580
* Delete Key By name after Hovering
581+
* @param keyName The name of the key
593582
*/
594583
async deleteKeyByNameFromList(keyName: string): Promise<void> {
595584
await this.searchByKeyName(keyName);
@@ -766,7 +755,10 @@ export class BrowserPage extends InstancePage {
766755
.click(this.saveMemberButton);
767756
}
768757

769-
//Open key details
758+
/**
759+
* Open key details with search
760+
* @param keyName The name of the key
761+
*/
770762
async openKeyDetails(keyName: string): Promise<void> {
771763
await this.searchByKeyName(keyName);
772764
await t.click(this.keyNameInTheList);
@@ -878,66 +870,6 @@ export class BrowserPage extends InstancePage {
878870
await t.typeText(this.jsonValueInput, jsonStructure, { replace: true, paste: true });
879871
await t.click(this.applyEditButton);
880872
}
881-
/**
882-
* Check tree view structure
883-
* @folders name of folders for tree view build
884-
* @delimiter string with delimiter value
885-
* @commonKeyFolder flag if not patterned keys will be displayed
886-
*/
887-
async checkTreeViewFoldersStructure(folders: string[][], delimiter: string, commonKeyFolder: boolean): Promise<void> {
888-
// Verify that all keys that are not inside of tree view doesn't contain delimiter
889-
if (commonKeyFolder) {
890-
await t
891-
.expect(this.treeViewNotPatternedKeys.exists).ok('Folder with not patterned keys')
892-
.click(this.treeViewNotPatternedKeys);
893-
const notPatternedKeys = Selector('[data-test-subj=key-list-panel]').find(this.cssSelectorKey);
894-
const notPatternedKeysNumber = await notPatternedKeys.count;
895-
for (let i = 0; i < notPatternedKeysNumber; i++) {
896-
await t.expect(notPatternedKeys.nth(i).withText(delimiter).exists).notOk('Not contained delimiter keys');
897-
}
898-
}
899-
// Verify that every level of tree view is clickable
900-
const foldersNumber = folders.length;
901-
for (let i = 0; i < foldersNumber; i++) {
902-
const innerFoldersNumber = folders[i].length;
903-
const array: string[] = [];
904-
for (let j = 0; j < innerFoldersNumber; j++) {
905-
if (j === 0) {
906-
const folderSelector = `[data-testid="node-item_${folders[i][j]}${delimiter}"]`;
907-
array.push(folderSelector);
908-
await t.click(Selector(folderSelector));
909-
}
910-
else {
911-
const lastSelector = array[array.length - 1].substring(0, array[array.length - 1].length - 2);
912-
const folderSelector = `${lastSelector}${folders[i][j]}${delimiter}"]`;
913-
array.push(folderSelector);
914-
await t.click(Selector(folderSelector));
915-
}
916-
}
917-
// Verify that the last folder level contains required keys
918-
const lastSelector = array[array.length - 1].substring(0, array[array.length - 1].length - 2);
919-
const folderSelector = `${lastSelector}keys${delimiter}keys${delimiter}"]`;
920-
await t.click(Selector(folderSelector));
921-
const foundKeyName = `${folders[i].join(delimiter)}`;
922-
await t
923-
.expect(Selector(`[data-testid*="key-${foundKeyName}"]`).exists).ok('Specific key not found')
924-
.click(array[0]);
925-
}
926-
}
927-
928-
/**
929-
* Change delimiter value
930-
* @delimiter string with delimiter value
931-
*/
932-
async changeDelimiterInTreeView(delimiter: string): Promise<void> {
933-
// Open delimiter popup
934-
await t.click(this.treeViewDelimiterButton);
935-
// Apply new value to the field
936-
await t.typeText(this.treeViewDelimiterInput, delimiter, { replace: true, paste: true });
937-
// Click on save button
938-
await t.click(this.treeViewDelimiterValueSave);
939-
await t.expect(this.treeViewDelimiterButton.withExactText(delimiter).exists).ok('Delimiter is not changed');
940-
}
941873

942874
//Delete entry from Stream key
943875
async deleteStreamEntry(): Promise<void> {
@@ -1019,33 +951,6 @@ export class BrowserPage extends InstancePage {
1019951
.click(option);
1020952
}
1021953

1022-
/**
1023-
* Get text from first tree element
1024-
*/
1025-
async getTextFromNthTreeElement(number: number): Promise<string> {
1026-
return (await Selector('[role="treeitem"]').nth(number).find('div').textContent).replace(/\s/g, '');
1027-
}
1028-
1029-
/**
1030-
* Open tree folder with multiple level
1031-
* @param names folder names with sequence of subfolder
1032-
*/
1033-
async openTreeFolders(names: string[]): Promise<void> {
1034-
let base = `node-item_${names[0]}:`;
1035-
await t.click(Selector(`[data-testid="${base}"]`));
1036-
if (names.length > 1) {
1037-
for (let i = 1; i < names.length; i++) {
1038-
base = `${base }${names[i]}:`;
1039-
await t.click(Selector(`[data-testid="${base}"]`));
1040-
}
1041-
}
1042-
await t.click(Selector(`[data-testid="${base}keys:keys:"]`));
1043-
1044-
await t.expect(
1045-
Selector(`[data-testid="${base}keys:keys:"]`).visible)
1046-
.ok('Folder is not selected');
1047-
}
1048-
1049954
/**
1050955
* Verify that database has no keys
1051956
*/
@@ -1061,6 +966,10 @@ export class BrowserPage extends InstancePage {
1061966
await t.click(this.clearFilterButton);
1062967
}
1063968

969+
/**
970+
* Open Guide link by name
971+
* @param guide The guide name
972+
*/
1064973
async clickGuideLinksByName(guide: string): Promise<void> {
1065974
const linkGuide = Selector(`[data-testid="guide-button-${guide}"]`);
1066975
await t.click(linkGuide);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { BulkActions } from './bulk-actions';
2+
import { TreeView } from './tree-view';
23

34
export {
4-
BulkActions
5+
BulkActions,
6+
TreeView,
57
};

0 commit comments

Comments
 (0)