|
@@ -1,7 +1,13 @@
|
|
|
-import {mountWithTheme} from 'sentry-test/enzyme';
|
|
|
+import selectEvent from 'react-select-event';
|
|
|
+
|
|
|
import {initializeOrg} from 'sentry-test/initializeOrg';
|
|
|
import {mockRouterPush} from 'sentry-test/mockRouterPush';
|
|
|
-import {selectByValue} from 'sentry-test/select-new';
|
|
|
+import {
|
|
|
+ cleanup,
|
|
|
+ fireEvent,
|
|
|
+ mountWithTheme,
|
|
|
+ waitFor,
|
|
|
+} from 'sentry-test/reactTestingLibrary';
|
|
|
|
|
|
import * as memberActionCreators from 'app/actionCreators/members';
|
|
|
import ProjectsStore from 'app/stores/projectsStore';
|
|
@@ -83,7 +89,7 @@ describe('ProjectAlertsCreate', function () {
|
|
|
},
|
|
|
];
|
|
|
|
|
|
- beforeEach(async function () {
|
|
|
+ beforeEach(function () {
|
|
|
memberActionCreators.fetchOrgMembers = jest.fn();
|
|
|
MockApiClient.addMockResponse({
|
|
|
url: '/projects/org-slug/project-slug/rules/configuration/',
|
|
@@ -105,6 +111,7 @@ describe('ProjectAlertsCreate', function () {
|
|
|
});
|
|
|
|
|
|
afterEach(function () {
|
|
|
+ cleanup();
|
|
|
MockApiClient.clearMockResponses();
|
|
|
});
|
|
|
|
|
@@ -125,7 +132,7 @@ describe('ProjectAlertsCreate', function () {
|
|
|
/>
|
|
|
</AlertBuilderProjectProvider>
|
|
|
</AlertsContainer>,
|
|
|
- routerContext
|
|
|
+ {context: routerContext}
|
|
|
);
|
|
|
mockRouterPush(wrapper, router);
|
|
|
|
|
@@ -139,19 +146,28 @@ describe('ProjectAlertsCreate', function () {
|
|
|
|
|
|
describe('Issue Alert', function () {
|
|
|
it('loads default values', async function () {
|
|
|
- const {wrapper} = createWrapper();
|
|
|
- await tick();
|
|
|
- wrapper.update();
|
|
|
- expect(memberActionCreators.fetchOrgMembers).toHaveBeenCalled();
|
|
|
- expect(wrapper.find('SelectControl[name="environment"]').prop('value')).toBe(
|
|
|
- '__all_environments__'
|
|
|
- );
|
|
|
- expect(wrapper.find('SelectControl[name="actionMatch"]').prop('value')).toBe('all');
|
|
|
- expect(wrapper.find('SelectControl[name="frequency"]').prop('value')).toBe('30');
|
|
|
+ const {
|
|
|
+ wrapper: {getByDisplayValue},
|
|
|
+ } = createWrapper();
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(getByDisplayValue('__all_environments__')).toBeInTheDocument();
|
|
|
+ });
|
|
|
+ expect(getByDisplayValue('all')).toBeInTheDocument();
|
|
|
+ expect(getByDisplayValue('30')).toBeInTheDocument();
|
|
|
});
|
|
|
|
|
|
it('updates values and saves', async function () {
|
|
|
- const {wrapper, router} = createWrapper({
|
|
|
+ const {
|
|
|
+ wrapper: {
|
|
|
+ getAllByLabelText,
|
|
|
+ getAllByText,
|
|
|
+ getByLabelText,
|
|
|
+ getByPlaceholderText,
|
|
|
+ getByText,
|
|
|
+ },
|
|
|
+ router,
|
|
|
+ } = createWrapper({
|
|
|
organization: {
|
|
|
features: ['alert-filters'],
|
|
|
},
|
|
@@ -161,140 +177,110 @@ describe('ProjectAlertsCreate', function () {
|
|
|
method: 'POST',
|
|
|
body: TestStubs.ProjectAlertRule(),
|
|
|
});
|
|
|
- await tick();
|
|
|
- wrapper.update();
|
|
|
|
|
|
- expect(memberActionCreators.fetchOrgMembers).toHaveBeenCalled();
|
|
|
- // Change target environment
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(memberActionCreators.fetchOrgMembers).toHaveBeenCalled();
|
|
|
+ });
|
|
|
|
|
|
- selectByValue(wrapper, 'production', {control: true, name: 'environment'});
|
|
|
+ // Change target environment
|
|
|
+ await selectEvent.select(getByText('All Environments'), ['production']);
|
|
|
// Change actionMatch and filterMatch dropdown
|
|
|
- selectByValue(wrapper, 'any', {name: 'actionMatch'});
|
|
|
- selectByValue(wrapper, 'any', {name: 'filterMatch'});
|
|
|
+ await selectEvent.select(getAllByText('all')[0], ['any']);
|
|
|
+ await selectEvent.select(getAllByText('all')[0], ['any']);
|
|
|
|
|
|
// Change name of alert rule
|
|
|
- wrapper
|
|
|
- .find('input[name="name"]')
|
|
|
- .simulate('change', {target: {value: 'My Rule Name'}});
|
|
|
- // Add a condition and remove it
|
|
|
- selectByValue(
|
|
|
- wrapper,
|
|
|
- 'sentry.rules.conditions.first_seen_event.FirstSeenEventCondition',
|
|
|
- {selector: 'Select[placeholder="Add optional condition..."]'}
|
|
|
- );
|
|
|
+ fireEvent.change(getByPlaceholderText('My Rule Name'), {
|
|
|
+ target: {value: 'My Rule Name'},
|
|
|
+ });
|
|
|
|
|
|
- wrapper
|
|
|
- .find('RuleNode')
|
|
|
- .at(0)
|
|
|
- .find('button[aria-label="Delete Node"]')
|
|
|
- .simulate('click');
|
|
|
+ // Add a condition and remove it
|
|
|
+ await selectEvent.select(getByText('Add optional condition...'), [
|
|
|
+ 'A new issue is created',
|
|
|
+ ]);
|
|
|
+ fireEvent.click(getByLabelText('Delete Node'));
|
|
|
|
|
|
// Add another condition
|
|
|
- selectByValue(
|
|
|
- wrapper,
|
|
|
- 'sentry.rules.conditions.tagged_event.TaggedEventCondition',
|
|
|
- {selector: 'Select[placeholder="Add optional condition..."]'}
|
|
|
- );
|
|
|
-
|
|
|
+ await selectEvent.select(getByText('Add optional condition...'), [
|
|
|
+ "An event's tags match {key} {match} {value}",
|
|
|
+ ]);
|
|
|
// Edit new Condition
|
|
|
- const ruleNode = wrapper.find('RuleNode').at(0);
|
|
|
-
|
|
|
- ruleNode
|
|
|
- .find('input[name="key"]')
|
|
|
- .simulate('change', {target: {value: 'conditionKey'}});
|
|
|
-
|
|
|
- ruleNode
|
|
|
- .find('input[name="value"]')
|
|
|
- .simulate('change', {target: {value: 'conditionValue'}});
|
|
|
-
|
|
|
- selectByValue(wrapper, 'ne', {name: 'match', control: true});
|
|
|
-
|
|
|
- // Add a filter and remove it
|
|
|
- selectByValue(wrapper, 'sentry.rules.filters.age_comparison.AgeComparisonFilter', {
|
|
|
- selector: 'Select[placeholder="Add optional filter..."]',
|
|
|
+ fireEvent.change(getByPlaceholderText('key'), {
|
|
|
+ target: {value: 'conditionKey'},
|
|
|
});
|
|
|
+ fireEvent.change(getByPlaceholderText('value'), {
|
|
|
+ target: {value: 'conditionValue'},
|
|
|
+ });
|
|
|
+ await selectEvent.select(getByText('equals'), ['does not equal']);
|
|
|
|
|
|
- wrapper
|
|
|
- .find('RuleNode')
|
|
|
- .at(1)
|
|
|
- .find('button[aria-label="Delete Node"]')
|
|
|
- .simulate('click');
|
|
|
+ // Add a filter and remove it
|
|
|
+ await selectEvent.select(getByText('Add optional filter...'), [
|
|
|
+ 'The issue is {comparison_type} than {value} {time}',
|
|
|
+ ]);
|
|
|
+ fireEvent.click(getAllByLabelText('Delete Node')[1]);
|
|
|
|
|
|
// Add a new filter
|
|
|
- selectByValue(wrapper, 'sentry.rules.filters.age_comparison.AgeComparisonFilter', {
|
|
|
- selector: 'Select[placeholder="Add optional filter..."]',
|
|
|
+ await selectEvent.select(getByText('Add optional filter...'), [
|
|
|
+ 'The issue is {comparison_type} than {value} {time}',
|
|
|
+ ]);
|
|
|
+ fireEvent.change(getByPlaceholderText('10'), {
|
|
|
+ target: {value: '12'},
|
|
|
});
|
|
|
|
|
|
- const filterRuleNode = wrapper.find('RuleNode').at(1);
|
|
|
-
|
|
|
- filterRuleNode
|
|
|
- .find('input[type="number"]')
|
|
|
- .simulate('change', {target: {value: '12'}});
|
|
|
-
|
|
|
// Add an action and remove it
|
|
|
- selectByValue(wrapper, 'sentry.rules.actions.notify_event.NotifyEventAction', {
|
|
|
- selector: 'Select[placeholder="Add action..."]',
|
|
|
- });
|
|
|
-
|
|
|
- wrapper
|
|
|
- .find('RuleNodeList')
|
|
|
- .at(2)
|
|
|
- .find('button[aria-label="Delete Node"]')
|
|
|
- .simulate('click');
|
|
|
+ await selectEvent.select(getByText('Add action...'), [
|
|
|
+ 'Send a notification (for all legacy integrations)',
|
|
|
+ ]);
|
|
|
+ fireEvent.click(getAllByLabelText('Delete Node')[2]);
|
|
|
|
|
|
// Add a new action
|
|
|
- selectByValue(
|
|
|
- wrapper,
|
|
|
- 'sentry.rules.actions.notify_event_service.NotifyEventServiceAction',
|
|
|
- {
|
|
|
- selector: 'Select[placeholder="Add action..."]',
|
|
|
- }
|
|
|
- );
|
|
|
+ await selectEvent.select(getByText('Add action...'), [
|
|
|
+ 'Send a notification via {service}',
|
|
|
+ ]);
|
|
|
|
|
|
- selectByValue(wrapper, '60', {
|
|
|
- name: 'frequency',
|
|
|
- });
|
|
|
+ // Update action interval
|
|
|
+ await selectEvent.select(getByText('30 minutes'), ['60 minutes']);
|
|
|
|
|
|
- wrapper.find('form').simulate('submit');
|
|
|
+ fireEvent.click(getByText('Save Rule'));
|
|
|
|
|
|
- expect(mock).toHaveBeenCalledWith(
|
|
|
- expect.any(String),
|
|
|
- expect.objectContaining({
|
|
|
- data: {
|
|
|
- actionMatch: 'any',
|
|
|
- filterMatch: 'any',
|
|
|
- actions: [
|
|
|
- {
|
|
|
- id: 'sentry.rules.actions.notify_event_service.NotifyEventServiceAction',
|
|
|
- service: 'mail',
|
|
|
- },
|
|
|
- ],
|
|
|
- conditions: [
|
|
|
- {
|
|
|
- id: 'sentry.rules.conditions.tagged_event.TaggedEventCondition',
|
|
|
- key: 'conditionKey',
|
|
|
- match: 'ne',
|
|
|
- value: 'conditionValue',
|
|
|
- },
|
|
|
- ],
|
|
|
- filters: [
|
|
|
- {
|
|
|
- id: 'sentry.rules.filters.age_comparison.AgeComparisonFilter',
|
|
|
- comparison_type: 'older',
|
|
|
- time: 'minute',
|
|
|
- value: '12',
|
|
|
- },
|
|
|
- ],
|
|
|
- environment: 'production',
|
|
|
- frequency: '60',
|
|
|
- name: 'My Rule Name',
|
|
|
- owner: null,
|
|
|
- },
|
|
|
- })
|
|
|
- );
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(mock).toHaveBeenCalledWith(
|
|
|
+ expect.any(String),
|
|
|
+ expect.objectContaining({
|
|
|
+ data: {
|
|
|
+ actionMatch: 'any',
|
|
|
+ filterMatch: 'any',
|
|
|
+ actions: [
|
|
|
+ {
|
|
|
+ id: 'sentry.rules.actions.notify_event_service.NotifyEventServiceAction',
|
|
|
+ service: 'mail',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ conditions: [
|
|
|
+ {
|
|
|
+ id: 'sentry.rules.conditions.tagged_event.TaggedEventCondition',
|
|
|
+ key: 'conditionKey',
|
|
|
+ match: 'ne',
|
|
|
+ value: 'conditionValue',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ filters: [
|
|
|
+ {
|
|
|
+ id: 'sentry.rules.filters.age_comparison.AgeComparisonFilter',
|
|
|
+ comparison_type: 'older',
|
|
|
+ time: 'minute',
|
|
|
+ value: '12',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ environment: 'production',
|
|
|
+ frequency: '60',
|
|
|
+ name: 'My Rule Name',
|
|
|
+ owner: null,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ );
|
|
|
+ });
|
|
|
expect(metric.startTransaction).toHaveBeenCalledWith({name: 'saveAlertRule'});
|
|
|
|
|
|
- await tick();
|
|
|
expect(router.push).toHaveBeenCalledWith('/organizations/org-slug/alerts/rules/');
|
|
|
});
|
|
|
});
|