integrationDetailedView.spec.tsx 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import {GitHubIntegrationProvider} from 'sentry-fixture/githubIntegrationProvider';
  2. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  3. import IntegrationDetailedView from 'sentry/views/settings/organizationIntegrations/integrationDetailedView';
  4. describe('IntegrationDetailedView', function () {
  5. const ENDPOINT = '/organizations/org-slug/';
  6. const org = TestStubs.Organization({
  7. access: ['org:integrations', 'org:write'],
  8. });
  9. beforeEach(() => {
  10. MockApiClient.clearMockResponses();
  11. MockApiClient.addMockResponse({
  12. url: `/organizations/${org.slug}/config/integrations/?provider_key=bitbucket`,
  13. body: {
  14. providers: [
  15. {
  16. canAdd: true,
  17. canDisable: false,
  18. features: ['commits', 'issue-basic'],
  19. key: 'bitbucket',
  20. metadata: {
  21. aspects: {},
  22. author: 'The Sentry Team',
  23. description:
  24. 'Connect your Sentry organization to Bitbucket, enabling the following features:',
  25. features: [],
  26. issue_url:
  27. 'https://github.com/getsentry/sentry/issues/new?template=bug.yml&title=Bitbucket%20Integration:%20&labels=Component%3A%20Integrations',
  28. noun: 'Installation',
  29. source_url:
  30. 'https://github.com/getsentry/sentry/tree/master/src/sentry/integrations/bitbucket',
  31. },
  32. name: 'Bitbucket',
  33. setupDialog: {
  34. height: 600,
  35. url: '/organizations/sentry/integrations/bitbucket/setup/',
  36. width: 600,
  37. },
  38. slug: 'bitbucket',
  39. },
  40. ],
  41. },
  42. });
  43. MockApiClient.addMockResponse({
  44. url: `/organizations/${org.slug}/integrations/?provider_key=bitbucket&includeConfig=0`,
  45. body: [
  46. {
  47. accountType: null,
  48. configData: {},
  49. configOrganization: [],
  50. domainName: 'bitbucket.org/%7Bfb715533-bbd7-4666-aa57-01dc93dd9cc0%7D',
  51. icon: 'https://secure.gravatar.com/avatar/8b4cb68e40b74c90427d8262256bd1c8?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FNN-0.png',
  52. id: '4',
  53. name: '{fb715533-bbd7-4666-aa57-01dc93dd9cc0}',
  54. provider: {
  55. aspects: {},
  56. canAdd: true,
  57. canDisable: false,
  58. features: ['commits', 'issue-basic'],
  59. key: 'bitbucket',
  60. name: 'Bitbucket',
  61. slug: 'bitbucket',
  62. },
  63. status: 'active',
  64. },
  65. ],
  66. });
  67. });
  68. it('shows integration name, status, and install button', function () {
  69. render(
  70. <IntegrationDetailedView
  71. {...TestStubs.routeComponentProps()}
  72. params={{integrationSlug: 'bitbucket'}}
  73. location={TestStubs.location({query: {}})}
  74. />
  75. );
  76. expect(screen.getByText('Bitbucket')).toBeInTheDocument();
  77. expect(screen.getByText('Installed')).toBeInTheDocument();
  78. expect(screen.getByRole('button', {name: 'Add integration'})).toBeEnabled();
  79. });
  80. it('view configurations', function () {
  81. render(
  82. <IntegrationDetailedView
  83. {...TestStubs.routeComponentProps()}
  84. params={{integrationSlug: 'bitbucket'}}
  85. location={TestStubs.location({query: {tab: 'configurations'}})}
  86. />
  87. );
  88. expect(screen.getByTestId('integration-name')).toHaveTextContent(
  89. '{fb715533-bbd7-4666-aa57-01dc93dd9cc0}'
  90. );
  91. expect(screen.getByRole('button', {name: 'Configure'})).toBeEnabled();
  92. });
  93. it('disables configure for members without access', function () {
  94. render(
  95. <IntegrationDetailedView
  96. {...TestStubs.routeComponentProps()}
  97. params={{integrationSlug: 'bitbucket'}}
  98. location={TestStubs.location({query: {tab: 'configurations'}})}
  99. />,
  100. {organization: TestStubs.Organization({access: ['org:read']})}
  101. );
  102. expect(screen.getByRole('button', {name: 'Configure'})).toBeDisabled();
  103. });
  104. it('allows members to configure github/gitlab', function () {
  105. MockApiClient.addMockResponse({
  106. url: `/organizations/${org.slug}/config/integrations/?provider_key=github`,
  107. body: {
  108. providers: [GitHubIntegrationProvider()],
  109. },
  110. });
  111. MockApiClient.addMockResponse({
  112. url: `/organizations/${org.slug}/integrations/?provider_key=github&includeConfig=0`,
  113. body: [
  114. {
  115. accountType: null,
  116. configData: {},
  117. configOrganization: [],
  118. domainName: 'github.com/%7Bfb715533-bbd7-4666-aa57-01dc93dd9cc0%7D',
  119. icon: 'https://secure.gravatar.com/avatar/8b4cb68e40b74c90427d8262256bd1c8?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FNN-0.png',
  120. id: '4',
  121. name: '{fb715533-bbd7-4666-aa57-01dc93dd9cc0}',
  122. provider: {
  123. aspects: {},
  124. canAdd: true,
  125. canDisable: false,
  126. features: ['commits', 'issue-basic'],
  127. key: 'github',
  128. name: 'GitHub',
  129. slug: 'github',
  130. },
  131. status: 'active',
  132. },
  133. ],
  134. });
  135. render(
  136. <IntegrationDetailedView
  137. {...TestStubs.routeComponentProps()}
  138. params={{integrationSlug: 'github'}}
  139. location={TestStubs.location({query: {tab: 'configurations'}})}
  140. />,
  141. {organization: TestStubs.Organization({access: ['org:read']})}
  142. );
  143. expect(screen.getByRole('button', {name: 'Configure'})).toBeEnabled();
  144. });
  145. it('shows features tab for github only', function () {
  146. MockApiClient.addMockResponse({
  147. url: `/organizations/${org.slug}/config/integrations/?provider_key=github`,
  148. body: {
  149. providers: [GitHubIntegrationProvider()],
  150. },
  151. });
  152. MockApiClient.addMockResponse({
  153. url: `/organizations/${org.slug}/integrations/?provider_key=github&includeConfig=0`,
  154. body: [
  155. {
  156. accountType: null,
  157. configData: {},
  158. configOrganization: [],
  159. domainName: 'github.com/%7Bfb715533-bbd7-4666-aa57-01dc93dd9cc0%7D',
  160. icon: 'https://secure.gravatar.com/avatar/8b4cb68e40b74c90427d8262256bd1c8?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FNN-0.png',
  161. id: '4',
  162. name: '{fb715533-bbd7-4666-aa57-01dc93dd9cc0}',
  163. provider: {
  164. aspects: {},
  165. canAdd: true,
  166. canDisable: false,
  167. features: ['commits', 'issue-basic'],
  168. key: 'github',
  169. name: 'GitHub',
  170. slug: 'github',
  171. },
  172. status: 'active',
  173. },
  174. ],
  175. });
  176. render(
  177. <IntegrationDetailedView
  178. {...TestStubs.routeComponentProps()}
  179. params={{integrationSlug: 'github'}}
  180. organization={org}
  181. location={TestStubs.location({query: {}})}
  182. />
  183. );
  184. expect(screen.getByText('features')).toBeInTheDocument();
  185. });
  186. it('cannot enable PR bot without GitHub integration', async function () {
  187. org.features.push('integrations-open-pr-comment');
  188. MockApiClient.addMockResponse({
  189. url: `/organizations/${org.slug}/config/integrations/?provider_key=github`,
  190. body: {
  191. providers: [GitHubIntegrationProvider()],
  192. },
  193. });
  194. MockApiClient.addMockResponse({
  195. url: `/organizations/${org.slug}/integrations/?provider_key=github&includeConfig=0`,
  196. body: [],
  197. });
  198. render(
  199. <IntegrationDetailedView
  200. {...TestStubs.routeComponentProps()}
  201. params={{integrationSlug: 'github'}}
  202. organization={org}
  203. location={TestStubs.location({query: {}})}
  204. />
  205. );
  206. await userEvent.click(screen.getByText('features'));
  207. expect(
  208. screen.getByRole('checkbox', {name: /Enable Comments on Suspect Pull Requests/})
  209. ).toBeDisabled();
  210. expect(
  211. screen.getByRole('checkbox', {name: /Enable Comments on Open Pull Requests/})
  212. ).toBeDisabled();
  213. });
  214. it('can enable github features', async function () {
  215. org.features.push('integrations-open-pr-comment');
  216. org.features.push('integrations-gh-invite');
  217. MockApiClient.addMockResponse({
  218. url: `/organizations/${org.slug}/config/integrations/?provider_key=github`,
  219. body: {
  220. providers: [GitHubIntegrationProvider()],
  221. },
  222. });
  223. MockApiClient.addMockResponse({
  224. url: `/organizations/${org.slug}/integrations/?provider_key=github&includeConfig=0`,
  225. body: [TestStubs.GitHubIntegration()],
  226. });
  227. render(
  228. <IntegrationDetailedView
  229. {...TestStubs.routeComponentProps()}
  230. params={{integrationSlug: 'github'}}
  231. organization={org}
  232. location={TestStubs.location({query: {}})}
  233. />
  234. );
  235. await userEvent.click(screen.getByText('features'));
  236. const mock = MockApiClient.addMockResponse({
  237. url: ENDPOINT,
  238. method: 'PUT',
  239. });
  240. await userEvent.click(
  241. screen.getByRole('checkbox', {name: /Enable Comments on Suspect Pull Requests/})
  242. );
  243. await waitFor(() => {
  244. expect(mock).toHaveBeenCalledWith(
  245. ENDPOINT,
  246. expect.objectContaining({
  247. data: {githubPRBot: true},
  248. })
  249. );
  250. });
  251. await userEvent.click(
  252. screen.getByRole('checkbox', {name: /Enable Comments on Open Pull Requests/})
  253. );
  254. await waitFor(() => {
  255. expect(mock).toHaveBeenCalledWith(
  256. ENDPOINT,
  257. expect.objectContaining({
  258. data: {githubOpenPRBot: true},
  259. })
  260. );
  261. });
  262. await userEvent.click(
  263. screen.getByRole('checkbox', {name: /Enable Missing Member Detection/})
  264. );
  265. await waitFor(() => {
  266. expect(mock).toHaveBeenCalledWith(
  267. ENDPOINT,
  268. expect.objectContaining({
  269. data: {githubNudgeInvite: true},
  270. })
  271. );
  272. });
  273. });
  274. });