integrationCodeMappings.spec.jsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. 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. userEvent.type(screen.getByRole('textbox', {name: 'Stack Trace Root'}), stackRoot);
  100. userEvent.type(screen.getByRole('textbox', {name: 'Source Code Root'}), sourceRoot);
  101. userEvent.clear(screen.getByRole('textbox', {name: 'Branch'}));
  102. userEvent.type(screen.getByRole('textbox', {name: 'Branch'}), defaultBranch);
  103. userEvent.click(screen.getByRole('button', {name: 'Save Changes'}));
  104. await waitForModalToHide();
  105. expect(createMock).toHaveBeenCalledWith(
  106. url,
  107. expect.objectContaining({
  108. data: expect.objectContaining({
  109. projectId: projects[1].id,
  110. repositoryId: repos[1].id,
  111. stackRoot,
  112. sourceRoot,
  113. defaultBranch,
  114. integrationId: integration.id,
  115. }),
  116. })
  117. );
  118. });
  119. it('edit existing config', async () => {
  120. const stackRoot = 'new/root';
  121. const sourceRoot = 'source/root';
  122. const defaultBranch = 'master';
  123. const url = `/organizations/${org.slug}/code-mappings/${pathConfig1.id}/`;
  124. const editMock = MockApiClient.addMockResponse({
  125. url,
  126. method: 'PUT',
  127. body: TestStubs.RepositoryProjectPathConfig({
  128. project: projects[0],
  129. repo: repos[0],
  130. integration,
  131. stackRoot,
  132. sourceRoot,
  133. defaultBranch,
  134. }),
  135. });
  136. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  137. const {waitForModalToHide} = renderGlobalModal();
  138. userEvent.click(screen.getAllByRole('button', {name: 'edit'})[0]);
  139. userEvent.clear(screen.getByRole('textbox', {name: 'Stack Trace Root'}));
  140. userEvent.type(screen.getByRole('textbox', {name: 'Stack Trace Root'}), stackRoot);
  141. userEvent.click(screen.getByRole('button', {name: 'Save Changes'}));
  142. await waitForModalToHide();
  143. expect(editMock).toHaveBeenCalledWith(
  144. url,
  145. expect.objectContaining({
  146. data: expect.objectContaining({
  147. defaultBranch,
  148. projectId: '2',
  149. repositoryId: '4',
  150. sourceRoot,
  151. stackRoot,
  152. }),
  153. })
  154. );
  155. });
  156. it('switches default branch to the repo defaultBranch', async () => {
  157. MockApiClient.addMockResponse({
  158. url: `/organizations/${org.slug}/integrations/${integration.id}/repos/`,
  159. body: {
  160. repos: [
  161. {
  162. id: repos[0].id,
  163. identifier: repos[1].name,
  164. defaultBranch: 'main',
  165. },
  166. ],
  167. },
  168. });
  169. render(<IntegrationCodeMappings organization={org} integration={integration} />);
  170. renderGlobalModal();
  171. userEvent.click(screen.getByRole('button', {name: 'Add Code Mapping'}));
  172. expect(screen.getByRole('textbox', {name: 'Branch'})).toHaveValue('master');
  173. await selectEvent.select(screen.getByText('Choose repo'), repos[1].name);
  174. await waitFor(() => {
  175. expect(screen.getByRole('textbox', {name: 'Branch'})).toHaveValue('main');
  176. });
  177. });
  178. });