chore: added test cases for Logs (#4828)

* chore: add test cases for Logs

* chore: add test cases for Logs - explorer

* chore: add test cases for Logs - toolbarAction

* chore: add test cases for Logs - list and table view

* chore: add test cases for Logs - list and table view

* chore: code fix
This commit is contained in:
SagarRajput-7 2024-04-15 11:30:25 +05:30 committed by GitHub
parent 3a5a61aff9
commit 0d5934d56b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 402 additions and 9 deletions

View File

@ -608,6 +608,7 @@ function LogsExplorerViews({
className="periscope-btn"
onClick={handleToggleShowFormatOptions}
icon={<Sliders size={14} />}
data-testid="periscope-btn"
/>
{showFormatMenuItems && (

View File

@ -0,0 +1,151 @@
import { render, RenderResult } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQueryRange';
import { logsQueryRangeSuccessResponse } from 'mocks-server/__mockdata__/logs_query_range';
import { server } from 'mocks-server/server';
import { rest } from 'msw';
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { VirtuosoMockContext } from 'react-virtuoso';
import i18n from 'ReactI18';
import store from 'store';
import LogsExplorerViews from '..';
import { logsQueryRangeSuccessNewFormatResponse } from './mock';
const logExplorerRoute = '/logs/logs-explorer';
const queryRangeURL = 'http://localhost/api/v3/query_range';
const lodsQueryServerRequest = (): void =>
server.use(
rest.post(queryRangeURL, (req, res, ctx) =>
res(ctx.status(200), ctx.json(logsQueryRangeSuccessResponse)),
),
);
// mocking the graph components in this test as this should be handled separately
jest.mock(
'container/TimeSeriesView/TimeSeriesView',
() =>
// eslint-disable-next-line func-names, @typescript-eslint/explicit-function-return-type, react/display-name
function () {
return <div>Time Series Chart</div>;
},
);
jest.mock(
'container/LogsExplorerChart',
() =>
// eslint-disable-next-line func-names, @typescript-eslint/explicit-function-return-type, react/display-name
function () {
return <div>Histogram Chart</div>;
},
);
jest.mock('constants/panelTypes', () => ({
AVAILABLE_EXPORT_PANEL_TYPES: ['graph', 'table'],
}));
jest.mock('d3-interpolate', () => ({
interpolate: jest.fn(),
}));
jest.mock('hooks/queryBuilder/useGetExplorerQueryRange', () => ({
__esModule: true,
useGetExplorerQueryRange: jest.fn(),
}));
// Set up the specific behavior for useGetExplorerQueryRange in individual test cases
beforeEach(() => {
(useGetExplorerQueryRange as jest.Mock).mockReturnValue({
data: { payload: logsQueryRangeSuccessNewFormatResponse },
});
});
const renderer = (): RenderResult =>
render(
<MemoryRouter initialEntries={[logExplorerRoute]}>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<MockQueryClientProvider>
<QueryBuilderProvider>
<VirtuosoMockContext.Provider
value={{ viewportHeight: 300, itemHeight: 100 }}
>
<LogsExplorerViews selectedView={SELECTED_VIEWS.SEARCH} showHistogram />
</VirtuosoMockContext.Provider>
</QueryBuilderProvider>
</MockQueryClientProvider>
</I18nextProvider>
</Provider>
</MemoryRouter>,
);
describe('LogsExplorerViews -', () => {
it('render correctly with props - list and table', async () => {
lodsQueryServerRequest();
const { queryByText, queryByTestId } = renderer();
expect(queryByTestId('periscope-btn')).toBeInTheDocument();
await userEvent.click(queryByTestId('periscope-btn') as HTMLElement);
expect(document.querySelector('.menu-container')).toBeInTheDocument();
const menuItems = document.querySelectorAll('.menu-items .item');
expect(menuItems.length).toBe(3);
// switch to table view
// eslint-disable-next-line sonarjs/no-duplicate-string
await userEvent.click(queryByTestId('table-view') as HTMLElement);
expect(
queryByText(
'{"container_id":"container_id","container_name":"container_name","driver":"driver","eta":"2m0s","location":"frontend","log_level":"INFO","message":"Dispatch successful","service":"frontend","span_id":"span_id","trace_id":"span_id"}',
),
).toBeInTheDocument();
});
it('check isLoading state', async () => {
lodsQueryServerRequest();
(useGetExplorerQueryRange as jest.Mock).mockReturnValue({
data: { payload: logsQueryRangeSuccessNewFormatResponse },
isLoading: true,
isFetching: false,
});
const { queryByText, queryByTestId } = renderer();
// switch to table view
await userEvent.click(queryByTestId('table-view') as HTMLElement);
expect(
queryByText(
'Just a bit of patience, just a little bits enough ⎯ were getting your logs!',
),
).toBeInTheDocument();
});
it('check error state', async () => {
lodsQueryServerRequest();
(useGetExplorerQueryRange as jest.Mock).mockReturnValue({
data: { payload: logsQueryRangeSuccessNewFormatResponse },
isLoading: false,
isFetching: false,
isError: true,
});
const { queryByText, queryByTestId } = renderer();
expect(
queryByText('Something went wrong. Please try again or contact support.'),
).toBeInTheDocument();
// switch to table view
await userEvent.click(queryByTestId('table-view') as HTMLElement);
expect(
queryByText('Something went wrong. Please try again or contact support.'),
).toBeInTheDocument();
});
});

View File

@ -0,0 +1,51 @@
export const logsQueryRangeSuccessNewFormatResponse = {
data: {
result: [],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: null,
list: [
{
timestamp: '2024-02-15T21:20:22Z',
data: {
attributes_bool: {},
attributes_float64: {},
attributes_int64: {},
attributes_string: {
container_id: 'container_id',
container_name: 'container_name',
driver: 'driver',
eta: '2m0s',
location: 'frontend',
log_level: 'INFO',
message: 'Dispatch successful',
service: 'frontend',
span_id: 'span_id',
trace_id: 'span_id',
},
body:
'2024-02-15T21:20:22.035Z\tINFO\tfrontend\tDispatch successful\t{"service": "frontend", "trace_id": "span_id", "span_id": "span_id", "driver": "driver", "eta": "2m0s"}',
id: 'id',
resources_string: {
'container.name': 'container_name',
},
severity_number: 0,
severity_text: '',
span_id: '',
trace_flags: 0,
trace_id: '',
},
},
],
},
],
},
},
},
};

View File

@ -0,0 +1,105 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
import LeftToolbarActions from '../LeftToolbarActions';
import RightToolbarActions from '../RightToolbarActions';
describe('ToolbarActions', () => {
it('LeftToolbarActions - renders correctly with default props', async () => {
const handleChangeSelectedView = jest.fn();
const handleToggleShowHistogram = jest.fn();
const { queryByTestId } = render(
<LeftToolbarActions
items={{
search: {
name: 'search',
label: 'Search',
disabled: false,
show: true,
},
queryBuilder: {
name: 'query-builder',
label: 'Query Builder',
disabled: false,
show: true,
},
clickhouse: {
name: 'clickhouse',
label: 'Clickhouse',
disabled: false,
},
}}
selectedView={SELECTED_VIEWS.SEARCH}
onChangeSelectedView={handleChangeSelectedView}
onToggleHistrogramVisibility={handleToggleShowHistogram}
showHistogram
/>,
);
expect(screen.getByTestId('search-view')).toBeInTheDocument();
expect(screen.getByTestId('query-builder-view')).toBeInTheDocument();
// clickhouse should not be present as its show: false
expect(queryByTestId('clickhouse-view')).not.toBeInTheDocument();
await userEvent.click(screen.getByTestId('search-view'));
expect(handleChangeSelectedView).toBeCalled();
await userEvent.click(screen.getByTestId('query-builder-view'));
expect(handleChangeSelectedView).toBeCalled();
});
it('renders - clickhouse view and test histogram toggle', async () => {
const handleChangeSelectedView = jest.fn();
const handleToggleShowHistogram = jest.fn();
const { queryByTestId, getByRole } = render(
<LeftToolbarActions
items={{
search: {
name: 'search',
label: 'Search',
disabled: false,
show: false,
},
queryBuilder: {
name: 'query-builder',
label: 'Query Builder',
disabled: false,
show: true,
},
clickhouse: {
name: 'clickhouse',
label: 'Clickhouse',
disabled: false,
show: true,
},
}}
selectedView={SELECTED_VIEWS.QUERY_BUILDER}
onChangeSelectedView={handleChangeSelectedView}
onToggleHistrogramVisibility={handleToggleShowHistogram}
showHistogram
/>,
);
const clickHouseView = queryByTestId('clickhouse-view');
expect(clickHouseView).toBeInTheDocument();
await userEvent.click(clickHouseView as HTMLElement);
expect(handleChangeSelectedView).toBeCalled();
await userEvent.click(getByRole('switch'));
expect(handleToggleShowHistogram).toBeCalled();
});
it('RightToolbarActions - render correctly with props', async () => {
const onStageRunQuery = jest.fn();
const { queryByText } = render(
<RightToolbarActions onStageRunQuery={onStageRunQuery} />,
);
const stageNRunBtn = queryByText('Stage & Run Query');
expect(stageNRunBtn).toBeInTheDocument();
await userEvent.click(stageNRunBtn as HTMLElement);
expect(onStageRunQuery).toBeCalled();
});
});

View File

@ -1,9 +1,18 @@
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {
initialQueriesMap,
initialQueryBuilderFormValues,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { noop } from 'lodash-es';
import { logsQueryRangeSuccessResponse } from 'mocks-server/__mockdata__/logs_query_range';
import { server } from 'mocks-server/server';
import { rest } from 'msw';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import {
QueryBuilderContext,
QueryBuilderProvider,
} from 'providers/QueryBuilder';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
@ -12,8 +21,9 @@ import { MemoryRouter } from 'react-router-dom';
import { VirtuosoMockContext } from 'react-virtuoso';
import i18n from 'ReactI18';
import store from 'store';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import LogsExplorer from '..';
import LogsExplorer from '../index';
const queryRangeURL = 'http://localhost/api/v3/query_range';
// mocking the graph components in this test as this should be handled separately
@ -42,6 +52,15 @@ jest.mock('d3-interpolate', () => ({
interpolate: jest.fn(),
}));
const logExplorerRoute = '/logs/logs-explorer';
const lodsQueryServerRequest = (): void =>
server.use(
rest.post(queryRangeURL, (req, res, ctx) =>
res(ctx.status(200), ctx.json(logsQueryRangeSuccessResponse)),
),
);
describe('Logs Explorer Tests', () => {
test('Logs Explorer default view test without data', async () => {
const {
@ -51,7 +70,7 @@ describe('Logs Explorer Tests', () => {
getByTestId,
queryByTestId,
} = render(
<MemoryRouter initialEntries={['/logs/logs-explorer']}>
<MemoryRouter initialEntries={[logExplorerRoute]}>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<MockQueryClientProvider>
@ -95,13 +114,9 @@ describe('Logs Explorer Tests', () => {
test('Logs Explorer Page should render with data', async () => {
// mocking the query range API to return the logs
server.use(
rest.post(queryRangeURL, (req, res, ctx) =>
res(ctx.status(200), ctx.json(logsQueryRangeSuccessResponse)),
),
);
lodsQueryServerRequest();
const { queryByText, queryByTestId } = render(
<MemoryRouter initialEntries={['/logs/logs-explorer']}>
<MemoryRouter initialEntries={[logExplorerRoute]}>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<MockQueryClientProvider>
@ -144,4 +159,74 @@ describe('Logs Explorer Tests', () => {
),
).toBeInTheDocument();
});
test('Multiple Current Queries', async () => {
// mocking the query range API to return the logs
lodsQueryServerRequest();
const { queryAllByText } = render(
<MemoryRouter initialEntries={[logExplorerRoute]}>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<MockQueryClientProvider>
<QueryBuilderContext.Provider
value={{
currentQuery: {
...initialQueriesMap.metrics,
builder: {
...initialQueriesMap.metrics.builder,
queryData: [
initialQueryBuilderFormValues,
initialQueryBuilderFormValues,
],
},
},
setSupersetQuery: jest.fn(),
supersetQuery: initialQueriesMap.metrics,
stagedQuery: initialQueriesMap.metrics,
initialDataSource: null,
panelType: PANEL_TYPES.TIME_SERIES,
isEnabledQuery: false,
handleSetQueryData: noop,
handleSetFormulaData: noop,
handleSetQueryItemData: noop,
handleSetConfig: noop,
removeQueryBuilderEntityByIndex: noop,
removeQueryTypeItemByIndex: noop,
addNewBuilderQuery: noop,
cloneQuery: noop,
addNewFormula: noop,
addNewQueryItem: noop,
redirectWithQueryBuilderData: noop,
handleRunQuery: noop,
resetQuery: noop,
updateAllQueriesOperators: (): Query => initialQueriesMap.metrics,
updateQueriesData: (): Query => initialQueriesMap.metrics,
initQueryBuilderData: noop,
handleOnUnitsChange: noop,
isStagedQueryUpdated: (): boolean => false,
}}
>
<VirtuosoMockContext.Provider
value={{ viewportHeight: 300, itemHeight: 100 }}
>
<LogsExplorer />
</VirtuosoMockContext.Provider>
</QueryBuilderContext.Provider>
</MockQueryClientProvider>
</I18nextProvider>
</Provider>
</MemoryRouter>,
);
const queries = queryAllByText(
'Search Filter : select options from suggested values, for IN/NOT IN operators - press "Enter" after selecting options',
);
expect(queries.length).toBe(2);
const legendFormats = queryAllByText('Legend Format');
expect(legendFormats.length).toBe(2);
const aggrInterval = queryAllByText('AGGREGATION INTERVAL');
expect(aggrInterval.length).toBe(2);
});
});