Compare commits

...

5 Commits

Author SHA1 Message Date
ahmadshaheer
733d6ce78c chore: overall improvements to general tests 2024-07-18 10:59:58 +04:30
ahmadshaheer
d7d78d6ab4 chore: overall improvements to general tests 2024-07-18 10:50:18 +04:30
ahmadshaheer
fb73f23dce feat: write tests for cloud user general settings 2024-07-17 19:32:17 +04:30
ahmadshaheer
cb790ea3e5 chore: overall improvements to general settings tests 2024-07-17 19:31:09 +04:30
ahmadshaheer
e48784c09c feat: general settings tests 2024-07-17 15:21:39 +04:30
9 changed files with 341 additions and 14 deletions

View File

@@ -524,7 +524,13 @@ function GeneralSettings({
) {
return (
<Fragment key={category.name}>
<Col xs={22} xl={11} key={category.name} style={{ margin: '0.5rem' }}>
<Col
xs={22}
xl={11}
key={category.name}
style={{ margin: '0.5rem' }}
data-testid={`${category.name.toLowerCase()}-card`}
>
<Card style={{ height: '100%' }}>
<Typography.Title style={{ margin: 0 }} level={3}>
{category.name}
@@ -554,6 +560,7 @@ function GeneralSettings({
type="primary"
onClick={category.save.modalOpen}
disabled={category.save.isDisabled}
data-testid="retention-submit-button"
>
{category.save.saveButtonText}
</Button>
@@ -574,6 +581,7 @@ function GeneralSettings({
centered
open={category.save.modal}
confirmLoading={category.save.apiLoading}
data-testid={`${category.name.toLowerCase()}-modal`}
>
<Typography>
{t('retention_confirmation_description', {
@@ -597,14 +605,16 @@ function GeneralSettings({
<Col xs={24} md={22} xl={20} xxl={18} style={{ margin: 'auto' }}>
<ErrorTextContainer>
{!isCloudUserVal && (
<TextToolTip
{...{
text: `More details on how to set retention period`,
url: 'https://signoz.io/docs/userguide/retention-period/',
}}
/>
<div data-testid="help-icon">
<TextToolTip
{...{
text: `More details on how to set retention period`,
url: 'https://signoz.io/docs/userguide/retention-period/',
}}
/>
</div>
)}
{errorText && <ErrorText>{errorText}</ErrorText>}
{errorText && <ErrorText data-testid="error-text">{errorText}</ErrorText>}
</ErrorTextContainer>
<Row justify="start">{renderConfig}</Row>
@@ -615,7 +625,7 @@ function GeneralSettings({
);
}
interface GeneralSettingsProps {
export interface GeneralSettingsProps {
getAvailableDiskPayload: GetDisksPayload;
metricsTtlValuesPayload: GetRetentionPeriodMetricsPayload;
tracesTtlValuesPayload: GetRetentionPeriodTracesPayload;

View File

@@ -95,9 +95,11 @@ function Retention({
return (
<RetentionContainer>
<Row justify="space-between">
<Row justify="space-between" aria-label={text}>
<Col span={12} style={{ display: 'flex' }}>
<RetentionFieldLabel>{text}</RetentionFieldLabel>
<RetentionFieldLabel data-testid="retention-field-label">
{text}
</RetentionFieldLabel>
</Col>
<Row justify="end">
<RetentionFieldInputContainer>
@@ -106,12 +108,14 @@ function Retention({
disabled={isCloudUserVal}
onChange={(e): void => onChangeHandler(e, setSelectedValue)}
style={{ width: 75 }}
data-testid="retention-field-input"
/>
<Select
value={selectedTimeUnit}
onChange={currentSelectedOption}
disabled={isCloudUserVal}
style={{ width: 100 }}
data-testid="retention-field-dropdown"
>
{menuItems}
</Select>

View File

@@ -60,6 +60,7 @@ function StatusMessage({
style={{
color: messageColor,
}}
data-testid="status-message"
>
{statusMessage}
</Col>

View File

@@ -2,6 +2,7 @@ import { Typography } from 'antd';
import getDisks from 'api/disks/getDisks';
import getRetentionPeriodApi from 'api/settings/getRetention';
import Spinner from 'components/Spinner';
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
import { useTranslation } from 'react-i18next';
import { useQueries } from 'react-query';
import { useSelector } from 'react-redux';
@@ -11,8 +12,6 @@ import { TTTLType } from 'types/api/settings/common';
import { PayloadProps as GetRetentionPeriodAPIPayloadProps } from 'types/api/settings/getRetention';
import AppReducer from 'types/reducer/app';
import GeneralSettingsContainer from './GeneralSettings';
type TRetentionAPIReturn<T extends TTTLType> = Promise<
SuccessResponse<GetRetentionPeriodAPIPayloadProps<T>> | ErrorResponse
>;

View File

@@ -7,7 +7,7 @@ export default function GeneralSettingsCloud(): JSX.Element {
return (
<Card className="general-settings-container">
<Info size={16} />
<Typography.Text>
<Typography.Text data-testid="cloud-user-info-card">
Please <a href="mailto:cloud-support@signoz.io"> email us </a> or connect
with us via intercom support to change the retention period.
</Typography.Text>

View File

@@ -97,4 +97,12 @@ export const handlers = [
rest.post('http://localhost/api/v1/invite', (_, res, ctx) =>
res(ctx.status(200), ctx.json(inviteUser)),
),
rest.post('http://localhost/api/v1/settings/ttl', (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({
message: 'move ttl has been successfully set up',
}),
),
),
];

View File

@@ -0,0 +1,180 @@
/* eslint-disable sonarjs/no-duplicate-string */
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
import {
act,
fireEvent,
render,
screen,
waitFor,
within,
} from 'tests/test-utils';
import { generalSettingsProps } from './mock';
const tooltipText = /More details on how to set retention period/;
const types = [
{
testId: 'metrics-card',
header: 'Metrics',
modalTestId: 'metrics-modal',
},
{
testId: 'traces-card',
header: 'Traces',
modalTestId: 'traces-modal',
},
{
testId: 'logs-card',
header: 'Logs',
modalTestId: 'logs-modal',
},
];
describe('General Settings Page', () => {
beforeEach(() => {
render(
<GeneralSettingsContainer
metricsTtlValuesPayload={generalSettingsProps.metricsTtlValuesPayload}
tracesTtlValuesPayload={generalSettingsProps.tracesTtlValuesPayload}
logsTtlValuesPayload={generalSettingsProps.logsTtlValuesPayload}
getAvailableDiskPayload={generalSettingsProps.getAvailableDiskPayload}
metricsTtlValuesRefetch={generalSettingsProps.metricsTtlValuesRefetch}
tracesTtlValuesRefetch={generalSettingsProps.tracesTtlValuesRefetch}
logsTtlValuesRefetch={generalSettingsProps.logsTtlValuesRefetch}
/>,
);
});
it('should properly display the help icon', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);
await waitFor(() => {
const tooltip = screen.getByText(tooltipText);
expect(tooltip).toBeInTheDocument();
});
});
types.forEach(({ testId, header, modalTestId }) => {
describe(`${header} Card`, () => {
it(`should be able to find "${header}" as the header `, () => {
expect(
screen.getByRole('heading', {
name: header,
}),
).toBeInTheDocument();
});
it(`should check if ${header} body is properly displayed`, () => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldLabel = within(sectionCard).getByTestId(
'retention-field-label',
);
expect(retentionFieldLabel).toBeInTheDocument();
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
expect(retentionFieldInput).toBeInTheDocument();
const retentionFieldDropdown = within(sectionCard).getByTestId(
'retention-field-dropdown',
);
expect(retentionFieldDropdown).toBeInTheDocument();
const retentionSubmitButton = within(sectionCard).getByTestId(
'retention-submit-button',
);
expect(retentionSubmitButton).toBeInTheDocument();
});
it('Should check if save button is disabled by default', () => {
const sectionCard = screen.getByTestId(testId);
const retentionSubmitButton = within(sectionCard).getByTestId(
'retention-submit-button',
);
expect(retentionSubmitButton).toBeDisabled();
});
it('Should check if changing the value of the textbox enables the save button ', () => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
const retentionSubmitButton = within(sectionCard).getByTestId(
'retention-submit-button',
);
expect(retentionSubmitButton).toBeDisabled();
act(() => {
fireEvent.change(retentionFieldInput, { target: { value: '2' } });
});
expect(retentionSubmitButton).toBeEnabled();
});
it('Should check if "retention_null_value_error" is displayed if the value is not set ', async () => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
act(() => {
fireEvent.change(retentionFieldInput, { target: { value: 0 } });
});
expect(
await screen.findByText('retention_null_value_error'),
).toBeInTheDocument();
});
it('should display the modal when a value is provided and save is clicked', async () => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
const retentionSubmitButton = within(sectionCard).getByTestId(
'retention-submit-button',
);
act(() => {
fireEvent.change(retentionFieldInput, { target: { value: 1 } });
fireEvent.click(retentionSubmitButton);
});
const sectionModal = screen.getByTestId(modalTestId);
expect(
await within(sectionModal).findByText('retention_confirmation'),
).toBeInTheDocument();
});
describe(`${header} Modal`, () => {
let sectionModal: HTMLElement;
beforeEach(() => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
const retentionSubmitButton = within(sectionCard).getByTestId(
'retention-submit-button',
);
act(() => {
fireEvent.change(retentionFieldInput, { target: { value: 1 } });
fireEvent.click(retentionSubmitButton);
});
sectionModal = screen.getByTestId(modalTestId);
});
it('Should check if the modal is properly displayed', async () => {
expect(
within(sectionModal).getByText('retention_confirmation'),
).toBeInTheDocument();
expect(
within(sectionModal).getByText('retention_confirmation_description'),
).toBeInTheDocument();
});
});
});
});
});

View File

@@ -0,0 +1,62 @@
import GeneralSettingsContainer from 'container/GeneralSettings/GeneralSettings';
import { render, screen, within } from 'tests/test-utils';
import { generalSettingsProps } from './mock';
jest.mock('utils/app', () => {
const app = jest.requireActual('utils/app');
return {
...app,
isCloudUser: jest.fn(() => true),
};
});
const types = [
{
testId: 'metrics-card',
header: 'Metrics',
},
{
testId: 'traces-card',
header: 'Traces',
},
{
testId: 'logs-card',
header: 'Logs',
},
];
describe('Cloud User General Settings', () => {
beforeEach(() => {
render(
<GeneralSettingsContainer
metricsTtlValuesPayload={generalSettingsProps.metricsTtlValuesPayload}
tracesTtlValuesPayload={generalSettingsProps.tracesTtlValuesPayload}
logsTtlValuesPayload={generalSettingsProps.logsTtlValuesPayload}
getAvailableDiskPayload={generalSettingsProps.getAvailableDiskPayload}
metricsTtlValuesRefetch={generalSettingsProps.metricsTtlValuesRefetch}
tracesTtlValuesRefetch={generalSettingsProps.tracesTtlValuesRefetch}
logsTtlValuesRefetch={generalSettingsProps.logsTtlValuesRefetch}
/>,
);
});
it('should display the cloud user info card', () => {
const cloudUserCard = screen.getByTestId('cloud-user-info-card');
expect(cloudUserCard).toBeInTheDocument();
});
types.forEach(({ testId, header }) => {
it(`should check if value textbox and duration dropdown are disabled in the body of ${header}`, () => {
const sectionCard = screen.getByTestId(testId);
const retentionFieldInput = within(sectionCard).getByTestId(
'retention-field-input',
);
expect(retentionFieldInput).toBeDisabled();
const retentionFieldDropdown = within(sectionCard).getByTestId(
'retention-field-dropdown',
);
expect(retentionFieldDropdown).toHaveClass('ant-select-disabled');
});
});
});

View File

@@ -0,0 +1,63 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { QueryObserverResult } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api';
import {
PayloadPropsLogs,
PayloadPropsMetrics,
PayloadPropsTraces,
TStatus,
} from 'types/api/settings/getRetention';
export const generalSettingsProps = {
metricsTtlValuesPayload: {
metrics_ttl_duration_hrs: 720,
metrics_move_ttl_duration_hrs: -1,
expected_metrics_ttl_duration_hrs: 720,
expected_metrics_move_ttl_duration_hrs: -1,
status: 'success' as TStatus,
},
tracesTtlValuesPayload: {
traces_ttl_duration_hrs: 360,
traces_move_ttl_duration_hrs: -1,
expected_traces_ttl_duration_hrs: 24,
expected_traces_move_ttl_duration_hrs: -1,
status: '' as TStatus,
},
logsTtlValuesPayload: {
logs_ttl_duration_hrs: 360,
logs_move_ttl_duration_hrs: -1,
expected_logs_ttl_duration_hrs: 360,
expected_logs_move_ttl_duration_hrs: -1,
status: 'success' as TStatus,
},
getAvailableDiskPayload: [
{
name: 'default',
type: 'local',
},
],
metricsTtlValuesRefetch(): Promise<
QueryObserverResult<
ErrorResponse | SuccessResponse<PayloadPropsMetrics, unknown>,
unknown
>
> {
throw new Error('Function not implemented.');
},
tracesTtlValuesRefetch(): Promise<
QueryObserverResult<
ErrorResponse | SuccessResponse<PayloadPropsTraces, unknown>,
unknown
>
> {
throw new Error('Function not implemented.');
},
logsTtlValuesRefetch(): Promise<
QueryObserverResult<
ErrorResponse | SuccessResponse<PayloadPropsLogs, unknown>,
unknown
>
> {
throw new Error('Function not implemented.');
},
};