addCodeOwnerModal.spec.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import selectEvent from 'react-select-event';
  2. import {GitHubIntegrationFixture} from 'sentry-fixture/githubIntegration';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {ProjectFixture} from 'sentry-fixture/project';
  5. import {RepositoryFixture} from 'sentry-fixture/repository';
  6. import {RepositoryProjectPathConfigFixture} from 'sentry-fixture/repositoryProjectPathConfig';
  7. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  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(screen.getByText('--'), 'example/hello-there');
  75. expect(screen.getByTestId('icon-check-mark')).toBeInTheDocument();
  76. expect(screen.getByRole('button', {name: 'Preview File'})).toHaveAttribute(
  77. 'href',
  78. 'blah'
  79. );
  80. });
  81. it('renders no codeowner file found', async function () {
  82. MockApiClient.addMockResponse({
  83. url: `/organizations/${org.slug}/code-mappings/${codeMapping.id}/codeowners/`,
  84. method: 'GET',
  85. statusCode: 404,
  86. });
  87. render(
  88. <AddCodeOwnerModal
  89. Body={ModalBody}
  90. closeModal={jest.fn()}
  91. CloseButton={makeCloseButton(jest.fn())}
  92. Header={makeClosableHeader(jest.fn())}
  93. Footer={ModalFooter}
  94. organization={org}
  95. project={project}
  96. />
  97. );
  98. await selectEvent.select(screen.getByText('--'), 'example/hello-there');
  99. expect(screen.getByText('No codeowner file found.')).toBeInTheDocument();
  100. });
  101. it('adds codeowner file', async function () {
  102. MockApiClient.addMockResponse({
  103. url: `/organizations/${org.slug}/code-mappings/${codeMapping.id}/codeowners/`,
  104. method: 'GET',
  105. body: {html_url: 'blah', filepath: 'CODEOWNERS', raw: '* @MeredithAnya\n'},
  106. });
  107. const addFileRequest = MockApiClient.addMockResponse({
  108. url: `/projects/${org.slug}/${project.slug}/codeowners/`,
  109. method: 'POST',
  110. body: {},
  111. });
  112. const handleCloseModal = jest.fn();
  113. render(
  114. <AddCodeOwnerModal
  115. Body={ModalBody}
  116. closeModal={handleCloseModal}
  117. CloseButton={makeCloseButton(jest.fn())}
  118. Header={makeClosableHeader(jest.fn())}
  119. Footer={ModalFooter}
  120. organization={org}
  121. project={project}
  122. />
  123. );
  124. await selectEvent.select(screen.getByText('--'), 'example/hello-there');
  125. await userEvent.click(screen.getByRole('button', {name: 'Add File'}));
  126. await waitFor(() => {
  127. expect(addFileRequest).toHaveBeenCalledWith(
  128. `/projects/${org.slug}/${project.slug}/codeowners/`,
  129. expect.objectContaining({
  130. data: {codeMappingId: '2', raw: '* @MeredithAnya\n'},
  131. })
  132. );
  133. });
  134. expect(handleCloseModal).toHaveBeenCalled();
  135. });
  136. });