Alerting: Add tests for combination of switch modes in the alert rule form (#98052)

* Add tests for combination of switch

* refactor test

* use alerting option for default datasource in RuleEditor Grafana rules test

* add test for grafana recording rules

* use enum for grafana steps in tests

* dont make each test dependent on previous localstorage

* add test for local storage
This commit is contained in:
Sonia Aguilar 2025-01-08 14:48:08 +01:00 committed by GitHub
parent 299e16b61a
commit 9c7a355afd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 1424 additions and 84 deletions

View File

@ -0,0 +1,119 @@
import { UserEvent } from '@testing-library/user-event';
import * as React from 'react';
import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
import { screen } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
import { FeatureToggles } from '@grafana/data';
import { contextSrv } from 'app/core/services/context_srv';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { PROMETHEUS_DATASOURCE_UID } from 'app/features/alerting/unified/mocks/server/constants';
import { AccessControlAction } from 'app/types';
import { grantUserPermissions, mockDataSource } from './mocks';
import { grafanaRulerGroup } from './mocks/grafanaRulerApi';
import { captureRequests, serializeRequests } from './mocks/server/events';
import { FOLDER_TITLE_HAPPY_PATH } from './mocks/server/handlers/search';
import { testWithFeatureToggles } from './test/test-utils';
import { setupDataSources } from './testSetup/datasources';
jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) => <div>{actions}</div>,
}));
jest.setTimeout(60 * 1000);
setupMswServer();
const selectFolderAndGroup = async (user: UserEvent) => {
await user.click(await screen.findByRole('button', { name: /select folder/i }));
await user.click(await screen.findByLabelText(FOLDER_TITLE_HAPPY_PATH));
const groupInput = await ui.inputs.group.find();
await user.click(await byRole('combobox').find(groupInput));
await clickSelectOption(groupInput, grafanaRulerGroup.name);
};
const dataSources = {
default: mockDataSource(
{
type: 'prometheus',
name: 'Prom',
uid: PROMETHEUS_DATASOURCE_UID,
isDefault: true,
},
{ alerting: true, module: 'core:plugin/prometheus' }
),
};
describe('RuleEditor grafana recording rules', () => {
beforeEach(() => {
jest.clearAllMocks();
setupDataSources(dataSources.default);
contextSrv.isEditor = true;
contextSrv.hasEditPermissionInFolders = true;
grantUserPermissions([
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
AccessControlAction.AlertingRuleDelete,
AccessControlAction.AlertingRuleCreate,
AccessControlAction.DataSourcesRead,
AccessControlAction.DataSourcesWrite,
AccessControlAction.DataSourcesCreate,
AccessControlAction.FoldersWrite,
AccessControlAction.FoldersRead,
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
});
const testCreateGrafanaRR = (featureToggles: Array<keyof FeatureToggles>, testName: string) => {
testWithFeatureToggles(featureToggles);
it(testName, async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor(undefined, 'grafana-recording');
await user.type(await ui.inputs.name.find(), 'my great new rule');
await user.type(await ui.inputs.metric.find(), 'metricName');
await selectFolderAndGroup(user);
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
};
const testCreateGrafanaRRWithInvalidMetricName = (featureToggles: Array<keyof FeatureToggles>, testName: string) => {
testWithFeatureToggles(featureToggles);
it(testName, async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor(undefined, 'grafana-recording');
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup(user);
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
expect(requests).toHaveLength(0);
});
};
testCreateGrafanaRR([], 'can create new grafana recording rule with simplified steps feature toggles disabled');
testCreateGrafanaRR(
['alertingQueryAndExpressionsStepMode', 'alertingNotificationsStepMode'],
'can create new grafana recording rule with simplified steps enabled'
);
testCreateGrafanaRRWithInvalidMetricName(
[],
'cannot create new grafana recording rule with invalid metric name with simplified steps feature toggles disabled'
);
testCreateGrafanaRRWithInvalidMetricName(
['alertingQueryAndExpressionsStepMode', 'alertingNotificationsStepMode'],
'cannot create new grafana recording rule with invalid metric name with simplified steps enabled'
);
});

View File

@ -11,6 +11,7 @@ import { AccessControlAction } from 'app/types';
import { grantUserPermissions, mockDataSource } from './mocks';
import { grafanaRulerGroup } from './mocks/grafanaRulerApi';
import { captureRequests, serializeRequests } from './mocks/server/events';
import { setupDataSources } from './testSetup/datasources';
jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
@ -42,6 +43,7 @@ describe('RuleEditor grafana managed rules', () => {
});
it('can create new grafana managed alert', async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const dataSources = {
default: mockDataSource(
{
@ -50,7 +52,7 @@ describe('RuleEditor grafana managed rules', () => {
uid: PROMETHEUS_DATASOURCE_UID,
isDefault: true,
},
{ alerting: false }
{ alerting: true, module: 'core:plugin/prometheus' }
),
};
@ -69,5 +71,8 @@ describe('RuleEditor grafana managed rules', () => {
await user.click(ui.buttons.saveAndExit.get());
expect(await screen.findByRole('status')).toHaveTextContent('Rule added successfully');
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
});

View File

@ -67,7 +67,7 @@ describe('RuleEditor recording rules', () => {
});
it('can create a new cloud recording rule', async () => {
renderRuleEditor(undefined, true);
renderRuleEditor(undefined, 'recording');
await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await userEvent.type(await ui.inputs.name.find(), 'my great new recording rule');

View File

@ -0,0 +1,259 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RuleEditor grafana recording rules can create new grafana recording rule with simplified steps enabled 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"grafana_alert": {
"condition": "B",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
],
"is_paused": false,
"record": {
"from": "B",
"metric": "metricName",
},
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;
exports[`RuleEditor grafana recording rules can create new grafana recording rule with simplified steps feature toggles disabled 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"grafana_alert": {
"condition": "B",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
],
"is_paused": false,
"record": {
"from": "B",
"metric": "metricName",
},
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;

View File

@ -0,0 +1,168 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RuleEditor grafana managed rules can create new grafana managed alert 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {
"description": "some description",
},
"for": "1m",
"grafana_alert": {
"condition": "C",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
"no_data_state": "NoData",
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;

View File

@ -1,27 +1,25 @@
import { UserEvent } from '@testing-library/user-event';
import { ReactNode } from 'react';
import { Route, Routes } from 'react-router-dom-v5-compat';
import { ui } from 'test/helpers/alertingRuleEditor';
import { GrafanaRuleFormStep, renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
import { render, screen, userEvent } from 'test/test-utils';
import { screen, waitFor } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
import { config } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import RuleEditor from 'app/features/alerting/unified/RuleEditor';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { grantUserPermissions, mockDataSource } from 'app/features/alerting/unified/mocks';
import { setAlertmanagerChoices } from 'app/features/alerting/unified/mocks/server/configure';
import { PROMETHEUS_DATASOURCE_UID } from 'app/features/alerting/unified/mocks/server/constants';
import { captureRequests, serializeRequests } from 'app/features/alerting/unified/mocks/server/events';
import { FOLDER_TITLE_HAPPY_PATH } from 'app/features/alerting/unified/mocks/server/handlers/search';
import { AlertmanagerProvider } from 'app/features/alerting/unified/state/AlertmanagerContext';
import { testWithFeatureToggles } from 'app/features/alerting/unified/test/test-utils';
import { DataSourceType, GRAFANA_DATASOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources';
import { DataSourceType } from 'app/features/alerting/unified/utils/datasource';
import { MANUAL_ROUTING_KEY, SIMPLIFIED_QUERY_EDITOR_KEY } from 'app/features/alerting/unified/utils/rule-form';
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import { grafanaRulerGroup } from '../../../../mocks/grafanaRulerApi';
import { setupDataSources } from '../../../../testSetup/datasources';
jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
AppChromeUpdate: ({ actions }: { actions: ReactNode }) => <div>{actions}</div>,
@ -29,8 +27,6 @@ jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
jest.setTimeout(60 * 1000);
setupMswServer();
const dataSources = {
default: mockDataSource(
{
@ -39,7 +35,7 @@ const dataSources = {
uid: PROMETHEUS_DATASOURCE_UID,
isDefault: true,
},
{ alerting: false }
{ alerting: true, module: 'core:plugin/prometheus' }
),
am: mockDataSource({
name: 'Alertmanager',
@ -47,10 +43,7 @@ const dataSources = {
}),
};
setupDataSources(dataSources.default, dataSources.am);
const selectFolderAndGroup = async () => {
const user = userEvent.setup();
const selectFolderAndGroup = async (user: UserEvent) => {
await user.click(await screen.findByRole('button', { name: /select folder/i }));
await user.click(await screen.findByLabelText(FOLDER_TITLE_HAPPY_PATH));
const groupInput = await ui.inputs.group.find();
@ -58,12 +51,21 @@ const selectFolderAndGroup = async () => {
await clickSelectOption(groupInput, grafanaRulerGroup.name);
};
const selectContactPoint = async (user: UserEvent, contactPointName: string) => {
const contactPointInput = await ui.inputs.simplifiedRouting.contactPoint.find();
await user.click(byRole('combobox').get(contactPointInput));
await clickSelectOption(contactPointInput, contactPointName);
};
setupMswServer();
describe('Can create a new grafana managed alert using simplified routing', () => {
testWithFeatureToggles(['alertingSimplifiedRouting']);
beforeEach(() => {
jest.clearAllMocks();
window.localStorage.clear();
setupDataSources(dataSources.default, dataSources.am);
contextSrv.isEditor = true;
contextSrv.hasEditPermissionInFolders = true;
config.featureToggles.alertingSimplifiedRouting = true;
grantUserPermissions([
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
@ -84,11 +86,11 @@ describe('Can create a new grafana managed alert using simplified routing', () =
it('cannot create new grafana managed alert when using simplified routing and not selecting a contact point', async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderSimplifiedRuleEditor();
const { user } = renderRuleEditor();
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup();
await selectFolderAndGroup(user);
//select contact point routing
await user.click(ui.inputs.simplifiedRouting.contactPointRouting.get());
@ -104,26 +106,25 @@ describe('Can create a new grafana managed alert using simplified routing', () =
it('simplified routing is not available when Grafana AM is not enabled', async () => {
setAlertmanagerChoices(AlertmanagerChoice.External, 1);
renderSimplifiedRuleEditor();
renderRuleEditor();
expect(ui.inputs.simplifiedRouting.contactPointRouting.query()).not.toBeInTheDocument();
await waitFor(() => expect(ui.inputs.simplifiedRouting.contactPointRouting.query()).not.toBeInTheDocument());
});
it('can create new grafana managed alert when using simplified routing and selecting a contact point', async () => {
const contactPointName = 'lotsa-emails';
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderSimplifiedRuleEditor();
const { user } = renderRuleEditor();
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup();
await selectFolderAndGroup(user);
//select contact point routing
await user.click(ui.inputs.simplifiedRouting.contactPointRouting.get());
const contactPointInput = await ui.inputs.simplifiedRouting.contactPoint.find();
await user.click(byRole('combobox').get(contactPointInput));
await clickSelectOption(contactPointInput, contactPointName);
await selectContactPoint(user, contactPointName);
// save and check what was sent to backend
await user.click(ui.buttons.saveAndExit.get());
@ -137,27 +138,108 @@ describe('Can create a new grafana managed alert using simplified routing', () =
testWithFeatureToggles(['alertingApiServer']);
it('allows selecting a contact point when using alerting API server', async () => {
const { user } = renderSimplifiedRuleEditor();
const { user } = renderRuleEditor();
await user.click(await ui.inputs.simplifiedRouting.contactPointRouting.find());
const contactPointInput = await ui.inputs.simplifiedRouting.contactPoint.find();
await user.click(byRole('combobox').get(contactPointInput));
await clickSelectOption(contactPointInput, 'lotsa-emails');
await selectContactPoint(user, 'Email');
expect(await screen.findByText('Email')).toBeInTheDocument();
});
});
});
describe('switch modes enabled', () => {
testWithFeatureToggles(['alertingQueryAndExpressionsStepMode', 'alertingNotificationsStepMode']);
function renderSimplifiedRuleEditor() {
return render(
<AlertmanagerProvider alertmanagerSourceName={GRAFANA_DATASOURCE_NAME} accessType="notification">
<Routes>
<Route path={'/alerting/new/:type'} element={<RuleEditor />} />
<Route path={'/alerting/:id/edit'} element={<RuleEditor />} />
</Routes>
</AlertmanagerProvider>,
{ historyOptions: { initialEntries: ['/alerting/new/alerting'] } }
);
}
it('can create the new grafana-managed rule with default modes', async () => {
const contactPointName = 'lotsa-emails';
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor();
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup(user);
await selectContactPoint(user, contactPointName);
// save and check what was sent to backend
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
it('can create the new grafana-managed rule with advanced modes', async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor();
await user.click(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Query).get()); // switch to query step advanced mode
await user.click(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Notification).get()); // switch to notifications step advanced mode
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup(user);
// save and check what was sent to backend
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
it('can create the new grafana-managed rule with only notifications step advanced mode', async () => {
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor();
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup(user);
await user.click(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Notification).get()); // switch notifications step to advanced mode
// save and check what was sent to backend
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
it('can create the new grafana-managed rule with only query step advanced mode', async () => {
const contactPointName = 'lotsa-emails';
const capture = captureRequests((r) => r.method === 'POST' && r.url.includes('/api/ruler/'));
const { user } = renderRuleEditor();
await user.type(await ui.inputs.name.find(), 'my great new rule');
await selectFolderAndGroup(user);
await selectContactPoint(user, contactPointName);
await user.click(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Query).get()); // switch query step to advanced mode
// save and check what was sent to backend
await user.click(ui.buttons.saveAndExit.get());
const requests = await capture;
const serializedRequests = await serializeRequests(requests);
expect(serializedRequests).toMatchSnapshot();
});
it('switch modes are intiallized depending on the local storage - 1', async () => {
localStorage.setItem(SIMPLIFIED_QUERY_EDITOR_KEY, 'false');
localStorage.setItem(MANUAL_ROUTING_KEY, 'true');
const { user } = renderRuleEditor();
await selectFolderAndGroup(user);
expect(ui.inputs.switchModeAdvanced(GrafanaRuleFormStep.Query).get()).toBeInTheDocument();
expect(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Notification).get()).toBeInTheDocument();
});
it('switch modes are intiallized depending on the local storage - 2', async () => {
localStorage.setItem(SIMPLIFIED_QUERY_EDITOR_KEY, 'true');
localStorage.setItem(MANUAL_ROUTING_KEY, 'false');
const { user } = renderRuleEditor();
await selectFolderAndGroup(user);
expect(ui.inputs.switchModeBasic(GrafanaRuleFormStep.Query).get()).toBeInTheDocument();
expect(ui.inputs.switchModeAdvanced(GrafanaRuleFormStep.Notification).get()).toBeInTheDocument();
});
});
});

View File

@ -51,43 +51,20 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
"annotations": {},
"for": "1m",
"grafana_alert": {
"condition": "B",
"condition": "C",
"data": [
{
"datasourceUid": "__expr__",
"datasourceUid": "prometheus",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"A",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"instant": true,
"refId": "A",
"type": "reduce",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
@ -95,9 +72,7 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
"conditions": [
{
"evaluator": {
"params": [
0,
],
"params": [],
"type": "gt",
},
"operator": {
@ -120,12 +95,50 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "threshold",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
@ -154,3 +167,693 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
},
]
`;
exports[`Can create a new grafana managed alert using simplified routing switch modes enabled can create the new grafana-managed rule with advanced modes 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"for": "1m",
"grafana_alert": {
"condition": "C",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
"metadata": {
"editor_settings": {
"simplified_notifications_section": false,
"simplified_query_and_expressions_section": false,
},
},
"no_data_state": "NoData",
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;
exports[`Can create a new grafana managed alert using simplified routing switch modes enabled can create the new grafana-managed rule with default modes 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"for": "1m",
"grafana_alert": {
"condition": "C",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
"metadata": {
"editor_settings": {
"simplified_notifications_section": true,
"simplified_query_and_expressions_section": true,
},
},
"no_data_state": "NoData",
"notification_settings": {
"receiver": "lotsa-emails",
},
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;
exports[`Can create a new grafana managed alert using simplified routing switch modes enabled can create the new grafana-managed rule with only notifications step advanced mode 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"for": "1m",
"grafana_alert": {
"condition": "C",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
"metadata": {
"editor_settings": {
"simplified_notifications_section": false,
"simplified_query_and_expressions_section": true,
},
},
"no_data_state": "NoData",
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;
exports[`Can create a new grafana managed alert using simplified routing switch modes enabled can create the new grafana-managed rule with only query step advanced mode 1`] = `
[
{
"body": {
"interval": "1m",
"name": "grafana-group-1",
"rules": [
{
"annotations": {
"summary": "Test alert",
},
"for": "5m",
"grafana_alert": {
"condition": "A",
"data": [
{
"datasourceUid": "datasource-uid",
"model": {
"datasource": {
"type": "prometheus",
"uid": "datasource-uid",
},
"expression": "vector(1)",
"queryType": "alerting",
"refId": "A",
},
"queryType": "alerting",
"refId": "A",
"relativeTimeRange": {
"from": 1000,
"to": 2000,
},
},
],
"exec_err_state": "Error",
"is_paused": false,
"namespace_uid": "uuid020c61ef",
"no_data_state": "NoData",
"rule_group": "grafana-group-1",
"title": "Grafana-rule",
"uid": "4d7125fee983",
},
"labels": {
"region": "nasa",
"severity": "critical",
},
},
{
"annotations": {},
"for": "1m",
"grafana_alert": {
"condition": "C",
"data": [
{
"datasourceUid": "prometheus",
"model": {
"instant": true,
"refId": "A",
},
"queryType": "",
"refId": "A",
"relativeTimeRange": {
"from": 600,
"to": 0,
},
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"B",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "A",
"reducer": "last",
"refId": "B",
"type": "reduce",
},
"queryType": "",
"refId": "B",
},
{
"datasourceUid": "__expr__",
"model": {
"conditions": [
{
"evaluator": {
"params": [
0,
],
"type": "gt",
},
"operator": {
"type": "and",
},
"query": {
"params": [
"C",
],
},
"reducer": {
"params": [],
"type": "last",
},
"type": "query",
},
],
"datasource": {
"type": "__expr__",
"uid": "__expr__",
},
"expression": "B",
"refId": "C",
"type": "threshold",
},
"queryType": "",
"refId": "C",
},
],
"exec_err_state": "Error",
"is_paused": false,
"metadata": {
"editor_settings": {
"simplified_notifications_section": true,
"simplified_query_and_expressions_section": false,
},
},
"no_data_state": "NoData",
"notification_settings": {
"receiver": "lotsa-emails",
},
"title": "my great new rule",
},
"labels": {},
},
],
},
"headers": [
[
"content-type",
"application/json",
],
[
"accept",
"application/json, text/plain, */*",
],
],
"method": "POST",
"url": "http://localhost/api/ruler/grafana/api/v1/rules/uuid020c61ef?subtype=cortex",
},
]
`;

View File

@ -1,15 +1,20 @@
import { Routes, Route } from 'react-router-dom-v5-compat';
import { Route, Routes } from 'react-router-dom-v5-compat';
import { render } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { selectors } from '@grafana/e2e-selectors';
import { AppNotificationList } from 'app/core/components/AppNotifications/AppNotificationList';
import RuleEditor from 'app/features/alerting/unified/RuleEditor';
export enum GrafanaRuleFormStep {
Query = 2,
Notification = 5,
}
export const ui = {
loadingIndicator: byText('Loading rule...'),
inputs: {
name: byRole('textbox', { name: 'name' }),
metric: byRole('textbox', { name: 'metric' }),
alertType: byTestId('alert-type-picker'),
dataSource: byTestId(selectors.components.DataSourcePicker.inputV2),
folder: byTestId('folder-picker'),
@ -26,6 +31,8 @@ export const ui = {
contactPoint: byTestId('contact-point-picker'),
routingOptions: byText(/muting, grouping and timings \(optional\)/i),
},
switchModeBasic: (stepNo: GrafanaRuleFormStep) => byTestId(`advanced-switch-${stepNo}-basic`),
switchModeAdvanced: (stepNo: GrafanaRuleFormStep) => byTestId(`advanced-switch-${stepNo}-advanced`),
},
buttons: {
saveAndExit: byRole('button', { name: 'Save rule and exit' }),
@ -34,8 +41,7 @@ export const ui = {
addLabel: byRole('button', { name: /Add label/ }),
},
};
export function renderRuleEditor(identifier?: string, recording = false) {
export function renderRuleEditor(identifier?: string, recording?: 'recording' | 'grafana-recording') {
return render(
<>
<AppNotificationList />
@ -46,9 +52,7 @@ export function renderRuleEditor(identifier?: string, recording = false) {
</>,
{
historyOptions: {
initialEntries: [
identifier ? `/alerting/${identifier}/edit` : `/alerting/new/${recording ? 'recording' : 'alerting'}`,
],
initialEntries: [identifier ? `/alerting/${identifier}/edit` : `/alerting/new/${recording ?? 'alerting'}`],
},
}
);