diff --git a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx index a3aeec38bdc..6f46fdb4ab1 100644 --- a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx @@ -3,44 +3,25 @@ import { ui } from 'test/helpers/alertingRuleEditor'; import { render, screen } from 'test/test-utils'; import { contextSrv } from 'app/core/services/context_srv'; -import { DashboardSearchHit, DashboardSearchItemType } from 'app/features/search/types'; +import { setFolderResponse } from 'app/features/alerting/unified/mocks/server/configure'; +import { captureRequests } from 'app/features/alerting/unified/mocks/server/events'; +import { DashboardSearchItemType } from 'app/features/search/types'; -import { searchFolders } from '../../../../app/features/manage-dashboards/state/actions'; -import { backendSrv } from '../../../core/services/backend_srv'; import { AccessControlAction } from '../../../types'; import RuleEditor from './RuleEditor'; -import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; import { setupMswServer } from './mockApi'; import { grantUserPermissions, mockDataSource, mockFolder } from './mocks'; import { grafanaRulerRule } from './mocks/grafanaRulerApi'; import { setupDataSources } from './testSetup/datasources'; import { Annotation } from './utils/constants'; -jest.mock('./components/rule-editor/ExpressionEditor', () => ({ - ExpressionEditor: ({ value, onChange }: ExpressionEditorProps) => ( - onChange(e.target.value)} /> - ), -})); - jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) =>
hi
, -})); - jest.setTimeout(60 * 1000); -const mocks = { - searchFolders: jest.mocked(searchFolders), -}; - setupMswServer(); function renderRuleEditor(identifier: string) { @@ -55,6 +36,24 @@ function renderRuleEditor(identifier: string) { } describe('RuleEditor grafana managed rules', () => { + const folder = { + title: 'Folder A', + uid: grafanaRulerRule.grafana_alert.namespace_uid, + id: 1, + type: DashboardSearchItemType.DashDB, + accessControl: { + [AccessControlAction.AlertingRuleUpdate]: true, + }, + }; + + const slashedFolder = { + title: 'Folder with /', + uid: 'abcde', + id: 2, + accessControl: { + [AccessControlAction.AlertingRuleUpdate]: true, + }, + }; beforeEach(() => { jest.clearAllMocks(); contextSrv.isEditor = true; @@ -73,21 +72,6 @@ describe('RuleEditor grafana managed rules', () => { AccessControlAction.AlertingRuleExternalRead, AccessControlAction.AlertingRuleExternalWrite, ]); - }); - - it('can edit grafana managed rule', async () => { - const folder = { - title: 'Folder A', - uid: grafanaRulerRule.grafana_alert.namespace_uid, - id: 1, - type: DashboardSearchItemType.DashDB, - }; - - const slashedFolder = { - title: 'Folder with /', - uid: 'abcde', - id: 2, - }; const dataSources = { default: mockDataSource( @@ -99,18 +83,12 @@ describe('RuleEditor grafana managed rules', () => { { alerting: false } ), }; - - jest.spyOn(backendSrv, 'getFolderByUid').mockResolvedValue({ - ...mockFolder(), - accessControl: { - [AccessControlAction.AlertingRuleUpdate]: true, - }, - }); - setupDataSources(dataSources.default); + setFolderResponse(mockFolder(folder)); + setFolderResponse(mockFolder(slashedFolder)); + }); - // mocks.api.fetchRulerRulesNamespace.mockResolvedValue([]); - mocks.searchFolders.mockResolvedValue([folder, slashedFolder] as DashboardSearchHit[]); + it('can edit grafana managed rule', async () => { const { user } = renderRuleEditor(grafanaRulerRule.grafana_alert.uid); // check that it's filled in @@ -141,7 +119,36 @@ describe('RuleEditor grafana managed rules', () => { // save and check what was sent to backend await user.click(ui.buttons.save.get()); - mocks.searchFolders.mockResolvedValue([] as DashboardSearchHit[]); expect(screen.getByText('New folder')).toBeInTheDocument(); }); + + it('saves evaluation interval correctly', async () => { + const { user } = renderRuleEditor(grafanaRulerRule.grafana_alert.uid); + + await user.click(await screen.findByRole('button', { name: /new evaluation group/i })); + await screen.findByRole('dialog'); + + await user.type(screen.getByLabelText(/evaluation group name/i), 'new group'); + const evalInterval = screen.getByLabelText(/^evaluation interval/i); + + await user.clear(evalInterval); + await user.type(evalInterval, '12m'); + await user.click(screen.getByRole('button', { name: /create/i })); + + // Update the pending period as well, otherwise we'll get a form validation error + // and the rule won't try and save + await user.type(screen.getByLabelText(/pending period/i), '12m'); + + const capture = captureRequests( + (req) => req.method === 'POST' && req.url.includes('/api/ruler/grafana/api/v1/rules/uuid020c61ef') + ); + + await user.click(ui.buttons.save.get()); + + const [request] = await capture; + const postBody = await request.json(); + + expect(postBody.name).toBe('new group'); + expect(postBody.interval).toBe('12m'); + }); }); diff --git a/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx b/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx index 6dcf9d49fdc..aea869c59bc 100644 --- a/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx @@ -211,6 +211,7 @@ export function FolderAndGroup({ className={styles.formInput} error={errors.group?.message} invalid={!!errors.group?.message} + htmlFor="group" >