From 13a819d4eadf474f533048a40968cca9d368e2af Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Mon, 21 Feb 2022 15:34:36 +0100 Subject: [PATCH] Add tests for alerts folder view --- .../unified/AlertsFolderView.test.tsx | 188 ++++++++++++++++++ .../alerting/unified/AlertsFolderView.tsx | 18 +- 2 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 public/app/features/alerting/unified/AlertsFolderView.test.tsx diff --git a/public/app/features/alerting/unified/AlertsFolderView.test.tsx b/public/app/features/alerting/unified/AlertsFolderView.test.tsx new file mode 100644 index 00000000000..54d14fe7249 --- /dev/null +++ b/public/app/features/alerting/unified/AlertsFolderView.test.tsx @@ -0,0 +1,188 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { FolderState } from 'app/types'; +import { AlertsFolderView } from './AlertsFolderView'; +import { byTestId, byText } from 'testing-library-selector'; +import { CombinedRuleNamespace } from 'app/types/unified-alerting'; +import { configureStore } from 'app/store/configureStore'; +import { Provider } from 'react-redux'; +import { MemoryRouter } from 'react-router-dom'; +import { mockCombinedRule } from './mocks'; +import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; +import userEvent from '@testing-library/user-event'; + +const ui = { + filter: { + name: byTestId('name-filter'), + label: byTestId('label-filter'), + }, + ruleList: { + row: byTestId('alert-card-row'), + }, +}; + +const combinedNamespaceMock = jest.fn(); +jest.mock('./hooks/useCombinedRuleNamespaces', () => ({ + useCombinedRuleNamespaces: () => combinedNamespaceMock(), +})); + +const mockFolder = (folderOverride: Partial = {}): FolderState => { + return { + id: 1, + title: 'Folder with alerts', + uid: 'folder-1', + hasChanged: false, + canSave: false, + url: '/folder-1', + version: 1, + permissions: [], + canViewFolderPermissions: false, + ...folderOverride, + }; +}; + +describe('AlertsFolderView tests', () => { + it('Should display grafana alert rules when the namespace name matches the folder name', () => { + // Arrange + const store = configureStore(); + const folder = mockFolder(); + + const grafanaNamespace: CombinedRuleNamespace = { + name: folder.title, + rulesSource: GRAFANA_RULES_SOURCE_NAME, + groups: [ + { + name: 'default', + rules: [ + mockCombinedRule({ name: 'Test Alert 1' }), + mockCombinedRule({ name: 'Test Alert 2' }), + mockCombinedRule({ name: 'Test Alert 3' }), + ], + }, + ], + }; + + combinedNamespaceMock.mockReturnValue([grafanaNamespace]); + + // Act + render( + + + + + + ); + + // Assert + const alertRows = ui.ruleList.row.queryAll(); + expect(alertRows).toHaveLength(3); + expect(alertRows[0]).toHaveTextContent('Test Alert 1'); + expect(alertRows[1]).toHaveTextContent('Test Alert 2'); + expect(alertRows[2]).toHaveTextContent('Test Alert 3'); + }); + + it('Shold not display alert rules when the namespace name does not match the folder name', () => { + // Arrange + const store = configureStore(); + const folder = mockFolder(); + + const grafanaNamespace: CombinedRuleNamespace = { + name: 'Folder without alerts', + rulesSource: GRAFANA_RULES_SOURCE_NAME, + groups: [ + { + name: 'default', + rules: [ + mockCombinedRule({ name: 'Test Alert from other folder 1' }), + mockCombinedRule({ name: 'Test Alert from other folder 2' }), + ], + }, + ], + }; + + combinedNamespaceMock.mockReturnValue([grafanaNamespace]); + + // Act + render( + + + + + + ); + + // Assert + expect(ui.ruleList.row.queryAll()).toHaveLength(0); + }); + + it('Should filter alert rules by the name, case insensitive', () => { + // Arrange + const store = configureStore(); + const folder = mockFolder(); + + const grafanaNamespace: CombinedRuleNamespace = { + name: folder.title, + rulesSource: GRAFANA_RULES_SOURCE_NAME, + groups: [ + { + name: 'default', + rules: [mockCombinedRule({ name: 'CPU Alert' }), mockCombinedRule({ name: 'RAM usage alert' })], + }, + ], + }; + + combinedNamespaceMock.mockReturnValue([grafanaNamespace]); + + // Act + render( + + + + + + ); + + userEvent.type(ui.filter.name.get(), 'cpu'); + + // Assert + expect(ui.ruleList.row.queryAll()).toHaveLength(1); + expect(ui.ruleList.row.get()).toHaveTextContent('CPU Alert'); + }); + + it('Should filter alert rule by labels', () => { + // Arrange + const store = configureStore(); + const folder = mockFolder(); + + const grafanaNamespace: CombinedRuleNamespace = { + name: folder.title, + rulesSource: GRAFANA_RULES_SOURCE_NAME, + groups: [ + { + name: 'default', + rules: [ + mockCombinedRule({ name: 'CPU Alert', labels: {} }), + mockCombinedRule({ name: 'RAM usage alert', labels: { severity: 'critical' } }), + ], + }, + ], + }; + + combinedNamespaceMock.mockReturnValue([grafanaNamespace]); + + // Act + render( + + + + + + ); + + userEvent.type(ui.filter.label.get(), 'severity=critical'); + + // Assert + expect(ui.ruleList.row.queryAll()).toHaveLength(1); + expect(ui.ruleList.row.get()).toHaveTextContent('RAM usage alert'); + }); +}); diff --git a/public/app/features/alerting/unified/AlertsFolderView.tsx b/public/app/features/alerting/unified/AlertsFolderView.tsx index 42b6e828373..b07d98c5e6a 100644 --- a/public/app/features/alerting/unified/AlertsFolderView.tsx +++ b/public/app/features/alerting/unified/AlertsFolderView.tsx @@ -8,7 +8,7 @@ import { useDispatch } from 'react-redux'; import { useDebounce } from 'react-use'; import { useCombinedRuleNamespaces } from './hooks/useCombinedRuleNamespaces'; import { useURLSearchParams } from './hooks/useURLSearchParams'; -import { fetchAllPromAndRulerRulesAction } from './state/actions'; +import { fetchAllPromAndRulerRulesAction, fetchPromRulesAction, fetchRulerRulesAction } from './state/actions'; import { labelsMatchMatchers, parseMatchers } from './utils/alertmanager'; import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; import { createViewLink } from './utils/misc'; @@ -17,12 +17,15 @@ interface Props { folder: FolderState; } +const ITEMS_PER_PAGE = 20; + export const AlertsFolderView = ({ folder }: Props) => { const styles = useStyles2(getStyles); const dispatch = useDispatch(); useEffect(() => { - dispatch(fetchAllPromAndRulerRulesAction()); + dispatch(fetchPromRulesAction({ rulesSourceName: GRAFANA_RULES_SOURCE_NAME })); + dispatch(fetchRulerRulesAction({ rulesSourceName: GRAFANA_RULES_SOURCE_NAME })); }, [dispatch]); const combinedNamespaces = useCombinedRuleNamespaces(GRAFANA_RULES_SOURCE_NAME); @@ -37,7 +40,7 @@ export const AlertsFolderView = ({ folder }: Props) => { ); const showNoResultsText = alertRules.length === 0 || filteredRules.length === 0; - const { page, numberOfPages, onPageChange, pageItems } = usePagination(filteredRules, 1, 5); + const { page, numberOfPages, onPageChange, pageItems } = usePagination(filteredRules, 1, ITEMS_PER_PAGE); return ( @@ -47,17 +50,24 @@ export const AlertsFolderView = ({ folder }: Props) => { onChange={setNameFilter} placeholder="Search alert rules by name" className={styles.filterInput} + data-testid="name-filter" />
{pageItems.map((currentRule) => ( - + {currentRule.name}