Skip to content

Commit ad8b74a

Browse files
committed
chore: more tests
1 parent 9ac7047 commit ad8b74a

File tree

3 files changed

+175
-12
lines changed

3 files changed

+175
-12
lines changed

tests/suites/paginatedTable/mocks.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type {Page} from '@playwright/test';
22

33
import {backend} from '../../utils/constants';
44

5+
const MOCK_DELAY = 200; // 200ms delay to simulate network latency
6+
57
interface NodeMockOptions {
68
offset: number;
79
limit: number;
@@ -52,6 +54,8 @@ export const setupNodesMock = async (page: Page) => {
5254

5355
const nodes = await generateNodeMock({offset, limit});
5456

57+
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
58+
5559
await route.fulfill({
5660
status: 200,
5761
contentType: 'application/json',
@@ -65,8 +69,54 @@ export const setupNodesMock = async (page: Page) => {
6569
});
6670
};
6771

72+
export const setupEmptyNodesMock = async (page: Page) => {
73+
await page.route(`${backend}/viewer/json/nodes?*`, async (route) => {
74+
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
75+
76+
await route.fulfill({
77+
status: 200,
78+
contentType: 'application/json',
79+
body: JSON.stringify({
80+
Overall: 'Green',
81+
Nodes: [],
82+
TotalNodes: '0',
83+
FoundNodes: '0',
84+
}),
85+
});
86+
});
87+
};
88+
89+
export const setupLargeNodesMock = async (page: Page, totalNodes = 1000) => {
90+
await page.route(`${backend}/viewer/json/nodes?*`, async (route) => {
91+
const url = new URL(route.request().url());
92+
const offset = parseInt(url.searchParams.get('offset') || '0', 10);
93+
const limit = parseInt(url.searchParams.get('limit') || '100', 10);
94+
95+
// Generate nodes for the requested chunk
96+
const nodes = await generateNodeMock({
97+
offset,
98+
limit: Math.min(limit, totalNodes - offset), // Ensure we don't generate more than total
99+
});
100+
101+
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
102+
103+
await route.fulfill({
104+
status: 200,
105+
contentType: 'application/json',
106+
body: JSON.stringify({
107+
Overall: 'Green',
108+
Nodes: nodes,
109+
TotalNodes: totalNodes.toString(),
110+
FoundNodes: totalNodes.toString(),
111+
}),
112+
});
113+
});
114+
};
115+
68116
export const setupSettingsMock = async (page: Page) => {
69117
await page.route(`${backend}/api/settings`, async (route) => {
118+
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
119+
70120
await route.fulfill({
71121
status: 200,
72122
contentType: 'application/json',

tests/suites/paginatedTable/paginatedTable.test.ts

Lines changed: 102 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {expect, test} from '@playwright/test';
22

33
import {NodesPage} from '../nodes/NodesPage';
44

5-
import {setupNodesMock, setupSettingsMock} from './mocks';
5+
import {setupEmptyNodesMock, setupLargeNodesMock, setupNodesMock, setupSettingsMock} from './mocks';
66
import {PaginatedTable} from './paginatedTable';
77

88
test.describe('PaginatedTable', () => {
@@ -29,17 +29,7 @@ test.describe('PaginatedTable', () => {
2929
expect(firstRowData['Host']).toBe('host-0.test');
3030
expect(firstRowData['Version']).toBe('main.b7cfb36');
3131

32-
// Scroll to bottom of container
33-
await page.evaluate(() => {
34-
const container = document.querySelector('.ydb-cluster');
35-
if (container) {
36-
// Force scroll to bottom
37-
container.scrollTo({
38-
top: container.scrollHeight,
39-
behavior: 'instant',
40-
});
41-
}
42-
});
32+
await paginatedTable.scrollToBottom();
4333

4434
await paginatedTable.waitForTableData();
4535

@@ -55,4 +45,104 @@ test.describe('PaginatedTable', () => {
5545
expect(uptime).toMatch(/^(\d+d\s)?(\d+):(\d{2}):(\d{2})$/); // Format: DDd? HH:MM:SS
5646
}
5747
});
48+
49+
test.only('loads data when scrolling to middle of table', async ({page}) => {
50+
// Setup mocks with large dataset
51+
await setupLargeNodesMock(page);
52+
await setupSettingsMock(page);
53+
54+
// Navigate to nodes page which uses PaginatedTable
55+
const nodesPage = new NodesPage(page);
56+
await nodesPage.goto();
57+
58+
const paginatedTable = new PaginatedTable(page);
59+
await paginatedTable.waitForTableVisible();
60+
await paginatedTable.waitForTableData();
61+
62+
// Get initial row count
63+
const initialVisibleRows = await paginatedTable.getRowCount();
64+
expect(initialVisibleRows).toBeGreaterThan(0);
65+
expect(initialVisibleRows).toBeLessThan(1000); // Should not show all rows initially
66+
67+
// Scroll to middle of container
68+
await paginatedTable.scrollToMiddle();
69+
await paginatedTable.waitForTableData();
70+
71+
// Get data from middle rows to verify middle chunk loaded
72+
const rowCount = await paginatedTable.getRowCount();
73+
const middleRowIndex = Math.floor(rowCount / 2);
74+
const middleRowData = await paginatedTable.getRowData(middleRowIndex);
75+
expect(middleRowData['Host']).toBe('host-500.test');
76+
expect(middleRowData['Version']).toBe('main.b7cfb36');
77+
});
78+
79+
test('displays empty state when no data is present', async ({page}) => {
80+
// Setup mocks with empty data
81+
await setupEmptyNodesMock(page);
82+
await setupSettingsMock(page);
83+
84+
const nodesPage = new NodesPage(page);
85+
await nodesPage.goto();
86+
87+
const paginatedTable = new PaginatedTable(page);
88+
await paginatedTable.waitForTableVisible();
89+
90+
// Verify empty state
91+
const rowCount = await paginatedTable.getRowCount();
92+
expect(rowCount).toBe(1);
93+
const emptyDataMessage = await paginatedTable.getEmptyDataMessageLocator();
94+
await expect(emptyDataMessage).toContainText('No such nodes');
95+
});
96+
97+
test('handles 10 pages of data correctly', async ({page}) => {
98+
// Setup mocks with 1000 nodes (100 per page * 10 pages)
99+
await setupSettingsMock(page);
100+
await setupLargeNodesMock(page);
101+
102+
const nodesPage = new NodesPage(page);
103+
await nodesPage.goto();
104+
105+
const paginatedTable = new PaginatedTable(page);
106+
await paginatedTable.waitForTableVisible();
107+
await paginatedTable.waitForTableData();
108+
109+
// Verify initial data load
110+
const initialRowCount = await paginatedTable.getRowCount();
111+
expect(initialRowCount).toBeGreaterThan(0);
112+
expect(initialRowCount).toBeLessThan(1000); // Should not load all rows at once
113+
114+
await paginatedTable.scrollToBottom();
115+
await paginatedTable.waitForTableData();
116+
117+
// Verify we can load data from the last page
118+
const finalRowCount = await paginatedTable.getRowCount();
119+
const lastRowData = await paginatedTable.getRowData(finalRowCount - 1);
120+
expect(lastRowData['Host']).toBe('host-999.test'); // Last node in 1000 nodes (0-999)
121+
});
122+
123+
test('handles 100 pages of data correctly', async ({page}) => {
124+
// Setup mocks with 10000 nodes (100 per page * 10 pages)
125+
await setupSettingsMock(page);
126+
await setupLargeNodesMock(page, 10000);
127+
128+
const nodesPage = new NodesPage(page);
129+
await nodesPage.goto();
130+
131+
const paginatedTable = new PaginatedTable(page);
132+
await paginatedTable.waitForTableVisible();
133+
await paginatedTable.waitForTableData();
134+
135+
// Verify initial data load
136+
const initialRowCount = await paginatedTable.getRowCount();
137+
expect(initialRowCount).toBeGreaterThan(0);
138+
expect(initialRowCount).toBeLessThan(10000); // Should not load all rows at once
139+
140+
await paginatedTable.scrollToBottom();
141+
await paginatedTable.waitForTableData();
142+
143+
// Verify we can load data from the last page
144+
const finalRowCount = await paginatedTable.getRowCount();
145+
const lastRowData = await paginatedTable.getRowData(finalRowCount - 1);
146+
expect(lastRowData['Host']).toBe('host-9999.test'); // Last node in 1000 nodes (0-999)
147+
});
58148
});

tests/suites/paginatedTable/paginatedTable.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class PaginatedTable {
1414
private refreshIntervalSelect: Locator;
1515
private headCells: Locator;
1616
private columnSetupButton: Locator;
17+
private scrollContainer: string;
1718
private columnSetupPopup: Locator;
1819

1920
constructor(page: Page) {
@@ -31,6 +32,7 @@ export class PaginatedTable {
3132
'.g-tree-select.g-table-column-setup button',
3233
);
3334
this.columnSetupPopup = page.locator('.g-popup .g-select-popup.g-tree-select__popup');
35+
this.scrollContainer = '.ydb-cluster';
3436
}
3537

3638
async waitForTableVisible() {
@@ -173,6 +175,27 @@ export class PaginatedTable {
173175
return await checkIcon.isVisible();
174176
}
175177

178+
async scrollToBottom() {
179+
await this.page.evaluate((selector) => {
180+
const container = document.querySelector(selector);
181+
if (container) {
182+
container.scrollTo({top: container.scrollHeight, behavior: 'instant'});
183+
}
184+
}, this.scrollContainer);
185+
}
186+
187+
async scrollToMiddle() {
188+
await this.page.evaluate((selector) => {
189+
const container = document.querySelector(selector);
190+
if (container) {
191+
container.scrollTo({
192+
top: Math.floor(container.scrollHeight / 2),
193+
behavior: 'instant',
194+
});
195+
}
196+
}, this.scrollContainer);
197+
}
198+
176199
private async getColumnIndex(columnName: string): Promise<number> {
177200
const count = await this.headCells.count();
178201
for (let i = 0; i < count; i++) {

0 commit comments

Comments
 (0)