Skip to content

Commit df5e07b

Browse files
test(ObjectSummary): properly find virtualized tree element (#1863)
1 parent 7e0429b commit df5e07b

File tree

2 files changed

+77
-7
lines changed

2 files changed

+77
-7
lines changed

tests/suites/tenant/summary/ObjectSummary.ts

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ export enum ObjectSummaryTab {
1212
Schema = 'Schema',
1313
}
1414
export class ObjectSummary {
15+
private page: Page;
1516
private tabs: Locator;
1617
private schemaViewer: Locator;
1718
private tree: Locator;
1819
private treeRows: Locator;
20+
private treeLoaders: Locator;
1921
private primaryKeys: Locator;
2022
private actionsMenu: ActionsMenu;
2123
private aclWrapper: Locator;
@@ -34,8 +36,10 @@ export class ObjectSummary {
3436
private overviewWrapper: Locator;
3537

3638
constructor(page: Page) {
39+
this.page = page;
3740
this.tree = page.locator('.ydb-object-summary__tree');
3841
this.treeRows = page.locator('.ydb-tree-view');
42+
this.treeLoaders = page.locator('.ydb-navigation-tree-view-loader');
3943
this.tabs = page.locator('.ydb-object-summary__tabs');
4044
this.schemaViewer = page.locator('.schema-viewer');
4145
this.primaryKeys = page.locator('.schema-viewer__keys_type_primary');
@@ -166,6 +170,16 @@ export class ObjectSummary {
166170
return true;
167171
}
168172

173+
async isTreeLoaded() {
174+
const loaders = await this.treeLoaders.all();
175+
176+
for (const loader of loaders) {
177+
await loader.waitFor({state: 'hidden', timeout: VISIBILITY_TIMEOUT});
178+
}
179+
180+
return true;
181+
}
182+
169183
async isTreeHidden() {
170184
await this.tree.waitFor({state: 'hidden', timeout: VISIBILITY_TIMEOUT});
171185
return true;
@@ -181,8 +195,61 @@ export class ObjectSummary {
181195
return true;
182196
}
183197

198+
async getTreeItem(text: string) {
199+
// Ensure tree is ready for the search
200+
await this.isTreeVisible();
201+
await this.isTreeLoaded();
202+
203+
const itemLocator = this.treeRows.filter({hasText: text}).first();
204+
205+
// Default timeout is too big for such case
206+
const timeout = 500;
207+
208+
if (await itemLocator.isVisible({timeout})) {
209+
return itemLocator;
210+
}
211+
212+
// Element could be in not rendered (virtualized) part of the tree
213+
// Such element cannot be found by playwright
214+
// Scroll 200px * 10 from top to bottom to find element
215+
// Firstly scroll to top in case tree was already scrolled down
216+
await this.tree.evaluate((e) => {
217+
e.scrollTo({top: 0, behavior: 'instant'});
218+
});
219+
220+
// Wait after scroll for elements to become stable
221+
await this.page.waitForTimeout(50);
222+
223+
if (await itemLocator.isVisible({timeout})) {
224+
return itemLocator;
225+
}
226+
227+
// Hover element so page.mouse.wheel work for it
228+
await this.tree.hover();
229+
230+
// Start scrolling from top to bottom untill desired element is found
231+
let i = 0;
232+
while (i < 10) {
233+
i++;
234+
235+
await this.page.mouse.wheel(0, 200);
236+
237+
// Wait after scroll for elements to become stable
238+
await this.page.waitForTimeout(50);
239+
240+
// Some nested nodes could be loading
241+
await this.isTreeLoaded();
242+
243+
if (await itemLocator.isVisible({timeout})) {
244+
return itemLocator;
245+
}
246+
}
247+
248+
throw new Error(`Tree item ${text} was not found`);
249+
}
250+
184251
async isOpenPreviewIconVisibleOnHover(text: string): Promise<boolean> {
185-
const treeItem = this.treeRows.filter({hasText: text}).first();
252+
const treeItem = await this.getTreeItem(text);
186253
await treeItem.hover();
187254

188255
const openPreviewIcon = treeItem.locator('button[title="Open preview"]');
@@ -196,15 +263,15 @@ export class ObjectSummary {
196263
}
197264

198265
async clickPreviewButton(text: string): Promise<void> {
199-
const treeItem = this.treeRows.filter({hasText: text}).first();
266+
const treeItem = await this.getTreeItem(text);
200267
await treeItem.hover();
201268

202269
const openPreviewIcon = treeItem.locator('button[title="Open preview"]');
203270
await openPreviewIcon.click();
204271
}
205272

206273
async clickActionsButton(text: string): Promise<void> {
207-
const treeItem = this.treeRows.filter({hasText: text}).first();
274+
const treeItem = await this.getTreeItem(text);
208275
await treeItem.hover();
209276

210277
const actionsIcon = treeItem.locator('.g-dropdown-menu__switcher-button');

tests/suites/tenant/summary/objectSummary.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ test.describe('Object Summary', async () => {
251251
await objectSummary.createDirectory(directoryName);
252252

253253
// Verify the new directory appears in the tree
254-
const treeItem = page.locator('.ydb-tree-view').filter({hasText: directoryName});
254+
const treeItem = await objectSummary.getTreeItem(directoryName);
255255
await expect(treeItem).toBeVisible();
256256
});
257257

@@ -276,14 +276,17 @@ test.describe('Object Summary', async () => {
276276
await queryEditor.waitForStatus('Completed');
277277

278278
// Verify table is not visible before refresh
279-
const treeItemBeforeRefresh = page.locator('.ydb-tree-view').filter({hasText: tableName});
280-
await expect(treeItemBeforeRefresh).not.toBeVisible();
279+
try {
280+
await objectSummary.getTreeItem(tableName);
281+
} catch (error) {
282+
expect(error).toBeTruthy();
283+
}
281284

282285
// Click refresh button to update tree view
283286
await objectSummary.clickRefreshButton();
284287

285288
// Verify table appears in tree
286-
const treeItemAfterRefresh = page.locator('.ydb-tree-view').filter({hasText: tableName});
289+
const treeItemAfterRefresh = await objectSummary.getTreeItem(tableName);
287290
await expect(treeItemAfterRefresh).toBeVisible();
288291
});
289292

0 commit comments

Comments
 (0)