eventAttachments.spec.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import {EventFixture} from 'sentry-fixture/event';
  2. import {EventAttachmentFixture} from 'sentry-fixture/eventAttachment';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {
  5. render,
  6. renderGlobalModal,
  7. screen,
  8. userEvent,
  9. waitFor,
  10. within,
  11. } from 'sentry-test/reactTestingLibrary';
  12. import {EventAttachments} from 'sentry/components/events/eventAttachments';
  13. describe('EventAttachments', function () {
  14. const {router, organization, project} = initializeOrg({
  15. organization: {
  16. features: ['event-attachments'],
  17. orgRole: 'member',
  18. attachmentsRole: 'member',
  19. },
  20. } as any);
  21. const event = EventFixture({metadata: {stripped_crash: false}});
  22. const props = {
  23. projectSlug: project.slug,
  24. event,
  25. };
  26. const attachmentsUrl = `/projects/${organization.slug}/${project.slug}/events/${event.id}/attachments/`;
  27. beforeEach(() => {
  28. MockApiClient.clearMockResponses();
  29. });
  30. it('shows attachments limit reached notice with stripped_crash: true', async function () {
  31. MockApiClient.addMockResponse({
  32. url: attachmentsUrl,
  33. body: [],
  34. });
  35. const strippedCrashEvent = {...event, metadata: {stripped_crash: true}};
  36. render(<EventAttachments {...props} event={strippedCrashEvent} />, {
  37. router,
  38. organization,
  39. });
  40. expect(await screen.findByText('Attachments (0)')).toBeInTheDocument();
  41. await tick();
  42. expect(screen.getByRole('link', {name: 'View crashes'})).toHaveAttribute(
  43. 'href',
  44. '/organizations/org-slug/issues/1/attachments/?types=event.minidump&types=event.applecrashreport'
  45. );
  46. expect(screen.getByRole('link', {name: 'configure limit'})).toHaveAttribute(
  47. 'href',
  48. `/settings/org-slug/projects/${props.projectSlug}/security-and-privacy/`
  49. );
  50. expect(
  51. screen.getByText(
  52. 'Your limit of stored crash reports has been reached for this issue.',
  53. {exact: false}
  54. )
  55. ).toBeInTheDocument();
  56. });
  57. it('does not render anything if no attachments (nor stripped) are available', async function () {
  58. MockApiClient.addMockResponse({
  59. url: attachmentsUrl,
  60. body: [],
  61. });
  62. const {container} = render(
  63. <EventAttachments
  64. {...props}
  65. event={{...event, metadata: {stripped_crash: false}}}
  66. />,
  67. {router, organization}
  68. );
  69. // No loading state to wait for
  70. await tick();
  71. expect(container).toBeEmptyDOMElement();
  72. });
  73. it('displays message when user lacks permission to preview an attachment', async function () {
  74. const {router: newRouter, organization: orgWithWrongAttachmentRole} = initializeOrg({
  75. organization: {
  76. features: ['event-attachments'],
  77. orgRole: 'member',
  78. attachmentsRole: 'admin',
  79. },
  80. } as any);
  81. const attachment = EventAttachmentFixture({
  82. name: 'some_file.txt',
  83. headers: {
  84. 'Content-Type': 'text/plain',
  85. },
  86. mimetype: 'text/plain',
  87. size: 100,
  88. });
  89. MockApiClient.addMockResponse({
  90. url: attachmentsUrl,
  91. body: [attachment],
  92. });
  93. MockApiClient.addMockResponse({
  94. url: `/projects/org-slug/events/${event.id}/attachments/?download`,
  95. body: 'file contents',
  96. });
  97. render(<EventAttachments {...props} />, {
  98. router: newRouter,
  99. organization: orgWithWrongAttachmentRole,
  100. });
  101. expect(await screen.findByText('Attachments (1)')).toBeInTheDocument();
  102. expect(screen.getByRole('button', {name: /preview/i})).toBeDisabled();
  103. await userEvent.hover(screen.getByRole('button', {name: /preview/i}));
  104. await screen.findByText(/insufficient permissions to preview attachments/i);
  105. });
  106. it('can open attachment previews', async function () {
  107. const attachment = EventAttachmentFixture({
  108. name: 'some_file.txt',
  109. headers: {
  110. 'Content-Type': 'text/plain',
  111. },
  112. mimetype: 'text/plain',
  113. size: 100,
  114. });
  115. MockApiClient.addMockResponse({
  116. url: attachmentsUrl,
  117. body: [attachment],
  118. });
  119. MockApiClient.addMockResponse({
  120. url: '/projects/org-slug/project-slug/events/1/attachments/1/?download',
  121. body: 'file contents',
  122. });
  123. render(<EventAttachments {...props} />, {router, organization});
  124. expect(await screen.findByText('Attachments (1)')).toBeInTheDocument();
  125. await userEvent.click(screen.getByRole('button', {name: /preview/i}));
  126. expect(await screen.findByText('file contents')).toBeInTheDocument();
  127. });
  128. it('can delete attachments', async function () {
  129. const attachment1 = EventAttachmentFixture({
  130. id: '1',
  131. name: 'pic_1.png',
  132. });
  133. const attachment2 = EventAttachmentFixture({
  134. id: '2',
  135. name: 'pic_2.png',
  136. });
  137. MockApiClient.addMockResponse({
  138. url: attachmentsUrl,
  139. body: [attachment1, attachment2],
  140. });
  141. const deleteMock = MockApiClient.addMockResponse({
  142. url: '/projects/org-slug/project-slug/events/1/attachments/1/',
  143. method: 'DELETE',
  144. });
  145. render(<EventAttachments {...props} />, {router, organization});
  146. renderGlobalModal();
  147. expect(await screen.findByText('Attachments (2)')).toBeInTheDocument();
  148. await userEvent.click(screen.getAllByRole('button', {name: 'Delete'})[0]);
  149. await userEvent.click(
  150. within(screen.getByRole('dialog')).getByRole('button', {name: /delete/i})
  151. );
  152. // Should make the delete request and remove the attachment optimistically
  153. await waitFor(() => {
  154. expect(deleteMock).toHaveBeenCalled();
  155. expect(screen.queryByTestId('pic_1.png')).not.toBeInTheDocument();
  156. });
  157. });
  158. });