integrationCodeMappings.spec.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import selectEvent from 'react-select-event';
  2. import {
  3. render,
  4. renderGlobalModal,
  5. screen,
  6. userEvent,
  7. waitFor,
  8. } from 'sentry-test/reactTestingLibrary';
  9. import ModalStore from 'sentry/stores/modalStore';
  10. import ProjectsStore from 'sentry/stores/projectsStore';
  11. import IntegrationCodeMappings from 'sentry/views/settings/organizationIntegrations/integrationCodeMappings';
  12. describe('IntegrationCodeMappings', function () {
  13. const projects = [
  14. TestStubs.Project(),
  15. TestStubs.Project({
  16. id: '3',
  17. slug: 'some-project',
  18. name: 'Some Project',
  19. }),
  20. ];
  21. const org = TestStubs.Organization();
  22. const integration = TestStubs.GitHubIntegration();
  23. const repos = [
  24. TestStubs.Repository({
  25. integrationId: integration.id,
  26. }),
  27. TestStubs.Repository({
  28. integrationId: integration.id,
  29. id: '5',
  30. name: 'example/hello-there',
  31. }),
  32. ];
  33. const pathConfig1 = TestStubs.RepositoryProjectPathConfig({
  34. project: projects[0],
  35. repo: repos[0],
  36. integration,
  37. stackRoot: 'stack/root',
  38. sourceRoot: 'source/root',
  39. });
  40. const pathConfig2 = TestStubs.RepositoryProjectPathConfig({
  41. project: projects[1],
  42. repo: repos[1],
  43. integration,
  44. id: '12',
  45. stackRoot: 'one/path',
  46. sourceRoot: 'another/root',
  47. });
  48. beforeEach(() => {
  49. ModalStore.init();
  50. ProjectsStore.loadInitialData(projects);
  51. MockApiClient.addMockResponse({
  52. url: `/organizations/${org.slug}/code-mappings/`,
  53. body: [pathConfig1, pathConfig2],
  54. });
  55. MockApiClient.addMockResponse({
  56. url: `/organizations/${org.slug}/repos/`,
  57. body: repos,
  58. });
  59. MockApiClient.addMockResponse({
  60. url: `/organizations/${org.slug}/integrations/${integration.id}/repos/`,
  61. body: {repos: []},
  62. });
  63. });
  64. afterEach(() => {
  65. // Clear the fields from the GlobalModal after every test
  66. ModalStore.reset();
  67. ProjectsStore.reset();
  68. MockApiClient.clearMockResponses();
  69. });
  70. it('shows the paths', () => {
  71. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  72. for (const repo of repos) {
  73. expect(screen.getByText(repo.name)).toBeInTheDocument();
  74. }
  75. });
  76. it('create new config', async () => {
  77. const stackRoot = 'my/root';
  78. const sourceRoot = 'hey/dude';
  79. const defaultBranch = 'release';
  80. const url = `/organizations/${org.slug}/code-mappings/`;
  81. const createMock = MockApiClient.addMockResponse({
  82. url,
  83. method: 'POST',
  84. body: TestStubs.RepositoryProjectPathConfig({
  85. project: projects[1],
  86. repo: repos[1],
  87. integration,
  88. stackRoot,
  89. sourceRoot,
  90. defaultBranch,
  91. }),
  92. });
  93. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  94. const {waitForModalToHide} = renderGlobalModal();
  95. await userEvent.click(screen.getByRole('button', {name: 'Add Code Mapping'}));
  96. expect(screen.getByRole('dialog')).toBeInTheDocument();
  97. await selectEvent.select(screen.getByText('Choose Sentry project'), projects[1].slug);
  98. await selectEvent.select(screen.getByText('Choose repo'), repos[1].name);
  99. await userEvent.type(
  100. screen.getByRole('textbox', {name: 'Stack Trace Root'}),
  101. stackRoot
  102. );
  103. await userEvent.type(
  104. screen.getByRole('textbox', {name: 'Source Code Root'}),
  105. sourceRoot
  106. );
  107. await userEvent.clear(screen.getByRole('textbox', {name: 'Branch'}));
  108. await userEvent.type(screen.getByRole('textbox', {name: 'Branch'}), defaultBranch);
  109. await userEvent.click(screen.getByRole('button', {name: 'Save Changes'}));
  110. await waitForModalToHide();
  111. expect(createMock).toHaveBeenCalledWith(
  112. url,
  113. expect.objectContaining({
  114. data: expect.objectContaining({
  115. projectId: projects[1].id,
  116. repositoryId: repos[1].id,
  117. stackRoot,
  118. sourceRoot,
  119. defaultBranch,
  120. integrationId: integration.id,
  121. }),
  122. })
  123. );
  124. });
  125. it('edit existing config', async () => {
  126. const stackRoot = 'new/root';
  127. const sourceRoot = 'source/root';
  128. const defaultBranch = 'master';
  129. const url = `/organizations/${org.slug}/code-mappings/${pathConfig1.id}/`;
  130. const editMock = MockApiClient.addMockResponse({
  131. url,
  132. method: 'PUT',
  133. body: TestStubs.RepositoryProjectPathConfig({
  134. project: projects[0],
  135. repo: repos[0],
  136. integration,
  137. stackRoot,
  138. sourceRoot,
  139. defaultBranch,
  140. }),
  141. });
  142. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  143. const {waitForModalToHide} = renderGlobalModal();
  144. await userEvent.click(screen.getAllByRole('button', {name: 'edit'})[0]);
  145. await userEvent.clear(screen.getByRole('textbox', {name: 'Stack Trace Root'}));
  146. await userEvent.type(
  147. screen.getByRole('textbox', {name: 'Stack Trace Root'}),
  148. stackRoot
  149. );
  150. await userEvent.click(screen.getByRole('button', {name: 'Save Changes'}));
  151. await waitForModalToHide();
  152. expect(editMock).toHaveBeenCalledWith(
  153. url,
  154. expect.objectContaining({
  155. data: expect.objectContaining({
  156. defaultBranch,
  157. projectId: '2',
  158. repositoryId: '4',
  159. sourceRoot,
  160. stackRoot,
  161. }),
  162. })
  163. );
  164. });
  165. it('switches default branch to the repo defaultBranch', async () => {
  166. MockApiClient.addMockResponse({
  167. url: `/organizations/${org.slug}/integrations/${integration.id}/repos/`,
  168. body: {
  169. repos: [
  170. {
  171. id: repos[0].id,
  172. identifier: repos[1].name,
  173. defaultBranch: 'main',
  174. },
  175. ],
  176. },
  177. });
  178. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  179. renderGlobalModal();
  180. await userEvent.click(screen.getByRole('button', {name: 'Add Code Mapping'}));
  181. expect(screen.getByRole('textbox', {name: 'Branch'})).toHaveValue('master');
  182. await selectEvent.select(screen.getByText('Choose repo'), repos[1].name);
  183. await waitFor(() => {
  184. expect(screen.getByRole('textbox', {name: 'Branch'})).toHaveValue('main');
  185. });
  186. });
  187. });