projectSourceMaps.spec.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {mountGlobalModal} from 'sentry-test/modal';
  4. import ProjectSourceMapsDetail from 'sentry/views/settings/projectSourceMaps/detail';
  5. import ProjectSourceMaps from 'sentry/views/settings/projectSourceMaps/list';
  6. describe('ProjectSourceMaps', function () {
  7. const {organization, project, routerContext, router} = initializeOrg({});
  8. const endpoint = `/projects/${organization.slug}/${project.slug}/files/source-maps/`;
  9. const props = {
  10. organization,
  11. project,
  12. params: {orgId: organization.slug, projectId: project.slug},
  13. location: routerContext.context.location,
  14. router,
  15. };
  16. it('renders', function () {
  17. MockApiClient.addMockResponse({
  18. url: endpoint,
  19. body: [
  20. TestStubs.SourceMapArchive(),
  21. TestStubs.SourceMapArchive({id: 2, name: 'abc'}),
  22. ],
  23. });
  24. const wrapper = mountWithTheme(<ProjectSourceMaps {...props} />);
  25. const items = wrapper.find('SourceMapsArchiveRow');
  26. expect(items).toHaveLength(2);
  27. expect(items.at(0).find('VersionText').text()).toBe('1234');
  28. });
  29. it('renders empty', function () {
  30. MockApiClient.addMockResponse({
  31. url: endpoint,
  32. body: [],
  33. });
  34. const wrapper = mountWithTheme(<ProjectSourceMaps {...props} />);
  35. expect(wrapper.find('EmptyStateWarning').text()).toBe(
  36. 'There are no archives for this project.'
  37. );
  38. });
  39. it('deletes the archive', async function () {
  40. const archive = TestStubs.SourceMapArchive();
  41. MockApiClient.addMockResponse({
  42. url: endpoint,
  43. body: [archive],
  44. });
  45. const deleteMock = MockApiClient.addMockResponse({
  46. method: 'DELETE',
  47. url: endpoint,
  48. });
  49. const wrapper = mountWithTheme(<ProjectSourceMaps {...props} />);
  50. wrapper.find('button[aria-label="Remove All Artifacts"]').simulate('click');
  51. // Confirm Modal
  52. const modal = await mountGlobalModal();
  53. modal.find('Button[data-test-id="confirm-button"]').simulate('click');
  54. expect(deleteMock).toHaveBeenCalledWith(
  55. endpoint,
  56. expect.objectContaining({query: {name: archive.name}})
  57. );
  58. });
  59. it('filters archives', function () {
  60. const mockRouter = {push: jest.fn()};
  61. const mock = MockApiClient.addMockResponse({
  62. url: endpoint,
  63. body: [],
  64. });
  65. const wrapper = mountWithTheme(
  66. <ProjectSourceMaps
  67. {...props}
  68. location={{query: {query: 'abc'}}}
  69. router={mockRouter}
  70. />
  71. );
  72. expect(mock).toHaveBeenCalledWith(
  73. endpoint,
  74. expect.objectContaining({
  75. query: {query: 'abc'},
  76. })
  77. );
  78. wrapper
  79. .find('SearchBar input')
  80. .simulate('change', {target: {value: 'defg'}})
  81. .simulate('submit', {preventDefault() {}});
  82. expect(mockRouter.push).toHaveBeenCalledWith({
  83. query: {cursor: undefined, query: 'defg'},
  84. });
  85. });
  86. });
  87. describe('ProjectSourceMapsDetail', function () {
  88. const {organization, project, routerContext, router} = initializeOrg({});
  89. const archiveName = '1234';
  90. const endpoint = `/projects/${organization.slug}/${project.slug}/releases/${archiveName}/files/`;
  91. const props = {
  92. organization,
  93. project,
  94. params: {orgId: organization.slug, projectId: project.slug, name: archiveName},
  95. location: routerContext.context.location,
  96. router,
  97. };
  98. it('renders', function () {
  99. MockApiClient.addMockResponse({
  100. url: endpoint,
  101. body: [
  102. TestStubs.SourceMapArtifact(),
  103. TestStubs.SourceMapArtifact({name: 'abc', id: '2'}),
  104. ],
  105. });
  106. const wrapper = mountWithTheme(<ProjectSourceMapsDetail {...props} />);
  107. const items = wrapper.find('SourceMapsArtifactRow');
  108. expect(items).toHaveLength(2);
  109. expect(items.at(1).find('Name').text()).toBe('abc');
  110. });
  111. it('renders empty', function () {
  112. MockApiClient.addMockResponse({
  113. url: endpoint,
  114. body: [],
  115. });
  116. const wrapper = mountWithTheme(<ProjectSourceMapsDetail {...props} />);
  117. expect(wrapper.find('EmptyStateWarning').text()).toBe(
  118. 'There are no artifacts in this archive.'
  119. );
  120. });
  121. it('links to release', function () {
  122. MockApiClient.addMockResponse({
  123. url: endpoint,
  124. body: [],
  125. });
  126. const wrapper = mountWithTheme(<ProjectSourceMapsDetail {...props} />);
  127. expect(wrapper.find('Link[aria-label="Go to Release"]').prop('to')).toBe(
  128. `/organizations/${organization.slug}/releases/${archiveName}/?project=${project.id}`
  129. );
  130. });
  131. it('deletes all artifacts', async function () {
  132. MockApiClient.addMockResponse({
  133. url: endpoint,
  134. body: [],
  135. });
  136. const archiveDeleteEndpoint = `/projects/${organization.slug}/${project.slug}/files/source-maps/`;
  137. const deleteMock = MockApiClient.addMockResponse({
  138. method: 'DELETE',
  139. url: archiveDeleteEndpoint,
  140. });
  141. const wrapper = mountWithTheme(<ProjectSourceMapsDetail {...props} />);
  142. wrapper.find('button[aria-label="Remove All Artifacts"]').simulate('click');
  143. // Confirm Modal
  144. const modal = await mountGlobalModal();
  145. modal.find('Button[data-test-id="confirm-button"]').simulate('click');
  146. expect(deleteMock).toHaveBeenCalledWith(
  147. archiveDeleteEndpoint,
  148. expect.objectContaining({
  149. query: {name: archiveName},
  150. })
  151. );
  152. });
  153. it('filters artifacts', function () {
  154. const mockRouter = {push: jest.fn()};
  155. const mock = MockApiClient.addMockResponse({
  156. url: endpoint,
  157. body: [],
  158. });
  159. const wrapper = mountWithTheme(
  160. <ProjectSourceMapsDetail
  161. {...props}
  162. location={{query: {query: 'abc'}}}
  163. router={mockRouter}
  164. />
  165. );
  166. expect(mock).toHaveBeenCalledWith(
  167. endpoint,
  168. expect.objectContaining({
  169. query: {query: 'abc'},
  170. })
  171. );
  172. wrapper
  173. .find('SearchBar input')
  174. .simulate('change', {target: {value: 'defg'}})
  175. .simulate('submit', {preventDefault() {}});
  176. expect(mockRouter.push).toHaveBeenCalledWith({
  177. query: {cursor: undefined, query: 'defg'},
  178. });
  179. });
  180. it('deletes single artifact', async function () {
  181. const artifact = TestStubs.SourceMapArtifact();
  182. MockApiClient.addMockResponse({
  183. url: endpoint,
  184. body: [artifact],
  185. });
  186. const deleteMock = MockApiClient.addMockResponse({
  187. method: 'DELETE',
  188. url: `${endpoint}${artifact.id}/`,
  189. });
  190. const wrapper = mountWithTheme(<ProjectSourceMapsDetail {...props} />);
  191. wrapper
  192. .find('SourceMapsArtifactRow button[aria-label="Remove Artifact"]')
  193. .simulate('click');
  194. // Confirm Modal
  195. const modal = await mountGlobalModal();
  196. modal.find('Button[data-test-id="confirm-button"]').simulate('click');
  197. expect(deleteMock).toHaveBeenCalled();
  198. });
  199. });