import {MemberFixture} from 'sentry-fixture/member'; import {MetricRuleFixture} from 'sentry-fixture/metricRule'; import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture'; import {initializeOrg} from 'sentry-test/initializeOrg'; import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; import {metric} from 'sentry/utils/analytics'; import MetricRulesEdit from 'sentry/views/alerts/rules/metric/edit'; import {AlertRuleTriggerType} from 'sentry/views/alerts/rules/metric/types'; jest.mock('sentry/utils/analytics', () => ({ metric: { startTransaction: jest.fn(() => ({ setTag: jest.fn(), setData: jest.fn(), })), mark: jest.fn(), measure: jest.fn(), endTransaction: jest.fn(), }, })); describe('MetricRulesEdit', function () { beforeEach(function () { MockApiClient.addMockResponse({ url: '/organizations/org-slug/users/', body: [], }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/tags/', body: [], }); MockApiClient.addMockResponse({ url: '/projects/org-slug/project-slug/environments/', body: [], }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/events-stats/', body: null, }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/events-meta/', body: {count: 5}, }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/alert-rules/available-actions/', body: [ { allowedTargetTypes: ['user', 'team'], integrationName: null, type: 'email', integrationId: null, }, ], }); MockApiClient.addMockResponse({ url: '/organizations/org-slug/members/', body: [MemberFixture()], }); }); afterEach(() => { MockApiClient.clearMockResponses(); jest.clearAllMocks(); }); it('renders and edits trigger', async function () { const {organization, project} = initializeOrg(); const rule = MetricRuleFixture(); const onChangeTitleMock = jest.fn(); const req = MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`, body: rule, }); const editRule = MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`, method: 'PUT', body: rule, }); render( ); // has existing trigger expect(screen.getByTestId('critical-threshold')).toHaveValue('70'); expect(screen.getByTestId('resolve-threshold')).toHaveValue('36'); expect(req).toHaveBeenCalled(); // Check correct rule name is called expect(onChangeTitleMock).toHaveBeenCalledWith(rule.name); await userEvent.clear(screen.getByTestId('resolve-threshold')); await userEvent.type(screen.getByTestId('resolve-threshold'), '7'); // Create a new action await userEvent.click(screen.getByLabelText('Add Action')); // Save Trigger await userEvent.click(screen.getByLabelText('Save Rule')); expect(metric.startTransaction).toHaveBeenCalledWith({name: 'saveAlertRule'}); expect(editRule).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ data: expect.objectContaining({ dataset: 'events', id: '4', name: 'My Incident Rule', projects: ['project-slug'], query: '', status: 0, timeWindow: 60, thresholdType: 0, resolveThreshold: 7, triggers: [ expect.objectContaining({ actions: [ expect.objectContaining({ integrationId: null, targetIdentifier: '', targetType: 'user', type: 'email', options: null, }), ], alertRuleId: '4', alertThreshold: 70, id: '1', }), ], }), method: 'PUT', }) ); // New Trigger should be in list // Has correct values expect(screen.getByTestId('critical-threshold')).toHaveValue('70'); expect(screen.getByTestId('resolve-threshold')).toHaveValue('7'); }); it('removes warning trigger', async function () { const {organization, project} = initializeOrg(); const rule = MetricRuleFixture(); rule.triggers.push({ label: AlertRuleTriggerType.WARNING, alertThreshold: 13, actions: [], }); rule.resolveThreshold = 12; MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`, body: rule, }); const editRule = MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/alert-rules/${rule.id}/`, method: 'PUT', body: rule, }); render( {}} project={project} /> ); // has existing trigger expect(screen.getByTestId('critical-threshold')).toHaveValue('70'); expect(screen.getByTestId('warning-threshold')).toHaveValue('13'); expect(screen.getByTestId('resolve-threshold')).toHaveValue('12'); // Clear warning Trigger await userEvent.clear(screen.getByTestId('warning-threshold')); await userEvent.click(screen.getByLabelText('Save Rule')); expect(editRule).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ data: expect.objectContaining({ dataset: 'events', id: '4', name: 'My Incident Rule', projects: ['project-slug'], query: '', status: 0, timeWindow: 60, resolveThreshold: 12, thresholdType: 0, triggers: [ expect.objectContaining({ actions: [], alertRuleId: '4', alertThreshold: 70, id: '1', }), ], }), method: 'PUT', }) ); }); it('renders 404', function () { const {organization, project} = initializeOrg(); MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/alert-rules/1234/`, statusCode: 404, body: {}, }); render( {}} params={{ projectId: project.slug, ruleId: '1234', }} organization={organization} project={project} /> ); expect(screen.getByText('This alert rule could not be found.')).toBeInTheDocument(); }); });