From 45d7169f8b52c2b2bec0c0f08a524d80a2a71166 Mon Sep 17 00:00:00 2001 From: rodrigopk Date: Tue, 6 Jan 2026 14:58:35 -0500 Subject: [PATCH] Add tests and use isUngroupedRuleGroup in PaginatedGrafanaLoader --- .../rule-list/PaginatedGrafanaLoader.test.tsx | 98 +++++++++++++++++++ .../rule-list/PaginatedGrafanaLoader.tsx | 6 +- 2 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.test.tsx diff --git a/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.test.tsx b/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.test.tsx new file mode 100644 index 00000000000..703f3e0ab03 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.test.tsx @@ -0,0 +1,98 @@ +import { render, screen } from 'test/test-utils'; +import { byRole, byText } from 'testing-library-selector'; + +import { AccessControlAction } from 'app/types/accessControl'; +import { GrafanaPromRuleGroupDTO } from 'app/types/unified-alerting-dto'; + +import { mockFolderApi, setupMswServer } from '../mockApi'; +import { grantUserPermissions, mockFolder, mockGrafanaPromAlertingRule } from '../mocks'; +import { NO_GROUP_PREFIX } from '../utils/rules'; + +import { GrafanaRuleGroupListItem } from './PaginatedGrafanaLoader'; + +const server = setupMswServer(); + +const ui = { + treeItem: byRole('treeitem'), + groupLink: (name: string | RegExp) => byRole('link', { name }), + ungroupedText: byText(/\(Ungrouped\)/), +}; + +describe('GrafanaRuleGroupListItem', () => { + beforeEach(() => { + grantUserPermissions([AccessControlAction.AlertingRuleRead]); + mockFolderApi(server).folder('folder-123', mockFolder({ uid: 'folder-123', title: 'TestFolder' })); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + it('should display rule name with (Ungrouped) suffix for ungrouped rules', async () => { + const grafanaRule = mockGrafanaPromAlertingRule({ name: 'My Alert Rule' }); + const ungroupedGroup: GrafanaPromRuleGroupDTO = { + name: `${NO_GROUP_PREFIX}test-rule-uid`, + file: 'TestFolder', + folderUid: 'folder-123', + interval: 60, + rules: [grafanaRule], + }; + + render(); + + expect(await ui.treeItem.find()).toBeInTheDocument(); + expect(await ui.groupLink(/My Alert Rule \(Ungrouped\)/).find()).toBeInTheDocument(); + }); + + it('should display normal group name for grouped rules', async () => { + const grafanaRule = mockGrafanaPromAlertingRule({ name: 'My Alert Rule' }); + const groupedGroup: GrafanaPromRuleGroupDTO = { + name: 'MyGroup', + file: 'TestFolder', + folderUid: 'folder-123', + interval: 60, + rules: [grafanaRule], + }; + + render(); + + expect(await ui.groupLink('MyGroup').find()).toBeInTheDocument(); + expect(screen.queryByText(/Ungrouped/)).not.toBeInTheDocument(); + }); + + it('should render link to group details page with correct URL', async () => { + const grafanaRule = mockGrafanaPromAlertingRule({ name: 'My Alert Rule' }); + const groupedGroup: GrafanaPromRuleGroupDTO = { + name: 'MyGroup', + file: 'TestFolder', + folderUid: 'folder-123', + interval: 60, + rules: [grafanaRule], + }; + + render(); + + const link = await ui.groupLink('MyGroup').find(); + expect(link).toHaveAttribute( + 'href', + expect.stringContaining('/alerting/grafana/namespaces/folder-123/groups/MyGroup/view') + ); + }); + + it('should render as treeitem with correct aria attributes', async () => { + const grafanaRule = mockGrafanaPromAlertingRule({ name: 'My Alert Rule' }); + const group: GrafanaPromRuleGroupDTO = { + name: 'TestGroup', + file: 'TestFolder', + folderUid: 'folder-123', + interval: 60, + rules: [grafanaRule], + }; + + render(); + + const treeItem = await ui.treeItem.find(); + expect(treeItem).toHaveAttribute('aria-expanded', 'false'); + expect(treeItem).toHaveAttribute('aria-selected', 'false'); + }); +}); diff --git a/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.tsx b/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.tsx index 8225dd0aed7..8fffeddf261 100644 --- a/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.tsx +++ b/public/app/features/alerting/unified/rule-list/PaginatedGrafanaLoader.tsx @@ -9,6 +9,7 @@ import { FolderActionsButton } from '../components/folder-actions/FolderActionsB import { GrafanaNoRulesCTA } from '../components/rules/NoRulesCTA'; import { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource'; import { groups } from '../utils/navigation'; +import { isUngroupedRuleGroup } from '../utils/rules'; import { GrafanaGroupLoader } from './GrafanaGroupLoader'; import { DataSourceSection } from './components/DataSourceSection'; @@ -147,9 +148,6 @@ interface GrafanaRuleGroupListItemProps { namespaceName: string; } -const NoGroupPrefix = 'no_group_for_rule_'; -const isNoGroup = (group: string) => group.startsWith(NoGroupPrefix); - export function GrafanaRuleGroupListItem({ group, namespaceName }: GrafanaRuleGroupListItemProps) { const groupIdentifier: GrafanaRuleGroupIdentifier = useMemo( () => ({ @@ -164,7 +162,7 @@ export function GrafanaRuleGroupListItem({ group, namespaceName }: GrafanaRuleGr const detailsLink = groups.detailsPageLink(GRAFANA_RULES_SOURCE_NAME, group.folderUid, group.name); - const groupDisplayName = isNoGroup(group.name) ? `${group.rules[0].name} (Ungrouped)` : group.name; + const groupDisplayName = isUngroupedRuleGroup(group.name) ? `${group.rules[0].name} (Ungrouped)` : group.name; return (