addCodeOwnerModal.spec.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import {GitHubIntegrationFixture} from 'sentry-fixture/githubIntegration';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {ProjectFixture} from 'sentry-fixture/project';
  4. import {RepositoryFixture} from 'sentry-fixture/repository';
  5. import {RepositoryProjectPathConfigFixture} from 'sentry-fixture/repositoryProjectPathConfig';
  6. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  7. import selectEvent from 'sentry-test/selectEvent';
  8. import {
  9. makeClosableHeader,
  10. makeCloseButton,
  11. ModalBody,
  12. ModalFooter,
  13. } from 'sentry/components/globalModal/components';
  14. import {AddCodeOwnerModal} from 'sentry/views/settings/project/projectOwnership/addCodeOwnerModal';
  15. describe('AddCodeOwnerModal', function () {
  16. const org = OrganizationFixture({features: ['integrations-codeowners']});
  17. const project = ProjectFixture();
  18. const integration = GitHubIntegrationFixture();
  19. const repo = RepositoryFixture({
  20. integrationId: integration.id,
  21. id: '5',
  22. name: 'example/hello-there',
  23. });
  24. const codeMapping = RepositoryProjectPathConfigFixture({
  25. project,
  26. repo,
  27. integration,
  28. stackRoot: 'stack/root',
  29. sourceRoot: 'source/root',
  30. });
  31. beforeEach(function () {
  32. MockApiClient.addMockResponse({
  33. url: `/organizations/${org.slug}/code-mappings/`,
  34. method: 'GET',
  35. body: [codeMapping],
  36. });
  37. MockApiClient.addMockResponse({
  38. url: `/organizations/${org.slug}/integrations/`,
  39. method: 'GET',
  40. body: [integration],
  41. });
  42. });
  43. it('renders', function () {
  44. render(
  45. <AddCodeOwnerModal
  46. Body={ModalBody}
  47. closeModal={jest.fn()}
  48. CloseButton={makeCloseButton(jest.fn())}
  49. Header={makeClosableHeader(jest.fn())}
  50. Footer={ModalFooter}
  51. organization={org}
  52. project={project}
  53. />
  54. );
  55. expect(screen.getByRole('button', {name: 'Add File'})).toBeDisabled();
  56. });
  57. it('renders codeowner file', async function () {
  58. MockApiClient.addMockResponse({
  59. url: `/organizations/${org.slug}/code-mappings/${codeMapping.id}/codeowners/`,
  60. method: 'GET',
  61. body: {html_url: 'blah', filepath: 'CODEOWNERS', raw: '* @MeredithAnya\n'},
  62. });
  63. render(
  64. <AddCodeOwnerModal
  65. Body={ModalBody}
  66. closeModal={jest.fn()}
  67. CloseButton={makeCloseButton(jest.fn())}
  68. Header={makeClosableHeader(jest.fn())}
  69. Footer={ModalFooter}
  70. organization={org}
  71. project={project}
  72. />
  73. );
  74. await selectEvent.select(
  75. screen.getByText('--'),
  76. `Repo Name: ${codeMapping.repoName}, Stack Trace Root: ${codeMapping.stackRoot}, Source Code Root: ${codeMapping.sourceRoot}`
  77. );
  78. expect(screen.getByTestId('icon-check-mark')).toBeInTheDocument();
  79. expect(screen.getByRole('button', {name: 'Preview File'})).toHaveAttribute(
  80. 'href',
  81. 'blah'
  82. );
  83. });
  84. it('renders no codeowner file found', async function () {
  85. MockApiClient.addMockResponse({
  86. url: `/organizations/${org.slug}/code-mappings/${codeMapping.id}/codeowners/`,
  87. method: 'GET',
  88. statusCode: 404,
  89. });
  90. render(
  91. <AddCodeOwnerModal
  92. Body={ModalBody}
  93. closeModal={jest.fn()}
  94. CloseButton={makeCloseButton(jest.fn())}
  95. Header={makeClosableHeader(jest.fn())}
  96. Footer={ModalFooter}
  97. organization={org}
  98. project={project}
  99. />
  100. );
  101. await selectEvent.select(
  102. screen.getByText('--'),
  103. `Repo Name: ${codeMapping.repoName}, Stack Trace Root: ${codeMapping.stackRoot}, Source Code Root: ${codeMapping.sourceRoot}`
  104. );
  105. expect(screen.getByText('No codeowner file found.')).toBeInTheDocument();
  106. });
  107. it('adds codeowner file', async function () {
  108. MockApiClient.addMockResponse({
  109. url: `/organizations/${org.slug}/code-mappings/${codeMapping.id}/codeowners/`,
  110. method: 'GET',
  111. body: {html_url: 'blah', filepath: 'CODEOWNERS', raw: '* @MeredithAnya\n'},
  112. });
  113. const addFileRequest = MockApiClient.addMockResponse({
  114. url: `/projects/${org.slug}/${project.slug}/codeowners/`,
  115. method: 'POST',
  116. body: {},
  117. });
  118. const handleCloseModal = jest.fn();
  119. render(
  120. <AddCodeOwnerModal
  121. Body={ModalBody}
  122. closeModal={handleCloseModal}
  123. CloseButton={makeCloseButton(jest.fn())}
  124. Header={makeClosableHeader(jest.fn())}
  125. Footer={ModalFooter}
  126. organization={org}
  127. project={project}
  128. />
  129. );
  130. await selectEvent.select(
  131. screen.getByText('--'),
  132. `Repo Name: ${codeMapping.repoName}, Stack Trace Root: ${codeMapping.stackRoot}, Source Code Root: ${codeMapping.sourceRoot}`
  133. );
  134. await userEvent.click(screen.getByRole('button', {name: 'Add File'}));
  135. await waitFor(() => {
  136. expect(addFileRequest).toHaveBeenCalledWith(
  137. `/projects/${org.slug}/${project.slug}/codeowners/`,
  138. expect.objectContaining({
  139. data: {codeMappingId: '2', raw: '* @MeredithAnya\n'},
  140. })
  141. );
  142. });
  143. expect(handleCloseModal).toHaveBeenCalled();
  144. });
  145. });