The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/alerting/unified/NotificationPolicies.test.tsx

826 lines
27 KiB

import { render, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
import { DataSourceSrv, locationService, setDataSourceSrv } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import {
AlertManagerCortexConfig,
AlertManagerDataSourceJsonData,
AlertManagerImplementation,
MatcherOperator,
MuteTimeInterval,
Route,
RouteWithID,
} from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import NotificationPolicies, { findRoutesMatchingFilters } from './NotificationPolicies';
import { fetchAlertManagerConfig, fetchStatus, updateAlertManagerConfig } from './api/alertmanager';
import { alertmanagerApi } from './api/alertmanagerApi';
import { discoverAlertmanagerFeatures } from './api/buildInfo';
import * as grafanaApp from './components/receivers/grafanaAppReceivers/grafanaApp';
import { mockDataSource, MockDataSourceSrv, someCloudAlertManagerConfig, someCloudAlertManagerStatus } from './mocks';
import { defaultGroupBy } from './utils/amroutes';
import { getAllDataSources } from './utils/config';
import { ALERTMANAGER_NAME_QUERY_KEY } from './utils/constants';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
jest.mock('./api/alertmanager');
jest.mock('./utils/config');
jest.mock('app/core/services/context_srv');
jest.mock('./api/buildInfo');
jest.mock('./useRouteGroupsMatcher');
const mocks = {
getAllDataSourcesMock: jest.mocked(getAllDataSources),
api: {
fetchAlertManagerConfig: jest.mocked(fetchAlertManagerConfig),
updateAlertManagerConfig: jest.mocked(updateAlertManagerConfig),
fetchStatus: jest.mocked(fetchStatus),
discoverAlertmanagerFeatures: jest.mocked(discoverAlertmanagerFeatures),
},
contextSrv: jest.mocked(contextSrv),
};
const useGetGrafanaReceiverTypeCheckerMock = jest.spyOn(grafanaApp, 'useGetGrafanaReceiverTypeChecker');
const renderNotificationPolicies = (alertManagerSourceName?: string) => {
locationService.push(location);
locationService.push(
'/alerting/routes' + (alertManagerSourceName ? `?${ALERTMANAGER_NAME_QUERY_KEY}=${alertManagerSourceName}` : '')
);
return render(
<TestProvider>
<NotificationPolicies />
</TestProvider>
);
};
const dataSources = {
am: mockDataSource({
name: 'Alertmanager',
type: DataSourceType.Alertmanager,
}),
promAlertManager: mockDataSource<AlertManagerDataSourceJsonData>({
name: 'PromManager',
type: DataSourceType.Alertmanager,
jsonData: {
implementation: AlertManagerImplementation.prometheus,
},
}),
};
const ui = {
rootReceiver: byTestId('am-routes-root-receiver'),
rootGroupBy: byTestId('am-routes-root-group-by'),
rootTimings: byTestId('am-routes-root-timings'),
row: byTestId('am-routes-row'),
rootRouteContainer: byTestId('am-root-route-container'),
editButton: byRole('button', { name: 'Edit' }),
saveButton: byRole('button', { name: 'Save' }),
setDefaultReceiverCTA: byRole('button', { name: 'Set a default contact point' }),
editRouteButton: byLabelText('Edit route'),
deleteRouteButton: byLabelText('Delete route'),
newPolicyButton: byRole('button', { name: /Add policy/ }),
newPolicyCTAButton: byRole('button', { name: /Add specific policy/ }),
savePolicyButton: byRole('button', { name: /save policy/i }),
receiverSelect: byTestId('am-receiver-select'),
groupSelect: byTestId('am-group-select'),
muteTimingSelect: byTestId('am-mute-timing-select'),
groupWaitContainer: byTestId('am-group-wait'),
groupIntervalContainer: byTestId('am-group-interval'),
groupRepeatContainer: byTestId('am-repeat-interval'),
confirmDeleteModal: byRole('dialog'),
confirmDeleteButton: byLabelText('Confirm Modal Danger Button'),
};
describe('NotificationPolicies', () => {
const subroutes: Route[] = [
{
match: {
sub1matcher1: 'sub1value1',
sub1matcher2: 'sub1value2',
},
match_re: {
sub1matcher3: 'sub1value3',
sub1matcher4: 'sub1value4',
},
group_by: ['sub1group1', 'sub1group2'],
receiver: 'a-receiver',
continue: true,
group_wait: '3s',
group_interval: '2m',
repeat_interval: '1s',
routes: [
{
match: {
sub1sub1matcher1: 'sub1sub1value1',
sub1sub1matcher2: 'sub1sub1value2',
},
match_re: {
sub1sub1matcher3: 'sub1sub1value3',
sub1sub1matcher4: 'sub1sub1value4',
},
group_by: ['sub1sub1group1', 'sub1sub1group2'],
receiver: 'another-receiver',
},
{
match: {
sub1sub2matcher1: 'sub1sub2value1',
sub1sub2matcher2: 'sub1sub2value2',
},
match_re: {
sub1sub2matcher3: 'sub1sub2value3',
sub1sub2matcher4: 'sub1sub2value4',
},
group_by: ['sub1sub2group1', 'sub1sub2group2'],
receiver: 'another-receiver',
},
],
},
{
match: {
sub2matcher1: 'sub2value1',
sub2matcher2: 'sub2value2',
},
match_re: {
sub2matcher3: 'sub2value3',
sub2matcher4: 'sub2value4',
},
receiver: 'another-receiver',
},
];
const emptyRoute: Route = {};
const simpleRoute: Route = {
receiver: 'simple-receiver',
matchers: ['hello=world', 'foo!=bar'],
};
const rootRoute: Route = {
receiver: 'default-receiver',
group_by: ['a-group', 'another-group'],
group_wait: '1s',
group_interval: '2m',
repeat_interval: '3d',
routes: subroutes,
};
const muteInterval: MuteTimeInterval = {
name: 'default-mute',
time_intervals: [
{
times: [{ start_time: '12:00', end_time: '24:00' }],
weekdays: ['monday:friday'],
days_of_month: ['1:7', '-1:-7'],
months: ['january:june'],
years: ['2020:2022'],
},
],
};
beforeEach(() => {
mocks.getAllDataSourcesMock.mockReturnValue(Object.values(dataSources));
mocks.contextSrv.hasAccess.mockImplementation(() => true);
mocks.contextSrv.hasPermission.mockImplementation(() => true);
mocks.contextSrv.evaluatePermission.mockImplementation(() => []);
mocks.api.discoverAlertmanagerFeatures.mockResolvedValue({ lazyConfigInit: false });
setDataSourceSrv(new MockDataSourceSrv(dataSources));
useGetGrafanaReceiverTypeCheckerMock.mockReturnValue(() => undefined);
});
afterEach(() => {
jest.resetAllMocks();
setDataSourceSrv(undefined as unknown as DataSourceSrv);
});
it.skip('loads and shows routes', async () => {
mocks.api.fetchAlertManagerConfig.mockResolvedValue({
alertmanager_config: {
route: rootRoute,
receivers: [
{
name: 'default-receiver',
},
{
name: 'a-receiver',
},
{
name: 'another-receiver',
},
],
},
template_files: {},
});
await renderNotificationPolicies();
await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(1));
expect(ui.rootReceiver.get()).toHaveTextContent(rootRoute.receiver!);
expect(ui.rootGroupBy.get()).toHaveTextContent(rootRoute.group_by!.join(', '));
const rootTimings = ui.rootTimings.get();
expect(rootTimings).toHaveTextContent(rootRoute.group_wait!);
expect(rootTimings).toHaveTextContent(rootRoute.group_interval!);
expect(rootTimings).toHaveTextContent(rootRoute.repeat_interval!);
const rows = await ui.row.findAll();
expect(rows).toHaveLength(2);
subroutes.forEach((route, index) => {
Object.entries(route.match ?? {}).forEach(([label, value]) => {
expect(rows[index]).toHaveTextContent(`${label}=${value}`);
});
Object.entries(route.match_re ?? {}).forEach(([label, value]) => {
expect(rows[index]).toHaveTextContent(`${label}=~${value}`);
});
if (route.group_by) {
expect(rows[index]).toHaveTextContent(route.group_by.join(', '));
}
if (route.receiver) {
expect(rows[index]).toHaveTextContent(route.receiver);
}
});
});
it.skip('can edit root route if one is already defined', async () => {
const defaultConfig: AlertManagerCortexConfig = {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
receiver: 'default',
group_by: ['alertname'],
},
templates: [],
},
template_files: {},
};
const currentConfig = { current: defaultConfig };
mocks.api.updateAlertManagerConfig.mockImplementation((amSourceName, newConfig) => {
currentConfig.current = newConfig;
return Promise.resolve();
});
mocks.api.fetchAlertManagerConfig.mockImplementation(() => {
return Promise.resolve(currentConfig.current);
});
await renderNotificationPolicies();
expect(await ui.rootReceiver.find()).toHaveTextContent('default');
expect(ui.rootGroupBy.get()).toHaveTextContent('alertname');
// open root route for editing
const rootRouteContainer = await ui.rootRouteContainer.find();
await userEvent.click(ui.editButton.get(rootRouteContainer));
// configure receiver & group by
const receiverSelect = await ui.receiverSelect.find();
await clickSelectOption(receiverSelect, 'critical');
const groupSelect = ui.groupSelect.get();
await userEvent.type(byRole('combobox').get(groupSelect), 'namespace{enter}');
// configure timing intervals
await userEvent.click(byText('Timing options').get(rootRouteContainer));
await updateTiming(ui.groupWaitContainer.get(), '1', 'Minutes');
await updateTiming(ui.groupIntervalContainer.get(), '4', 'Minutes');
await updateTiming(ui.groupRepeatContainer.get(), '5', 'Hours');
//save
await userEvent.click(ui.saveButton.get(rootRouteContainer));
// wait for it to go out of edit mode
await waitFor(() => expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument());
// check that appropriate api calls were made
expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(3);
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledTimes(1);
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith(GRAFANA_RULES_SOURCE_NAME, {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
group_by: ['alertname', 'namespace'],
receiver: 'critical',
routes: [],
group_interval: '4m',
group_wait: '1m',
repeat_interval: '5h',
mute_time_intervals: [],
},
templates: [],
},
template_files: {},
});
// check that new config values are rendered
await waitFor(() => expect(ui.rootReceiver.query()).toHaveTextContent('critical'));
expect(ui.rootGroupBy.get()).toHaveTextContent('alertname, namespace');
});
it.skip('can edit root route if one is not defined yet', async () => {
mocks.api.fetchAlertManagerConfig.mockResolvedValue({
alertmanager_config: {
receivers: [{ name: 'default' }],
},
template_files: {},
});
await renderNotificationPolicies();
// open root route for editing
const rootRouteContainer = await ui.rootRouteContainer.find();
await userEvent.click(ui.editButton.get(rootRouteContainer));
// configure receiver & group by
const receiverSelect = await ui.receiverSelect.find();
await clickSelectOption(receiverSelect, 'default');
const groupSelect = ui.groupSelect.get();
await userEvent.type(byRole('combobox').get(groupSelect), 'severity{enter}');
await userEvent.type(byRole('combobox').get(groupSelect), 'namespace{enter}');
//save
await userEvent.click(ui.saveButton.get(rootRouteContainer));
// wait for it to go out of edit mode
await waitFor(() => expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument());
// check that appropriate api calls were made
expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(3);
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledTimes(1);
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith(GRAFANA_RULES_SOURCE_NAME, {
alertmanager_config: {
receivers: [{ name: 'default' }],
route: {
continue: false,
group_by: defaultGroupBy.concat(['severity', 'namespace']),
receiver: 'default',
routes: [],
mute_time_intervals: [],
},
},
template_files: {},
});
});
it('hides create and edit button if user does not have permission', async () => {
mocks.contextSrv.hasAccess.mockImplementation((action) =>
[AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsRead].includes(
action as AccessControlAction
)
);
renderNotificationPolicies();
await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(1));
expect(ui.newPolicyButton.query()).not.toBeInTheDocument();
expect(ui.editButton.query()).not.toBeInTheDocument();
});
it('Show error message if loading Alertmanager config fails', async () => {
mocks.api.fetchAlertManagerConfig.mockRejectedValue({
status: 500,
data: {
message: "Alertmanager has exploded. it's gone. Forget about it.",
},
});
jest.spyOn(alertmanagerApi, 'useGetAlertmanagerAlertGroupsQuery').mockImplementation(() => ({
currentData: [],
refetch: jest.fn(),
}));
await renderNotificationPolicies();
await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(1));
expect(await byText("Alertmanager has exploded. it's gone. Forget about it.").find()).toBeInTheDocument();
expect(ui.rootReceiver.query()).not.toBeInTheDocument();
expect(ui.editButton.query()).not.toBeInTheDocument();
});
it.skip('Converts matchers to object_matchers for grafana alertmanager', async () => {
const defaultConfig: AlertManagerCortexConfig = {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
receiver: 'default',
group_by: ['alertname'],
routes: [simpleRoute],
group_interval: '4m',
group_wait: '1m',
repeat_interval: '5h',
},
templates: [],
},
template_files: {},
};
const currentConfig = { current: defaultConfig };
mocks.api.updateAlertManagerConfig.mockImplementation((amSourceName, newConfig) => {
currentConfig.current = newConfig;
return Promise.resolve();
});
mocks.api.fetchAlertManagerConfig.mockImplementation(() => {
return Promise.resolve(currentConfig.current);
});
await renderNotificationPolicies(GRAFANA_RULES_SOURCE_NAME);
expect(await ui.rootReceiver.find()).toHaveTextContent('default');
expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled();
// Toggle a save to test new object_matchers
const rootRouteContainer = await ui.rootRouteContainer.find();
await userEvent.click(ui.editButton.get(rootRouteContainer));
await userEvent.click(ui.saveButton.get(rootRouteContainer));
await waitFor(() => expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument());
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled();
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith(GRAFANA_RULES_SOURCE_NAME, {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
group_by: ['alertname'],
group_interval: '4m',
group_wait: '1m',
receiver: 'default',
repeat_interval: '5h',
mute_time_intervals: [],
routes: [
{
continue: false,
group_by: [],
object_matchers: [
['hello', '=', 'world'],
['foo', '!=', 'bar'],
],
receiver: 'simple-receiver',
mute_time_intervals: [],
routes: [],
},
],
},
templates: [],
},
template_files: {},
});
});
it.skip('Should be able to delete an empty route', async () => {
const routeConfig = {
continue: false,
receiver: 'default',
group_by: ['alertname'],
routes: [emptyRoute],
group_interval: '4m',
group_wait: '1m',
repeat_interval: '5h',
mute_time_intervals: [],
};
const defaultConfig: AlertManagerCortexConfig = {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: routeConfig,
templates: [],
},
template_files: {},
};
mocks.api.fetchAlertManagerConfig.mockImplementation(() => {
return Promise.resolve(defaultConfig);
});
mocks.api.updateAlertManagerConfig.mockResolvedValue(Promise.resolve());
await renderNotificationPolicies(GRAFANA_RULES_SOURCE_NAME);
await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled());
const deleteButtons = await ui.deleteRouteButton.findAll();
expect(deleteButtons).toHaveLength(1);
await userEvent.click(deleteButtons[0]);
const confirmDeleteButton = ui.confirmDeleteButton.get(ui.confirmDeleteModal.get());
expect(confirmDeleteButton).toBeInTheDocument();
await userEvent.click(confirmDeleteButton);
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith<[string, AlertManagerCortexConfig]>(
GRAFANA_RULES_SOURCE_NAME,
{
...defaultConfig,
alertmanager_config: {
...defaultConfig.alertmanager_config,
route: {
...routeConfig,
routes: [],
},
},
}
);
});
it.skip('Keeps matchers for non-grafana alertmanager sources', async () => {
const defaultConfig: AlertManagerCortexConfig = {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
receiver: 'default',
group_by: ['alertname'],
routes: [simpleRoute],
group_interval: '4m',
group_wait: '1m',
repeat_interval: '5h',
},
templates: [],
},
template_files: {},
};
const currentConfig = { current: defaultConfig };
mocks.api.updateAlertManagerConfig.mockImplementation((amSourceName, newConfig) => {
currentConfig.current = newConfig;
return Promise.resolve();
});
mocks.api.fetchAlertManagerConfig.mockImplementation(() => {
return Promise.resolve(currentConfig.current);
});
await renderNotificationPolicies(dataSources.am.name);
expect(await ui.rootReceiver.find()).toHaveTextContent('default');
expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled();
// Toggle a save to test new object_matchers
const rootRouteContainer = await ui.rootRouteContainer.find();
await userEvent.click(ui.editButton.get(rootRouteContainer));
await userEvent.click(ui.saveButton.get(rootRouteContainer));
await waitFor(() => expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument());
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled();
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith(dataSources.am.name, {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
group_by: ['alertname'],
group_interval: '4m',
group_wait: '1m',
matchers: [],
receiver: 'default',
repeat_interval: '5h',
mute_time_intervals: [],
routes: [
{
continue: false,
group_by: [],
matchers: ['hello=world', 'foo!=bar'],
receiver: 'simple-receiver',
routes: [],
mute_time_intervals: [],
},
],
},
templates: [],
},
template_files: {},
});
});
it.skip('Prometheus Alertmanager routes cannot be edited', async () => {
mocks.api.fetchStatus.mockResolvedValue({
...someCloudAlertManagerStatus,
config: someCloudAlertManagerConfig.alertmanager_config,
});
await renderNotificationPolicies(dataSources.promAlertManager.name);
const rootRouteContainer = await ui.rootRouteContainer.find();
expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument();
const rows = await ui.row.findAll();
expect(rows).toHaveLength(2);
expect(ui.editRouteButton.query()).not.toBeInTheDocument();
expect(ui.deleteRouteButton.query()).not.toBeInTheDocument();
expect(ui.saveButton.query()).not.toBeInTheDocument();
expect(mocks.api.fetchAlertManagerConfig).not.toHaveBeenCalled();
expect(mocks.api.fetchStatus).toHaveBeenCalledTimes(1);
});
it('Prometheus Alertmanager has no CTA button if there are no specific policies', async () => {
mocks.api.fetchStatus.mockResolvedValue({
...someCloudAlertManagerStatus,
config: {
...someCloudAlertManagerConfig.alertmanager_config,
route: {
...someCloudAlertManagerConfig.alertmanager_config.route,
routes: undefined,
},
},
});
jest.spyOn(alertmanagerApi, 'useGetAlertmanagerAlertGroupsQuery').mockImplementation(() => ({
currentData: [],
refetch: jest.fn(),
}));
await renderNotificationPolicies(dataSources.promAlertManager.name);
const rootRouteContainer = await ui.rootRouteContainer.find();
await waitFor(() =>
expect(within(rootRouteContainer).getByTestId('matching-instances')).toHaveTextContent('0instances')
);
expect(ui.editButton.query(rootRouteContainer)).not.toBeInTheDocument();
expect(ui.newPolicyCTAButton.query()).not.toBeInTheDocument();
expect(mocks.api.fetchAlertManagerConfig).not.toHaveBeenCalled();
expect(mocks.api.fetchStatus).toHaveBeenCalledTimes(1);
});
it.skip('Can add a mute timing to a route', async () => {
const defaultConfig: AlertManagerCortexConfig = {
alertmanager_config: {
receivers: [{ name: 'default' }, { name: 'critical' }],
route: {
continue: false,
receiver: 'default',
group_by: ['alertname'],
routes: [simpleRoute],
group_interval: '4m',
group_wait: '1m',
repeat_interval: '5h',
},
templates: [],
mute_time_intervals: [muteInterval],
},
template_files: {},
};
const currentConfig = { current: defaultConfig };
mocks.api.updateAlertManagerConfig.mockImplementation((amSourceName, newConfig) => {
currentConfig.current = newConfig;
return Promise.resolve();
});
mocks.api.fetchAlertManagerConfig.mockResolvedValue(defaultConfig);
await renderNotificationPolicies(dataSources.am.name);
const rows = await ui.row.findAll();
expect(rows).toHaveLength(1);
await userEvent.click(ui.editRouteButton.get(rows[0]));
const muteTimingSelect = ui.muteTimingSelect.get();
await clickSelectOption(muteTimingSelect, 'default-mute');
expect(muteTimingSelect).toHaveTextContent('default-mute');
const savePolicyButton = ui.savePolicyButton.get();
expect(savePolicyButton).toBeInTheDocument();
await userEvent.click(savePolicyButton);
await waitFor(() => expect(savePolicyButton).not.toBeInTheDocument());
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled();
expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith(dataSources.am.name, {
...defaultConfig,
alertmanager_config: {
...defaultConfig.alertmanager_config,
route: {
...defaultConfig.alertmanager_config.route,
mute_time_intervals: [],
matchers: [],
routes: [
{
...simpleRoute,
mute_time_intervals: [muteInterval.name],
routes: [],
continue: false,
group_by: [],
},
],
},
},
});
});
it.skip('Shows an empty config when config returns an error and the AM supports lazy config initialization', async () => {
mocks.api.discoverAlertmanagerFeatures.mockResolvedValue({ lazyConfigInit: true });
mocks.api.fetchAlertManagerConfig.mockRejectedValue({
message: 'alertmanager storage object not found',
});
await renderNotificationPolicies();
await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(1));
expect(ui.rootReceiver.query()).toBeInTheDocument();
expect(ui.setDefaultReceiverCTA.query()).toBeInTheDocument();
});
});
describe('findRoutesMatchingFilters', () => {
const simpleRouteTree: RouteWithID = {
id: '0',
receiver: 'default-receiver',
routes: [
{
id: '1',
receiver: 'simple-receiver',
matchers: ['hello=world', 'foo!=bar'],
routes: [
{
id: '2',
matchers: ['bar=baz'],
},
],
},
],
};
it('should not match non-existing', () => {
expect(
findRoutesMatchingFilters(simpleRouteTree, {
labelMatchersFilter: [['foo', MatcherOperator.equal, 'bar']],
})
).toHaveLength(0);
expect(
findRoutesMatchingFilters(simpleRouteTree, {
contactPointFilter: 'does-not-exist',
})
).toHaveLength(0);
});
it('should work with only label matchers', () => {
const matchingRoutes = findRoutesMatchingFilters(simpleRouteTree, {
labelMatchersFilter: [['hello', MatcherOperator.equal, 'world']],
});
expect(matchingRoutes).toHaveLength(1);
expect(matchingRoutes[0]).toHaveProperty('id', '1');
});
it('should work with only contact point and inheritance', () => {
const matchingRoutes = findRoutesMatchingFilters(simpleRouteTree, {
contactPointFilter: 'simple-receiver',
});
expect(matchingRoutes).toHaveLength(2);
expect(matchingRoutes[0]).toHaveProperty('id', '1');
expect(matchingRoutes[1]).toHaveProperty('id', '2');
});
it('should work with non-intersecting filters', () => {
const matchingRoutes = findRoutesMatchingFilters(simpleRouteTree, {
labelMatchersFilter: [['hello', MatcherOperator.equal, 'world']],
contactPointFilter: 'does-not-exist',
});
expect(matchingRoutes).toHaveLength(0);
});
it('should work with all filters', () => {
const matchingRoutes = findRoutesMatchingFilters(simpleRouteTree, {
labelMatchersFilter: [['hello', MatcherOperator.equal, 'world']],
contactPointFilter: 'simple-receiver',
});
expect(matchingRoutes).toHaveLength(1);
expect(matchingRoutes[0]).toHaveProperty('id', '1');
});
});
const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise<void> => {
await userEvent.click(byRole('combobox').get(selectElement));
await selectOptionInTest(selectElement, optionText);
};
const updateTiming = async (selectElement: HTMLElement, value: string, timeUnit: string): Promise<void> => {
const input = byRole('textbox').get(selectElement);
const select = byRole('combobox').get(selectElement);
await userEvent.clear(input);
await userEvent.type(input, value);
await userEvent.click(select);
await selectOptionInTest(selectElement, timeUnit);
};