Skip to content

Commit f07b7c3

Browse files
CopilotRaubzeug
andcommitted
fix: move tests to e2e suite and fix node Threads data flow
Co-authored-by: Raubzeug <[email protected]>
1 parent 48ab220 commit f07b7c3

File tree

5 files changed

+204
-86
lines changed

5 files changed

+204
-86
lines changed

src/containers/Node/__tests__/Node.test.ts

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/store/reducers/node/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type {TThreadPoolInfo} from '../../../types/api/threads';
12
import type {PreparedPDisk, PreparedVDisk} from '../../../utils/disks/types';
23
import type {PreparedNodeSystemState} from '../../../utils/nodes';
34

@@ -18,4 +19,6 @@ export interface PreparedStructurePDisk extends PreparedPDisk {
1819

1920
export type PreparedNodeStructure = Record<string, PreparedStructurePDisk>;
2021

21-
export interface PreparedNode extends Partial<PreparedNodeSystemState> {}
22+
export interface PreparedNode extends Partial<PreparedNodeSystemState> {
23+
Threads?: TThreadPoolInfo[];
24+
}

src/store/reducers/node/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ export const prepareNodeData = (data: TEvSystemStateResponse): PreparedNode => {
99
}
1010

1111
const nodeData = data.SystemStateInfo[0];
12+
13+
const preparedSystemState = prepareNodeSystemState(nodeData);
1214

13-
return prepareNodeSystemState(nodeData);
15+
// Include Threads from the top-level response for the tab filtering logic
16+
return {
17+
...preparedSystemState,
18+
Threads: data.Threads,
19+
};
1420
};

tests/suites/nodes/NodePage.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type {Locator, Page} from '@playwright/test';
2+
3+
import {PageModel} from '../../models/PageModel';
4+
5+
export class NodePage extends PageModel {
6+
readonly tabs: Locator;
7+
readonly threadsTab: Locator;
8+
readonly tabletsTab: Locator;
9+
readonly storageTab: Locator;
10+
11+
constructor(page: Page, nodeId: string) {
12+
super(page, `node/${nodeId}`);
13+
14+
this.tabs = this.selector.locator('.node__tab-list');
15+
this.threadsTab = this.tabs.locator('[value="threads"]');
16+
this.tabletsTab = this.tabs.locator('[value="tablets"]');
17+
this.storageTab = this.tabs.locator('[value="storage"]');
18+
}
19+
20+
async waitForNodePageLoad() {
21+
// Wait for the page to load and tabs to be visible
22+
await this.tabs.waitFor({state: 'visible'});
23+
}
24+
25+
async isThreadsTabVisible() {
26+
try {
27+
await this.threadsTab.waitFor({state: 'visible', timeout: 1000});
28+
return true;
29+
} catch {
30+
return false;
31+
}
32+
}
33+
34+
async clickThreadsTab() {
35+
await this.threadsTab.click();
36+
}
37+
38+
async getAllTabNames() {
39+
const tabs = await this.tabs.locator('.g-tabs__item').allTextContents();
40+
return tabs;
41+
}
42+
}

tests/suites/nodes/nodes.test.ts

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

33
import {backend} from '../../utils/constants';
44
import {NodesPage} from '../nodes/NodesPage';
5+
import {NodePage} from '../nodes/NodePage';
56
import {ClusterNodesTable} from '../paginatedTable/paginatedTable';
67

78
test.describe('Test Nodes page', async () => {
@@ -193,3 +194,153 @@ test.describe('Test Nodes Paginated Table', async () => {
193194
expect(hostValues.length).toBeGreaterThan(0);
194195
});
195196
});
197+
198+
test.describe('Test Node Page Threads Tab', async () => {
199+
test('Threads tab is hidden when node has no thread data', async ({page}) => {
200+
// Mock the node API to return no thread data
201+
await page.route(`${backend}/viewer/json/sysinfo?*`, async (route) => {
202+
await route.fulfill({
203+
json: {
204+
SystemStateInfo: [{
205+
Host: 'localhost',
206+
NodeId: 1,
207+
SystemState: 1, // Green
208+
Version: 'test-version',
209+
}],
210+
// No Threads property
211+
}
212+
});
213+
});
214+
215+
const nodesPage = new NodesPage(page);
216+
await nodesPage.goto();
217+
218+
// Get first node ID to navigate to
219+
const paginatedTable = new ClusterNodesTable(page);
220+
await paginatedTable.waitForTableToLoad();
221+
await paginatedTable.waitForTableData();
222+
223+
// Click on first node to navigate to node page
224+
const firstRowLink = page.locator('.ydb-paginated-table__table tbody tr:first-child a').first();
225+
await firstRowLink.click();
226+
227+
// Wait for navigation to complete
228+
await page.waitForURL(/\/node\/\d+/);
229+
230+
const nodeId = await page.url().match(/\/node\/(\d+)/)?.[1];
231+
expect(nodeId).toBeDefined();
232+
233+
const nodePage = new NodePage(page, nodeId!);
234+
await nodePage.waitForNodePageLoad();
235+
236+
// Verify threads tab is not visible
237+
const isThreadsTabVisible = await nodePage.isThreadsTabVisible();
238+
expect(isThreadsTabVisible).toBe(false);
239+
240+
// Verify other tabs are still visible
241+
const tabNames = await nodePage.getAllTabNames();
242+
expect(tabNames).toContain('Tablets');
243+
expect(tabNames).not.toContain('Threads');
244+
});
245+
246+
test('Threads tab is visible when node has thread data', async ({page}) => {
247+
// Mock the node API to return thread data
248+
await page.route(`${backend}/viewer/json/sysinfo?*`, async (route) => {
249+
await route.fulfill({
250+
json: {
251+
SystemStateInfo: [{
252+
Host: 'localhost',
253+
NodeId: 1,
254+
SystemState: 1, // Green
255+
Version: 'test-version',
256+
}],
257+
Threads: [{
258+
Name: 'TestPool',
259+
Threads: 4
260+
}]
261+
}
262+
});
263+
});
264+
265+
const nodesPage = new NodesPage(page);
266+
await nodesPage.goto();
267+
268+
// Get first node ID to navigate to
269+
const paginatedTable = new ClusterNodesTable(page);
270+
await paginatedTable.waitForTableToLoad();
271+
await paginatedTable.waitForTableData();
272+
273+
// Click on first node to navigate to node page
274+
const firstRowLink = page.locator('.ydb-paginated-table__table tbody tr:first-child a').first();
275+
await firstRowLink.click();
276+
277+
// Wait for navigation to complete
278+
await page.waitForURL(/\/node\/\d+/);
279+
280+
const nodeId = await page.url().match(/\/node\/(\d+)/)?.[1];
281+
expect(nodeId).toBeDefined();
282+
283+
const nodePage = new NodePage(page, nodeId!);
284+
await nodePage.waitForNodePageLoad();
285+
286+
// Verify threads tab is visible
287+
const isThreadsTabVisible = await nodePage.isThreadsTabVisible();
288+
expect(isThreadsTabVisible).toBe(true);
289+
290+
// Verify can click on threads tab
291+
await nodePage.clickThreadsTab();
292+
await page.waitForURL(/\/node\/\d+\/threads/);
293+
294+
// Verify other tabs are also visible
295+
const tabNames = await nodePage.getAllTabNames();
296+
expect(tabNames).toContain('Tablets');
297+
expect(tabNames).toContain('Threads');
298+
});
299+
300+
test('Threads tab is hidden when node has empty thread array', async ({page}) => {
301+
// Mock the node API to return empty thread data
302+
await page.route(`${backend}/viewer/json/sysinfo?*`, async (route) => {
303+
await route.fulfill({
304+
json: {
305+
SystemStateInfo: [{
306+
Host: 'localhost',
307+
NodeId: 1,
308+
SystemState: 1, // Green
309+
Version: 'test-version',
310+
}],
311+
Threads: [] // Empty array
312+
}
313+
});
314+
});
315+
316+
const nodesPage = new NodesPage(page);
317+
await nodesPage.goto();
318+
319+
// Get first node ID to navigate to
320+
const paginatedTable = new ClusterNodesTable(page);
321+
await paginatedTable.waitForTableToLoad();
322+
await paginatedTable.waitForTableData();
323+
324+
// Click on first node to navigate to node page
325+
const firstRowLink = page.locator('.ydb-paginated-table__table tbody tr:first-child a').first();
326+
await firstRowLink.click();
327+
328+
// Wait for navigation to complete
329+
await page.waitForURL(/\/node\/\d+/);
330+
331+
const nodeId = await page.url().match(/\/node\/(\d+)/)?.[1];
332+
expect(nodeId).toBeDefined();
333+
334+
const nodePage = new NodePage(page, nodeId!);
335+
await nodePage.waitForNodePageLoad();
336+
337+
// Verify threads tab is not visible
338+
const isThreadsTabVisible = await nodePage.isThreadsTabVisible();
339+
expect(isThreadsTabVisible).toBe(false);
340+
341+
// Verify other tabs are still visible
342+
const tabNames = await nodePage.getAllTabNames();
343+
expect(tabNames).toContain('Tablets');
344+
expect(tabNames).not.toContain('Threads');
345+
});
346+
});

0 commit comments

Comments
 (0)