integrationRepos.spec.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  2. import RepositoryStore from 'sentry/stores/repositoryStore';
  3. import IntegrationRepos from 'sentry/views/settings/organizationIntegrations/integrationRepos';
  4. describe('IntegrationRepos', function () {
  5. const org = TestStubs.Organization();
  6. const integration = TestStubs.GitHubIntegration();
  7. let resetReposSpy;
  8. beforeEach(() => {
  9. MockApiClient.clearMockResponses();
  10. RepositoryStore.init();
  11. resetReposSpy = jest.spyOn(RepositoryStore, 'resetRepositories');
  12. });
  13. afterEach(() => {
  14. jest.restoreAllMocks();
  15. resetReposSpy();
  16. });
  17. describe('Getting repositories', function () {
  18. it('handles broken integrations', async function () {
  19. MockApiClient.addMockResponse({
  20. url: `/organizations/${org.slug}/integrations/1/repos/`,
  21. statusCode: 400,
  22. body: {detail: 'Invalid grant'},
  23. });
  24. MockApiClient.addMockResponse({
  25. url: `/organizations/${org.slug}/repos/`,
  26. method: 'GET',
  27. body: [],
  28. });
  29. render(<IntegrationRepos integration={integration} />);
  30. expect(
  31. await screen.findByText(
  32. /We were unable to fetch repositories for this integration/
  33. )
  34. ).toBeInTheDocument();
  35. });
  36. });
  37. describe('Adding repositories', function () {
  38. it('can save successfully', async function () {
  39. const addRepo = MockApiClient.addMockResponse({
  40. url: `/organizations/${org.slug}/repos/`,
  41. method: 'POST',
  42. body: TestStubs.Repository({integrationId: '1'}),
  43. });
  44. MockApiClient.addMockResponse({
  45. url: `/organizations/${org.slug}/integrations/1/repos/`,
  46. body: {
  47. repos: [{identifier: 'example/repo-name', name: 'repo-name'}],
  48. },
  49. });
  50. MockApiClient.addMockResponse({
  51. url: `/organizations/${org.slug}/repos/`,
  52. method: 'GET',
  53. body: [],
  54. });
  55. render(<IntegrationRepos integration={integration} />);
  56. await userEvent.click(screen.getByText('Add Repository'));
  57. await userEvent.click(screen.getByText('repo-name'));
  58. expect(addRepo).toHaveBeenCalledWith(
  59. `/organizations/${org.slug}/repos/`,
  60. expect.objectContaining({
  61. data: {
  62. installation: '1',
  63. provider: 'integrations:github',
  64. identifier: 'example/repo-name',
  65. },
  66. })
  67. );
  68. expect(await screen.findByText('example/repo-name')).toBeInTheDocument();
  69. expect(resetReposSpy).toHaveBeenCalled();
  70. });
  71. it('handles failure during save', async function () {
  72. const addRepo = MockApiClient.addMockResponse({
  73. url: `/organizations/${org.slug}/repos/`,
  74. method: 'POST',
  75. statusCode: 400,
  76. body: {
  77. errors: {
  78. __all__: 'Repository already exists.',
  79. },
  80. },
  81. });
  82. MockApiClient.addMockResponse({
  83. url: `/organizations/${org.slug}/integrations/1/repos/`,
  84. body: {
  85. repos: [{identifier: 'getsentry/sentry', name: 'sentry-repo'}],
  86. },
  87. });
  88. MockApiClient.addMockResponse({
  89. url: `/organizations/${org.slug}/repos/`,
  90. method: 'GET',
  91. body: [],
  92. });
  93. render(<IntegrationRepos integration={integration} />);
  94. await userEvent.click(screen.getByText('Add Repository'));
  95. await userEvent.click(screen.getByText('sentry-repo'));
  96. expect(addRepo).toHaveBeenCalled();
  97. expect(screen.queryByText('getsentry/sentry')).not.toBeInTheDocument();
  98. });
  99. it('does not disable add repo for members', function () {
  100. MockApiClient.addMockResponse({
  101. url: `/organizations/${org.slug}/integrations/1/repos/`,
  102. body: {
  103. repos: [{identifier: 'example/repo-name', name: 'repo-name'}],
  104. },
  105. });
  106. MockApiClient.addMockResponse({
  107. url: `/organizations/${org.slug}/repos/`,
  108. method: 'GET',
  109. body: [],
  110. });
  111. render(
  112. <IntegrationRepos
  113. integration={integration}
  114. organization={TestStubs.Organization({access: []})}
  115. />
  116. );
  117. expect(screen.getByText('Add Repository')).toBeEnabled();
  118. });
  119. });
  120. describe('migratable repo', function () {
  121. it('associates repository with integration', async () => {
  122. MockApiClient.addMockResponse({
  123. url: `/organizations/${org.slug}/repos/`,
  124. body: [
  125. TestStubs.Repository({
  126. integrationId: null,
  127. externalSlug: 'example/repo-name',
  128. provider: {
  129. id: 'integrations:github',
  130. name: 'GitHub',
  131. status: 'active',
  132. },
  133. }),
  134. ],
  135. });
  136. MockApiClient.addMockResponse({
  137. url: `/organizations/${org.slug}/integrations/${integration.id}/repos/`,
  138. body: {repos: [{identifier: 'example/repo-name', name: 'repo-name'}]},
  139. });
  140. const updateRepo = MockApiClient.addMockResponse({
  141. method: 'PUT',
  142. url: `/organizations/${org.slug}/repos/4/`,
  143. body: {id: 244},
  144. });
  145. render(<IntegrationRepos integration={integration} />);
  146. await userEvent.click(screen.getByText('Add Repository'));
  147. await userEvent.click(screen.getByText('repo-name'));
  148. expect(updateRepo).toHaveBeenCalledWith(
  149. `/organizations/${org.slug}/repos/4/`,
  150. expect.objectContaining({
  151. data: {integrationId: '1'},
  152. })
  153. );
  154. await waitFor(() => expect(resetReposSpy).toHaveBeenCalled());
  155. });
  156. it('uses externalSlug not name for comparison', async () => {
  157. MockApiClient.addMockResponse({
  158. url: `/organizations/${org.slug}/repos/`,
  159. method: 'GET',
  160. body: [TestStubs.Repository({name: 'repo-name-other', externalSlug: 9876})],
  161. });
  162. const getItems = MockApiClient.addMockResponse({
  163. url: `/organizations/${org.slug}/integrations/${integration.id}/repos/`,
  164. method: 'GET',
  165. body: {
  166. repos: [{identifier: 9876, name: 'repo-name'}],
  167. },
  168. });
  169. const updateRepo = MockApiClient.addMockResponse({
  170. method: 'PUT',
  171. url: `/organizations/${org.slug}/repos/4/`,
  172. body: {id: 4320},
  173. });
  174. render(<IntegrationRepos integration={integration} />);
  175. await userEvent.click(screen.getByText('Add Repository'));
  176. await userEvent.click(screen.getByText('repo-name'));
  177. expect(getItems).toHaveBeenCalled();
  178. expect(updateRepo).toHaveBeenCalledWith(
  179. `/organizations/${org.slug}/repos/4/`,
  180. expect.objectContaining({
  181. data: {integrationId: '1'},
  182. })
  183. );
  184. });
  185. });
  186. });