Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/containers/Node/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,25 @@ export function Node() {

const isStorageNode = node?.Roles?.find((el) => el === STORAGE_ROLE);

const threadsQuantity = node?.Threads?.length;

const {activeTab, nodeTabs} = React.useMemo(() => {
let actulaNodeTabs = isStorageNode
let actualNodeTabs = isStorageNode
? NODE_TABS
: NODE_TABS.filter((el) => el.id !== 'storage');
if (isDiskPagesAvailable) {
actulaNodeTabs = actulaNodeTabs.filter((el) => el.id !== 'structure');
actualNodeTabs = actualNodeTabs.filter((el) => el.id !== 'structure');
}
// Filter out threads tab if there's no thread data in the API response
if (!threadsQuantity) {
actualNodeTabs = actualNodeTabs.filter((el) => el.id !== 'threads');
}

const actualActiveTab =
actulaNodeTabs.find(({id}) => id === activeTabId) ?? actulaNodeTabs[0];
actualNodeTabs.find(({id}) => id === activeTabId) ?? actualNodeTabs[0];

return {activeTab: actualActiveTab, nodeTabs: actulaNodeTabs};
}, [isStorageNode, isDiskPagesAvailable, activeTabId]);
return {activeTab: actualActiveTab, nodeTabs: actualNodeTabs};
}, [isStorageNode, isDiskPagesAvailable, activeTabId, threadsQuantity]);

const tenantName = node?.Tenants?.[0] || tenantNameFromQuery?.toString();

Expand Down
51 changes: 51 additions & 0 deletions tests/suites/nodes/NodePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type {Locator, Page} from '@playwright/test';

import {PageModel} from '../../models/PageModel';
import {VISIBILITY_TIMEOUT} from '../tenant/TenantPage';

export class NodePage extends PageModel {
readonly tabs: Locator;
readonly threadsTab: Locator;
readonly tabletsTab: Locator;
readonly storageTab: Locator;

constructor(page: Page, nodeId: string) {
super(page, `node/${nodeId}`);

this.tabs = this.selector.locator('.node__tab-list');
this.threadsTab = this.tabs.locator('[value="threads"]');
this.tabletsTab = this.tabs.locator('[value="tablets"]');
this.storageTab = this.tabs.locator('[value="storage"]');
}

async waitForNodePageLoad() {
// Wait for the page to load and tabs to be visible
try {
await this.tabs.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
} catch (error) {
console.error('Failed to load node page tabs:', error);
throw error;
}
}

async isThreadsTabVisible() {
const threadsTab = this.tabs.locator('.g-tab:has-text("Threads")');
try {
await threadsTab.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
return true;
} catch {
console.error('Threads tab is not visible');
return false;
}
}

async clickThreadsTab() {
const threadsTab = this.tabs.locator('.g-tab:has-text("Threads")');
await threadsTab.click();
}

async getAllTabNames() {
const tabs = await this.tabs.locator('.g-tab').allTextContents();
return tabs;
}
}
109 changes: 109 additions & 0 deletions tests/suites/nodes/nodes.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {expect, test} from '@playwright/test';

import {backend} from '../../utils/constants';
import {NodePage} from '../nodes/NodePage';
import {NodesPage} from '../nodes/NodesPage';
import {ClusterNodesTable} from '../paginatedTable/paginatedTable';

Expand Down Expand Up @@ -193,3 +194,111 @@ test.describe('Test Nodes Paginated Table', async () => {
expect(hostValues.length).toBeGreaterThan(0);
});
});

test.describe('Test Node Page Threads Tab', async () => {
test('Threads tab is hidden when node has no thread data', async ({page}) => {
// Mock the node API to return no thread data
await page.route(`**/viewer/json/sysinfo?*`, async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
SystemStateInfo: [
{
Host: 'localhost',
NodeId: 1,
SystemState: 'Green',
Version: 'test-version',
},
],
// No Threads property
}),
});
});

// Navigate directly to node page
const nodePage = new NodePage(page, '1');
await nodePage.goto();
await nodePage.waitForNodePageLoad();

// Verify other tabs are still visible
const tabNames = await nodePage.getAllTabNames();
expect(tabNames).toContain('Tablets');
expect(tabNames).not.toContain('Threads');
});

test('Threads tab is visible when node has thread data', async ({page}) => {
// Mock the node API to return thread data
await page.route(`**/viewer/json/sysinfo?*`, async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
SystemStateInfo: [
{
Host: 'localhost',
NodeId: 1,
SystemState: 'Green',
Version: 'test-version',
Threads: [
{
Name: 'TestPool',
Threads: 4,
},
],
},
],
}),
});
});

// Navigate directly to node page
const nodePage = new NodePage(page, '1');
await nodePage.goto();
await nodePage.waitForNodePageLoad();

// Verify threads tab is visible
const isThreadsTabVisible = await nodePage.isThreadsTabVisible();
expect(isThreadsTabVisible).toBe(true);

// Verify can click on threads tab
await nodePage.clickThreadsTab();
await page.waitForURL(/\/node\/\d+\/threads/);

// Verify other tabs are also visible
const tabNames = await nodePage.getAllTabNames();
expect(tabNames).toContain('Tablets');
expect(tabNames).toContain('Threads');
});

test('Threads tab is hidden when node has empty thread array', async ({page}) => {
// Mock the node API to return empty thread data
await page.route(`**/viewer/json/sysinfo?*`, async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
SystemStateInfo: [
{
Host: 'localhost',
NodeId: 1,
SystemState: 'Green',
Version: 'test-version',
},
],
Threads: [], // Empty array
}),
});
});

// Navigate directly to node page
const nodePage = new NodePage(page, '1');
await nodePage.goto();
await nodePage.waitForNodePageLoad();

// Verify other tabs are still visible
const tabNames = await nodePage.getAllTabNames();
expect(tabNames).toContain('Tablets');
expect(tabNames).not.toContain('Threads');
});
});
Loading