sentryAppExternalIssueActions.spec.jsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import {Fragment} from 'react';
  2. import {mountWithTheme} from 'sentry-test/enzyme';
  3. import GlobalModal from 'app/components/globalModal';
  4. import SentryAppExternalIssueActions from 'app/components/group/sentryAppExternalIssueActions';
  5. describe('SentryAppExternalIssueActions', () => {
  6. let group;
  7. let component;
  8. let sentryApp;
  9. let install;
  10. let submitUrl;
  11. let externalIssue;
  12. let wrapper;
  13. beforeEach(() => {
  14. group = TestStubs.Group();
  15. sentryApp = TestStubs.SentryApp();
  16. component = TestStubs.SentryAppComponent({
  17. sentryApp: {
  18. uuid: sentryApp.uuid,
  19. slug: sentryApp.slug,
  20. name: sentryApp.name,
  21. },
  22. });
  23. // unable to use the selectByValue here so remove the select option
  24. component.schema.create.required_fields.pop();
  25. install = TestStubs.SentryAppInstallation({sentryApp});
  26. submitUrl = `/sentry-app-installations/${install.uuid}/external-issue-actions/`;
  27. externalIssue = TestStubs.PlatformExternalIssue({
  28. groupId: group.id,
  29. serviceType: component.sentryApp.slug,
  30. });
  31. MockApiClient.addMockResponse({
  32. url: `/sentry-apps/${sentryApp.slug}/interaction/`,
  33. method: 'POST',
  34. });
  35. });
  36. describe('without an external issue linked', () => {
  37. beforeEach(() => {
  38. wrapper = mountWithTheme(
  39. <Fragment>
  40. <GlobalModal />
  41. <SentryAppExternalIssueActions
  42. group={group}
  43. sentryAppInstallation={install}
  44. sentryAppComponent={component}
  45. />
  46. </Fragment>,
  47. TestStubs.routerContext()
  48. );
  49. });
  50. it('renders a link to open the modal', () => {
  51. expect(wrapper.find('IntegrationLink a').text()).toEqual(
  52. `Link ${component.sentryApp.name} Issue`
  53. );
  54. });
  55. it('renders the add icon', () => {
  56. expect(wrapper.find('StyledIcon IconAdd')).toHaveLength(1);
  57. });
  58. it('opens the modal', async () => {
  59. wrapper.find('IntegrationLink a').simulate('click');
  60. await tick();
  61. wrapper.update();
  62. expect(wrapper.find('GlobalModal[visible=true]').exists()).toEqual(true);
  63. });
  64. it('renders the Create Issue form fields, based on schema', async () => {
  65. wrapper.find('IntegrationLink a').simulate('click');
  66. await tick();
  67. wrapper.update();
  68. wrapper.find('Modal NavTabs li.create a').first().simulate('click'); // Create
  69. component.schema.create.required_fields.forEach(field => {
  70. expect(wrapper.exists(`SentryAppExternalIssueForm #${field.name}`)).toBe(true);
  71. });
  72. (component.schema.create.optional_fields || []).forEach(field => {
  73. expect(wrapper.exists(`SentryAppExternalIssueForm #${field.name}`)).toBe(true);
  74. });
  75. });
  76. it('renders the Link Issue form fields, based on schema', async () => {
  77. wrapper.find('IntegrationLink a').simulate('click');
  78. await tick();
  79. wrapper.update();
  80. wrapper.find('Modal NavTabs li.link a').first().simulate('click'); // Link
  81. component.schema.link.required_fields.forEach(field => {
  82. expect(wrapper.exists(`SentryAppExternalIssueForm #${field.name}`)).toBe(true);
  83. });
  84. (component.schema.link.optional_fields || []).forEach(field => {
  85. expect(wrapper.exists(`SentryAppExternalIssueForm #${field.name}`)).toBe(true);
  86. });
  87. });
  88. it('links to an existing Issue', async () => {
  89. const request = MockApiClient.addMockResponse({
  90. url: submitUrl,
  91. method: 'POST',
  92. body: externalIssue,
  93. });
  94. wrapper.find('IntegrationLink a').simulate('click');
  95. await tick();
  96. wrapper.update();
  97. wrapper.find('NavTabs li.link a').simulate('click');
  98. wrapper.find('Input#issue').simulate('change', {target: {value: '99'}});
  99. wrapper.find('Form form').simulate('submit');
  100. expect(request).toHaveBeenCalledWith(
  101. submitUrl,
  102. expect.objectContaining({
  103. data: expect.objectContaining({
  104. action: 'link',
  105. issue: '99',
  106. groupId: group.id,
  107. }),
  108. })
  109. );
  110. });
  111. it('creates a new Issue', async () => {
  112. const request = MockApiClient.addMockResponse({
  113. url: submitUrl,
  114. method: 'POST',
  115. body: externalIssue,
  116. });
  117. wrapper.find('IntegrationLink a').simulate('click');
  118. await tick();
  119. wrapper.update();
  120. wrapper.find('NavTabs li.create a').simulate('click');
  121. wrapper.find('Input#title').simulate('change', {target: {value: 'foo'}});
  122. wrapper.find('TextArea#description').simulate('change', {target: {value: 'bar'}});
  123. wrapper.find('Form form').simulate('submit');
  124. expect(request).toHaveBeenCalledWith(
  125. submitUrl,
  126. expect.objectContaining({
  127. data: expect.objectContaining({
  128. action: 'create',
  129. title: 'foo',
  130. description: 'bar',
  131. groupId: group.id,
  132. }),
  133. })
  134. );
  135. });
  136. });
  137. describe('with an external issue linked', () => {
  138. beforeEach(() => {
  139. wrapper = mountWithTheme(
  140. <SentryAppExternalIssueActions
  141. group={group}
  142. sentryAppComponent={component}
  143. sentryAppInstallation={install}
  144. externalIssue={externalIssue}
  145. />,
  146. TestStubs.routerContext()
  147. );
  148. });
  149. it('renders a link to the external issue', () => {
  150. expect(wrapper.find('IntegrationLink a').text()).toEqual(externalIssue.displayName);
  151. });
  152. it('links to the issue', () => {
  153. expect(wrapper.find('IntegrationLink').first().prop('href')).toEqual(
  154. externalIssue.webUrl
  155. );
  156. });
  157. it('renders the remove issue button', () => {
  158. expect(wrapper.find('StyledIcon IconClose')).toHaveLength(1);
  159. });
  160. it('deletes a Linked Issue', () => {
  161. const request = MockApiClient.addMockResponse({
  162. url: `/issues/${group.id}/external-issues/${externalIssue.id}/`,
  163. method: 'DELETE',
  164. });
  165. wrapper.find('StyledIcon').simulate('click');
  166. expect(request).toHaveBeenCalled();
  167. });
  168. });
  169. });