issueAlertOptions.spec.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {OrganizationIntegrationsFixture} from 'sentry-fixture/organizationIntegrations';
  3. import {
  4. MOCK_RESP_INCONSISTENT_INTERVALS,
  5. MOCK_RESP_INCONSISTENT_PLACEHOLDERS,
  6. MOCK_RESP_ONLY_IGNORED_CONDITIONS_INVALID,
  7. MOCK_RESP_VERBOSE,
  8. } from 'sentry-fixture/ruleConditions';
  9. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  10. import selectEvent from 'sentry-test/selectEvent';
  11. import type {IssueAlertNotificationProps} from 'sentry/views/projectInstall/issueAlertNotificationOptions';
  12. import IssueAlertOptions from 'sentry/views/projectInstall/issueAlertOptions';
  13. describe('IssueAlertOptions', function () {
  14. const organization = OrganizationFixture();
  15. const URL = `/projects/${organization.slug}/rule-conditions/`;
  16. const notificationProps: IssueAlertNotificationProps = {
  17. actions: [],
  18. channel: 'channel',
  19. integration: OrganizationIntegrationsFixture(),
  20. provider: 'slack',
  21. providersToIntegrations: {},
  22. querySuccess: true,
  23. shouldRenderSetupButton: false,
  24. setActions: jest.fn(),
  25. setChannel: jest.fn(),
  26. setIntegration: jest.fn(),
  27. setProvider: jest.fn(),
  28. };
  29. const props = {
  30. onChange: jest.fn(),
  31. organization,
  32. notificationProps,
  33. };
  34. const getComponent = () => <IssueAlertOptions {...props} {...notificationProps} />;
  35. beforeEach(() => {
  36. MockApiClient.addMockResponse({
  37. url: `/projects/${organization.slug}/rule-conditions/`,
  38. body: MOCK_RESP_VERBOSE,
  39. });
  40. });
  41. afterEach(() => {
  42. MockApiClient.clearMockResponses();
  43. jest.clearAllMocks();
  44. });
  45. it('should render only the `Default Rule` and `Create Later` option on empty response:[]', () => {
  46. MockApiClient.addMockResponse({
  47. url: URL,
  48. body: [],
  49. });
  50. render(getComponent(), {organization});
  51. expect(screen.getAllByRole('radio')).toHaveLength(2);
  52. });
  53. it('should render only the `Default Rule` and `Create Later` option on empty response:{}', () => {
  54. MockApiClient.addMockResponse({
  55. url: URL,
  56. body: {},
  57. });
  58. render(getComponent(), {organization});
  59. expect(screen.getAllByRole('radio')).toHaveLength(2);
  60. });
  61. it('should render only the `Default Rule` and `Create Later` option on responses with different allowable intervals', () => {
  62. MockApiClient.addMockResponse({
  63. url: URL,
  64. body: MOCK_RESP_INCONSISTENT_INTERVALS,
  65. });
  66. render(getComponent(), {organization});
  67. expect(screen.getAllByRole('radio')).toHaveLength(2);
  68. });
  69. it('should render all(three) options on responses with different placeholder values', () => {
  70. MockApiClient.addMockResponse({
  71. url: URL,
  72. body: MOCK_RESP_INCONSISTENT_PLACEHOLDERS,
  73. });
  74. render(getComponent(), {organization});
  75. expect(screen.getAllByRole('radio')).toHaveLength(3);
  76. });
  77. it('should ignore conditions that are not `sentry.rules.conditions.event_frequency.EventFrequencyCondition` and `sentry.rules.conditions.event_frequency.EventUniqueUserFrequencyCondition`', async () => {
  78. MockApiClient.addMockResponse({
  79. url: URL,
  80. body: MOCK_RESP_ONLY_IGNORED_CONDITIONS_INVALID,
  81. });
  82. render(getComponent(), {organization});
  83. expect(screen.getAllByRole('radio')).toHaveLength(3);
  84. await selectEvent.select(screen.getByText('Select...'), 'users affected by');
  85. expect(props.onChange).toHaveBeenCalledWith(
  86. expect.objectContaining({
  87. defaultRules: false,
  88. shouldCreateCustomRule: true,
  89. })
  90. );
  91. });
  92. it('should render all(three) options on a valid response', () => {
  93. MockApiClient.addMockResponse({
  94. url: URL,
  95. body: MOCK_RESP_VERBOSE,
  96. });
  97. render(getComponent());
  98. expect(screen.getAllByRole('radio')).toHaveLength(3);
  99. });
  100. it('should pre-populate fields from server response', async () => {
  101. MockApiClient.addMockResponse({
  102. url: URL,
  103. body: MOCK_RESP_VERBOSE,
  104. });
  105. render(getComponent());
  106. await selectEvent.select(screen.getByText('occurrences of'), 'users affected by');
  107. await selectEvent.select(screen.getByText('one minute'), '30 days');
  108. expect(props.onChange).toHaveBeenCalledWith(
  109. expect.objectContaining({
  110. defaultRules: false,
  111. shouldCreateCustomRule: true,
  112. })
  113. );
  114. });
  115. it('should pre-fill threshold value after a valid server response', () => {
  116. MockApiClient.addMockResponse({
  117. url: URL,
  118. body: MOCK_RESP_VERBOSE,
  119. });
  120. render(getComponent());
  121. expect(screen.getByTestId('range-input')).toHaveValue(10);
  122. });
  123. it('should provide fallthroughType with issue action', async () => {
  124. MockApiClient.addMockResponse({
  125. url: URL,
  126. body: MOCK_RESP_VERBOSE,
  127. });
  128. render(getComponent());
  129. await userEvent.click(screen.getByLabelText(/When there are more than/i));
  130. expect(props.onChange).toHaveBeenCalledWith(
  131. expect.objectContaining({
  132. actions: [
  133. {
  134. id: 'sentry.mail.actions.NotifyEmailAction',
  135. targetType: 'IssueOwners',
  136. fallthroughType: 'ActiveMembers',
  137. },
  138. ],
  139. })
  140. );
  141. });
  142. it('should render alert configuration if `Default` or `Custom` alerts are selected', async () => {
  143. MockApiClient.addMockResponse({
  144. url: URL,
  145. body: MOCK_RESP_VERBOSE,
  146. });
  147. render(getComponent());
  148. await screen.findByRole('checkbox', {name: 'Notify via email'});
  149. await screen.findByRole('checkbox', {
  150. name: 'Notify via integration (Slack, Discord, MS Teams, etc.)',
  151. });
  152. await selectEvent.select(screen.getByText('occurrences of'), 'users affected by');
  153. await screen.findByRole('checkbox', {name: 'Notify via email'});
  154. await screen.findByRole('checkbox', {
  155. name: 'Notify via integration (Slack, Discord, MS Teams, etc.)',
  156. });
  157. });
  158. it('should not render notification configuration if `Create Alerts Later` is selected', async () => {
  159. MockApiClient.addMockResponse({
  160. url: URL,
  161. body: MOCK_RESP_VERBOSE,
  162. });
  163. render(getComponent());
  164. await userEvent.click(screen.getByLabelText("I'll create my own alerts later"));
  165. expect(
  166. screen.queryByRole('checkbox', {name: 'Notify via email'})
  167. ).not.toBeInTheDocument();
  168. expect(
  169. screen.queryByRole('checkbox', {
  170. name: 'Notify via integration (Slack, Discord, MS Teams, etc.)',
  171. })
  172. ).not.toBeInTheDocument();
  173. });
  174. });