chore: add unit tests for hosts list in infra monitoring (#8230)

This commit is contained in:
Amlan Kumar Nandy 2025-06-18 12:53:42 +07:00 committed by GitHub
parent 75f62372ae
commit 66affb0ece
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 489 additions and 0 deletions

View File

@ -0,0 +1,43 @@
import { render, screen } from '@testing-library/react';
import HostsEmptyOrIncorrectMetrics from '../HostsEmptyOrIncorrectMetrics';
describe('HostsEmptyOrIncorrectMetrics', () => {
it('shows no data message when noData is true', () => {
render(<HostsEmptyOrIncorrectMetrics noData incorrectData={false} />);
expect(
screen.getByText('No host metrics data received yet.'),
).toBeInTheDocument();
expect(
screen.getByText(/Infrastructure monitoring requires the/),
).toBeInTheDocument();
});
it('shows incorrect data message when incorrectData is true', () => {
render(<HostsEmptyOrIncorrectMetrics noData={false} incorrectData />);
expect(
screen.getByText(
'To see host metrics, upgrade to the latest version of SigNoz k8s-infra chart. Please contact support if you need help.',
),
).toBeInTheDocument();
});
it('does not show no data message when noData is false', () => {
render(<HostsEmptyOrIncorrectMetrics noData={false} incorrectData={false} />);
expect(
screen.queryByText('No host metrics data received yet.'),
).not.toBeInTheDocument();
expect(
screen.queryByText(/Infrastructure monitoring requires the/),
).not.toBeInTheDocument();
});
it('does not show incorrect data message when incorrectData is false', () => {
render(<HostsEmptyOrIncorrectMetrics noData={false} incorrectData={false} />);
expect(
screen.queryByText(
'To see host metrics, upgrade to the latest version of SigNoz k8s-infra chart. Please contact support if you need help.',
),
).not.toBeInTheDocument();
});
});

View File

@ -0,0 +1,166 @@
/* eslint-disable react/button-has-type */
import { render } from '@testing-library/react';
import ROUTES from 'constants/routes';
import * as useGetHostListHooks from 'hooks/infraMonitoring/useGetHostList';
import * as appContextHooks from 'providers/App/App';
import * as timezoneHooks from 'providers/Timezone';
import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import store from 'store';
import { LicenseEvent } from 'types/api/licensesV3/getActive';
import HostsList from '../HostsList';
jest.mock('lib/getMinMax', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => ({
minTime: 1713734400000,
maxTime: 1713738000000,
isValidTimeFormat: jest.fn().mockReturnValue(true),
})),
}));
jest.mock('components/CustomTimePicker/CustomTimePicker', () => ({
__esModule: true,
default: ({ onSelect, selectedTime, selectedValue }: any): JSX.Element => (
<div data-testid="custom-time-picker">
<button onClick={(): void => onSelect('custom')}>
{selectedTime} - {selectedValue}
</button>
</div>
),
}));
const queryClient = new QueryClient();
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
bars: jest.fn(),
};
const uplotMock = jest.fn(() => ({
paths,
}));
return {
paths,
default: uplotMock,
};
});
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: (): any => ({
globalTime: {
selectedTime: {
startTime: 1713734400000,
endTime: 1713738000000,
},
maxTime: 1713738000000,
minTime: 1713734400000,
},
}),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn().mockReturnValue({
pathname: ROUTES.INFRASTRUCTURE_MONITORING_HOSTS,
}),
}));
jest.mock('react-router-dom-v5-compat', () => {
const actual = jest.requireActual('react-router-dom-v5-compat');
return {
...actual,
useSearchParams: jest
.fn()
.mockReturnValue([
{ get: jest.fn(), entries: jest.fn().mockReturnValue([]) },
jest.fn(),
]),
useNavigationType: (): any => 'PUSH',
};
});
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): any => ({
safeNavigate: jest.fn(),
}),
}));
jest.spyOn(timezoneHooks, 'useTimezone').mockReturnValue({
timezone: {
offset: 0,
},
browserTimezone: {
offset: 0,
},
} as any);
jest.spyOn(useGetHostListHooks, 'useGetHostList').mockReturnValue({
data: {
payload: {
data: {
records: [
{
hostName: 'test-host',
active: true,
cpu: 0.75,
memory: 0.65,
wait: 0.03,
},
],
isSendingK8SAgentMetrics: false,
sentAnyHostMetricsData: true,
},
},
},
isLoading: false,
isError: false,
} as any);
jest.spyOn(appContextHooks, 'useAppContext').mockReturnValue({
user: {
role: 'admin',
},
activeLicenseV3: {
event_queue: {
created_at: '0',
event: LicenseEvent.NO_EVENT,
scheduled_at: '0',
status: '',
updated_at: '0',
},
license: {
license_key: 'test-license-key',
license_type: 'trial',
org_id: 'test-org-id',
plan_id: 'test-plan-id',
plan_name: 'test-plan-name',
plan_type: 'trial',
plan_version: 'test-plan-version',
},
},
} as any);
describe('HostsList', () => {
it('renders hosts list table', () => {
const { container } = render(
<QueryClientProvider client={queryClient}>
<MemoryRouter>
<Provider store={store}>
<HostsList />
</Provider>
</MemoryRouter>
</QueryClientProvider>,
);
expect(container.querySelector('.hosts-list-table')).toBeInTheDocument();
});
it('renders filters', () => {
const { container } = render(
<QueryClientProvider client={queryClient}>
<MemoryRouter>
<Provider store={store}>
<HostsList />
</Provider>
</MemoryRouter>
</QueryClientProvider>,
);
expect(container.querySelector('.filters')).toBeInTheDocument();
});
});

View File

@ -0,0 +1,37 @@
import { render, screen } from '@testing-library/react';
import HostsListControls from '../HostsListControls';
jest.mock('container/QueryBuilder/filters/QueryBuilderSearch', () => ({
__esModule: true,
default: (): JSX.Element => (
<div data-testid="query-builder-search">Search</div>
),
}));
jest.mock('container/TopNav/DateTimeSelectionV2', () => ({
__esModule: true,
default: (): JSX.Element => (
<div data-testid="date-time-selection">Date Time</div>
),
}));
describe('HostsListControls', () => {
const mockHandleFiltersChange = jest.fn();
const mockFilters = {
items: [],
op: 'AND',
};
it('renders search and date time filters', () => {
render(
<HostsListControls
handleFiltersChange={mockHandleFiltersChange}
filters={mockFilters}
/>,
);
expect(screen.getByTestId('query-builder-search')).toBeInTheDocument();
expect(screen.getByTestId('date-time-selection')).toBeInTheDocument();
});
});

View File

@ -0,0 +1,139 @@
/* eslint-disable react/jsx-props-no-spreading */
import { render, screen } from '@testing-library/react';
import HostsListTable from '../HostsListTable';
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
bars: jest.fn(),
};
const uplotMock = jest.fn(() => ({
paths,
}));
return {
paths,
default: uplotMock,
};
});
const EMPTY_STATE_CONTAINER_CLASS = '.hosts-empty-state-container';
describe('HostsListTable', () => {
const mockHost = {
hostName: 'test-host-1',
active: true,
cpu: 0.75,
memory: 0.65,
wait: 0.03,
load15: 1.5,
os: 'linux',
};
const mockTableData = {
payload: {
data: {
hosts: [mockHost],
},
},
};
const mockOnHostClick = jest.fn();
const mockSetCurrentPage = jest.fn();
const mockSetOrderBy = jest.fn();
const mockSetPageSize = jest.fn();
const mockProps = {
isLoading: false,
isError: false,
isFetching: false,
tableData: mockTableData,
hostMetricsData: [mockHost],
filters: {
items: [],
op: 'AND',
},
onHostClick: mockOnHostClick,
currentPage: 1,
setCurrentPage: mockSetCurrentPage,
pageSize: 10,
setOrderBy: mockSetOrderBy,
setPageSize: mockSetPageSize,
} as any;
it('renders loading state if isLoading is true', () => {
const { container } = render(<HostsListTable {...mockProps} isLoading />);
expect(container.querySelector('.hosts-list-loading-state')).toBeTruthy();
});
it('renders loading state if isFetching is true', () => {
const { container } = render(<HostsListTable {...mockProps} isFetching />);
expect(container.querySelector('.hosts-list-loading-state')).toBeTruthy();
});
it('renders error state if isError is true', () => {
render(<HostsListTable {...mockProps} isError />);
expect(screen.getByText('Something went wrong')).toBeTruthy();
});
it('renders empty state if no hosts are found', () => {
const { container } = render(<HostsListTable {...mockProps} />);
expect(container.querySelector(EMPTY_STATE_CONTAINER_CLASS)).toBeTruthy();
});
it('renders empty state if sentAnyHostMetricsData is false', () => {
const { container } = render(
<HostsListTable
{...mockProps}
tableData={{
...mockTableData,
payload: {
...mockTableData.payload,
data: {
...mockTableData.payload.data,
sentAnyHostMetricsData: false,
},
},
}}
/>,
);
expect(container.querySelector(EMPTY_STATE_CONTAINER_CLASS)).toBeTruthy();
});
it('renders empty state if isSendingIncorrectK8SAgentMetrics is true', () => {
const { container } = render(
<HostsListTable
{...mockProps}
tableData={{
...mockTableData,
payload: {
...mockTableData.payload,
data: {
...mockTableData.payload.data,
isSendingIncorrectK8SAgentMetrics: true,
},
},
}}
/>,
);
expect(container.querySelector(EMPTY_STATE_CONTAINER_CLASS)).toBeTruthy();
});
it('renders table data', () => {
const { container } = render(
<HostsListTable
{...mockProps}
tableData={{
...mockTableData,
payload: {
...mockTableData.payload,
data: {
...mockTableData.payload.data,
isSendingIncorrectK8SAgentMetrics: false,
sentAnyHostMetricsData: true,
},
},
}}
/>,
);
expect(container.querySelector('.hosts-list-table')).toBeTruthy();
});
});

View File

@ -0,0 +1,104 @@
import { render } from '@testing-library/react';
import { formatDataForTable, GetHostsQuickFiltersConfig } from '../utils';
const PROGRESS_BAR_CLASS = '.progress-bar';
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
bars: jest.fn(),
};
const uplotMock = jest.fn(() => ({
paths,
}));
return {
paths,
default: uplotMock,
};
});
describe('InfraMonitoringHosts utils', () => {
describe('formatDataForTable', () => {
it('should format host data correctly', () => {
const mockData = [
{
hostName: 'test-host',
active: true,
cpu: 0.95,
memory: 0.85,
wait: 0.05,
load15: 2.5,
os: 'linux',
},
] as any;
const result = formatDataForTable(mockData);
expect(result[0].hostName).toBe('test-host');
expect(result[0].wait).toBe('5%');
expect(result[0].load15).toBe(2.5);
// Test active tag rendering
const activeTag = render(result[0].active as JSX.Element);
expect(activeTag.container.textContent).toBe('ACTIVE');
expect(activeTag.container.querySelector('.active')).toBeTruthy();
// Test CPU progress bar
const cpuProgress = render(result[0].cpu as JSX.Element);
const cpuProgressBar = cpuProgress.container.querySelector(
PROGRESS_BAR_CLASS,
);
expect(cpuProgressBar).toBeTruthy();
// Test memory progress bar
const memoryProgress = render(result[0].memory as JSX.Element);
const memoryProgressBar = memoryProgress.container.querySelector(
PROGRESS_BAR_CLASS,
);
expect(memoryProgressBar).toBeTruthy();
});
it('should handle inactive hosts', () => {
const mockData = [
{
hostName: 'test-host',
active: false,
cpu: 0.3,
memory: 0.4,
wait: 0.02,
load15: 1.2,
os: 'linux',
cpuTimeSeries: [],
memoryTimeSeries: [],
waitTimeSeries: [],
load15TimeSeries: [],
},
] as any;
const result = formatDataForTable(mockData);
const inactiveTag = render(result[0].active as JSX.Element);
expect(inactiveTag.container.textContent).toBe('INACTIVE');
expect(inactiveTag.container.querySelector('.inactive')).toBeTruthy();
});
});
describe('GetHostsQuickFiltersConfig', () => {
it('should return correct config when dotMetricsEnabled is true', () => {
const result = GetHostsQuickFiltersConfig(true);
expect(result[0].attributeKey.key).toBe('host.name');
expect(result[1].attributeKey.key).toBe('os.type');
expect(result[0].aggregateAttribute).toBe('system.cpu.load_average.15m');
});
it('should return correct config when dotMetricsEnabled is false', () => {
const result = GetHostsQuickFiltersConfig(false);
expect(result[0].attributeKey.key).toBe('host_name');
expect(result[1].attributeKey.key).toBe('os_type');
expect(result[0].aggregateAttribute).toBe('system_cpu_load_average_15m');
});
});
});