signoz/frontend/src/container/RoutingPolicies/__tests__/RoutingPolicyDetails.test.tsx

424 lines
13 KiB
TypeScript
Raw Normal View History

import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import * as appHooks from 'providers/App/App';
import RoutingPolicyDetails from '../RoutingPolicyDetails';
import {
getAppContextMockState,
MOCK_CHANNEL_1,
MOCK_CHANNEL_2,
MOCK_ROUTING_POLICY_1,
} from './testUtils';
jest.spyOn(appHooks, 'useAppContext').mockReturnValue(getAppContextMockState());
const mockHandlePolicyDetailsModalAction = jest.fn();
const mockCloseModal = jest.fn();
const mockChannels = [MOCK_CHANNEL_1, MOCK_CHANNEL_2];
const mockRoutingPolicy = MOCK_ROUTING_POLICY_1;
const mockRefreshChannels = jest.fn();
const NEW_NAME = 'New Name';
const NEW_EXPRESSION = 'New Expression';
const NEW_DESCRIPTION = 'New Description';
const SAVE_BUTTON_TEXT = 'Save Routing Policy';
const NO_CHANNELS_FOUND_TEXT = 'No channels yet.';
describe('RoutingPolicyDetails', () => {
it('renders base create layout with header, 3 inputs and footer', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Create routing policy')).toBeInTheDocument();
expect(screen.getByText('Routing Policy Name')).toBeInTheDocument();
expect(screen.getByText('Expression')).toBeInTheDocument();
expect(screen.getByText('Notification Channels')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
expect(
screen.getByRole('button', { name: SAVE_BUTTON_TEXT }),
).toBeInTheDocument();
});
it('renders base edit layout with header, 3 inputs and footer', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="edit"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Edit routing policy')).toBeInTheDocument();
expect(screen.getByText('Routing Policy Name')).toBeInTheDocument();
expect(screen.getByText('Expression')).toBeInTheDocument();
expect(screen.getByText('Notification Channels')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
expect(
screen.getByRole('button', { name: SAVE_BUTTON_TEXT }),
).toBeInTheDocument();
});
it('prefills inputs with existing policy values in edit mode', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="edit"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const nameInput = screen.getByDisplayValue(mockRoutingPolicy.name);
expect(nameInput).toBeInTheDocument();
const expressionTextarea = screen.getByDisplayValue(
mockRoutingPolicy.expression,
);
expect(expressionTextarea).toBeInTheDocument();
expect(screen.getByText(MOCK_CHANNEL_1.name)).toBeInTheDocument();
});
it('creating and saving the routing policy works correctly', async () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const nameInput = screen.getByPlaceholderText('e.g. Base routing policy...');
expect(nameInput).toBeInTheDocument();
const expressionTextarea = screen.getByPlaceholderText(
'e.g. service.name == "payment" && threshold.name == "critical"',
);
expect(expressionTextarea).toBeInTheDocument();
const descriptionTextarea = screen.getByPlaceholderText(
'e.g. This is a routing policy that...',
);
expect(descriptionTextarea).toBeInTheDocument();
fireEvent.change(nameInput, { target: { value: NEW_NAME } });
fireEvent.change(expressionTextarea, { target: { value: NEW_EXPRESSION } });
fireEvent.change(descriptionTextarea, { target: { value: NEW_DESCRIPTION } });
const channelSelect = screen.getByRole('combobox');
fireEvent.mouseDown(channelSelect);
const channelOptions = await screen.findAllByText('Channel 1');
fireEvent.click(channelOptions[1]);
// Wait for the form to be valid before submitting
await waitFor(() => {
expect(screen.getByDisplayValue(NEW_NAME)).toBeInTheDocument();
});
const saveButton = screen.getByRole('button', {
name: 'Save Routing Policy',
});
fireEvent.click(saveButton);
// Wait for the form submission to complete
await waitFor(() => {
expect(mockHandlePolicyDetailsModalAction).toHaveBeenCalled();
});
expect(mockHandlePolicyDetailsModalAction).toHaveBeenCalledWith('create', {
name: NEW_NAME,
expression: NEW_EXPRESSION,
description: NEW_DESCRIPTION,
channels: ['Channel 1'],
});
});
it('editing and saving the routing policy works correctly', async () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="edit"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const nameInput = screen.getByDisplayValue(mockRoutingPolicy.name);
expect(nameInput).toBeInTheDocument();
const expressionTextarea = screen.getByDisplayValue(
mockRoutingPolicy.expression,
);
expect(expressionTextarea).toBeInTheDocument();
const descriptionTextarea = screen.getByDisplayValue(
mockRoutingPolicy.description || 'description 1',
);
expect(descriptionTextarea).toBeInTheDocument();
fireEvent.change(nameInput, { target: { value: NEW_NAME } });
fireEvent.change(expressionTextarea, { target: { value: NEW_EXPRESSION } });
fireEvent.change(descriptionTextarea, { target: { value: NEW_DESCRIPTION } });
// Wait for the form to be valid before submitting
await waitFor(() => {
expect(screen.getByDisplayValue(NEW_NAME)).toBeInTheDocument();
});
const saveButton = screen.getByRole('button', {
name: SAVE_BUTTON_TEXT,
});
fireEvent.click(saveButton);
// Wait for the form submission to complete
await waitFor(() => {
expect(mockHandlePolicyDetailsModalAction).toHaveBeenCalled();
});
expect(mockHandlePolicyDetailsModalAction).toHaveBeenCalledWith('edit', {
name: NEW_NAME,
expression: NEW_EXPRESSION,
description: NEW_DESCRIPTION,
channels: ['Channel 1'],
});
});
it('should close modal when cancel button is clicked', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="edit"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
fireEvent.click(cancelButton);
expect(mockCloseModal).toHaveBeenCalled();
});
it('buttons should be disabled when loading', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="edit"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
expect(cancelButton).toBeDisabled();
const saveButton = screen.getByRole('button', {
name: new RegExp(SAVE_BUTTON_TEXT, 'i'),
});
expect(saveButton).toBeDisabled();
});
it('submit should not be called when inputs are invalid', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={mockChannels}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const saveButton = screen.getByRole('button', {
name: SAVE_BUTTON_TEXT,
});
fireEvent.click(saveButton);
expect(mockHandlePolicyDetailsModalAction).not.toHaveBeenCalled();
});
it('notification channels select should be disabled when channels are loading', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
expect(channelSelect).toBeDisabled();
});
it('should show error state when channels fail to load', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
const selectContainer = channelSelect.closest('.ant-select');
expect(selectContainer).toHaveClass('ant-select-status-error');
});
it('should show empty state when no channels are available', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
fireEvent.mouseDown(channelSelect);
expect(screen.getByText(NO_CHANNELS_FOUND_TEXT)).toBeInTheDocument();
});
it('should show create channel button for admin users in empty state', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
fireEvent.mouseDown(channelSelect);
expect(screen.getByText(NO_CHANNELS_FOUND_TEXT)).toBeInTheDocument();
expect(screen.getByText('Create one')).toBeInTheDocument();
});
it('should show admin message for non-admin users in empty state', () => {
jest
.spyOn(appHooks, 'useAppContext')
.mockReturnValue(getAppContextMockState({ role: 'VIEWER' }));
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
fireEvent.mouseDown(channelSelect);
expect(screen.getByText(NO_CHANNELS_FOUND_TEXT)).toBeInTheDocument();
expect(
screen.getByText('Please ask your admin to create one.'),
).toBeInTheDocument();
expect(screen.queryByText('Create one')).not.toBeInTheDocument();
});
it('should call refreshChannels when refresh button is clicked in empty state', () => {
render(
<RoutingPolicyDetails
routingPolicy={mockRoutingPolicy}
closeModal={mockCloseModal}
mode="create"
channels={[]}
handlePolicyDetailsModalAction={mockHandlePolicyDetailsModalAction}
isPolicyDetailsModalActionLoading={false}
isErrorChannels={false}
isLoadingChannels={false}
refreshChannels={mockRefreshChannels}
/>,
);
const channelSelect = screen.getByRole('combobox');
fireEvent.mouseDown(channelSelect);
const refreshButton = screen.getByText('Refresh');
expect(refreshButton).toBeInTheDocument();
fireEvent.click(refreshButton);
expect(mockRefreshChannels).toHaveBeenCalledTimes(1);
});
});