diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index 9bca2d6be6b..b32a8c0e740 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -1,11 +1,12 @@ import { SerializedError } from '@reduxjs/toolkit'; import { prettyDOM, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { setupServer } from 'msw/node'; import React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; import { byRole, byTestId, byText } from 'testing-library-selector'; -import { PluginExtensionTypes } from '@grafana/data'; +import { PluginExtensionTypes, PluginMeta } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { DataSourceSrv, @@ -16,9 +17,17 @@ import { } from '@grafana/runtime'; import { backendSrv } from 'app/core/services/backend_srv'; import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons'; -import alertingServer from 'app/features/alerting/unified/mock-server'; +import { + mockAlertRuleApi, + mockApi, + mockFolderApi, + mockSearchApi, + mockUserApi, +} from 'app/features/alerting/unified/mockApi'; +import { mockAlertmanagerChoiceResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi'; import * as actions from 'app/features/alerting/unified/state/actions'; -import { AccessControlAction } from 'app/types'; +import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types'; +import { AccessControlAction, FolderDTO } from 'app/types'; import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto'; import * as analytics from './Analytics'; @@ -39,6 +48,8 @@ import { getPotentiallyPausedRulerRules, somePromRules, someRulerRules, + mockFolder, + mockUser, } from './mocks'; import * as config from './utils/config'; import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; @@ -149,13 +160,40 @@ const ui = { }, }; +const server = setupServer(); + +const configureMockServer = () => { + mockSearchApi(server).search([]); + mockUserApi(server).user(mockUser()); + mockFolderApi(server).folder( + 'NAMESPACE_UID', + mockFolder({ + accessControl: { [AccessControlAction.AlertingRuleUpdate]: true }, + }) + ); + mockApi(server).plugins.getPluginSettings( + // We aren't particularly concerned with the plugin response in these tests + // at the time of writing, so we can go unknown -> PluginMeta to get the bare minimum + { id: 'grafana-incident-app' } as unknown as PluginMeta + ); + mockAlertmanagerChoiceResponse(server, { + alertmanagersChoice: AlertmanagerChoice.All, + numExternalAlertmanagers: 1, + }); + mockAlertRuleApi(server).updateRule('grafana', { + message: 'rule group updated successfully', + updated: ['foo', 'bar', 'baz'], + }); +}; + beforeAll(() => { setBackendSrv(backendSrv); }); describe('RuleList', () => { beforeEach(() => { - alertingServer.listen({ onUnhandledRequest: 'error' }); + server.listen({ onUnhandledRequest: 'error' }); + configureMockServer(); grantUserPermissions([ AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleUpdate, @@ -179,13 +217,13 @@ describe('RuleList', () => { }); afterEach(() => { - alertingServer.resetHandlers(); + server.resetHandlers(); jest.resetAllMocks(); setDataSourceSrv(undefined as unknown as DataSourceSrv); }); afterAll(() => { - alertingServer.close(); + server.close(); }); it('load & show rule groups from multiple cloud data sources', async () => { diff --git a/public/app/features/alerting/unified/mock-server.ts b/public/app/features/alerting/unified/mock-server.ts deleted file mode 100644 index ea7e3fb650f..00000000000 --- a/public/app/features/alerting/unified/mock-server.ts +++ /dev/null @@ -1,44 +0,0 @@ -import 'whatwg-fetch'; -import { HttpResponse, http } from 'msw'; -import { setupServer } from 'msw/node'; - -import { AccessControlAction } from 'app/types'; - -const alertingServer = setupServer( - // TODO: Scaffold out test behaviour/configuration for search endpoint - http.get('/api/search', () => { - return HttpResponse.json([]); - }), - // TODO: Scaffold out test behaviour/configuration for user endpoint - http.get('/api/user', () => { - return HttpResponse.json({}); - }), - // TODO: Scaffold out test behaviour/configuration for alert manager endpoint - http.get('/api/v1/ngalert', () => { - return HttpResponse.json({ alertmanagersChoice: 'all', numExternalAlertmanagers: 1 }); - }), - // TODO: Scaffold out test behaviour/configuration for plugins / incident endpoint - http.get('/api/plugins/grafana-incident-app/settings', () => { - return new HttpResponse(null, { status: 200 }); - }), - - http.get('/api/folders/:folderUid', () => { - return HttpResponse.json({ - accessControl: { [AccessControlAction.AlertingRuleUpdate]: true }, - }); - }), - http.get('/api/prometheus/grafana/api/v1/rules', () => { - return HttpResponse.json([]); - }), - http.get('/api/ruler/grafana/api/v1/rules', () => { - return HttpResponse.json([]); - }), - http.post('/api/ruler/grafana/api/v1/rules/:namespaceUID/', async ({ request }) => { - return HttpResponse.json({ - message: 'rule group updated successfully', - updated: ['foo', 'bar', 'baz'], - }); - }) -); - -export default alertingServer; diff --git a/public/app/features/alerting/unified/mockApi.ts b/public/app/features/alerting/unified/mockApi.ts index 9c3ad1e8539..3e629fb351b 100644 --- a/public/app/features/alerting/unified/mockApi.ts +++ b/public/app/features/alerting/unified/mockApi.ts @@ -5,6 +5,7 @@ import { setupServer, SetupServer } from 'msw/node'; import { DataSourceInstanceSettings, PluginMeta } from '@grafana/data'; import { setBackendSrv } from '@grafana/runtime'; +import { AlertRuleUpdated } from 'app/features/alerting/unified/api/alertRuleApi'; import { PromBuildInfoResponse, PromRulesResponse, @@ -22,7 +23,7 @@ import { MatcherOperator, Route, } from '../../../plugins/datasource/alertmanager/types'; -import { DashboardDTO, FolderDTO, NotifierDTO } from '../../../types'; +import { DashboardDTO, FolderDTO, NotifierDTO, UserDTO } from '../../../types'; import { DashboardSearchItem } from '../../search/types'; import { CreateIntegrationDTO, NewOnCallIntegrationDTO, OnCallIntegrationDTO } from './api/onCallApi'; @@ -278,6 +279,9 @@ export function mockAlertRuleApi(server: SetupServer) { rulerRules: (dsName: string, response: RulerRulesConfigDTO) => { server.use(http.get(`/api/ruler/${dsName}/api/v1/rules`, () => HttpResponse.json(response))); }, + updateRule: (dsName: string, response: AlertRuleUpdated) => { + server.use(http.post(`/api/ruler/${dsName}/api/v1/rules/:namespaceUid`, () => HttpResponse.json(response))); + }, rulerRuleGroup: (dsName: string, namespace: string, group: string, response: RulerRuleGroupDTO) => { server.use( http.get(`/api/ruler/${dsName}/api/v1/rules/${namespace}/${group}`, () => HttpResponse.json(response)) @@ -398,6 +402,14 @@ export function mockSearchApi(server: SetupServer) { }; } +export function mockUserApi(server: SetupServer) { + return { + user: (user: UserDTO) => { + server.use(http.get(`/api/user`, () => HttpResponse.json(user))); + }, + }; +} + export function mockDashboardApi(server: SetupServer) { return { search: (results: DashboardSearchItem[]) => { diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index 458d97df016..9b3a72cf103 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -31,7 +31,15 @@ import { SilenceState, } from 'app/plugins/datasource/alertmanager/types'; import { configureStore } from 'app/store/configureStore'; -import { AccessControlAction, DashboardDTO, FolderDTO, NotifiersState, ReceiversState, StoreState } from 'app/types'; +import { + AccessControlAction, + DashboardDTO, + FolderDTO, + NotifiersState, + ReceiversState, + StoreState, + UserDTO, +} from 'app/types'; import { Alert, AlertingRule, @@ -611,6 +619,18 @@ export const mockFolder = (partial?: Partial): FolderDTO => { }; }; +export const mockUser = (partial?: Partial): UserDTO => { + return { + id: 1, + login: 'admin', + email: 'admin@grafana.com', + name: 'Admin', + isGrafanaAdmin: true, + isDisabled: false, + ...partial, + }; +}; + export const grantUserPermissions = (permissions: AccessControlAction[]) => { jest .spyOn(contextSrv, 'hasPermission')