import {initializeOrg} from 'sentry-test/initializeOrg'; import { render, renderGlobalModal, screen, userEvent, waitFor, within, } from 'sentry-test/reactTestingLibrary'; import {EventAttachments} from 'sentry/components/events/eventAttachments'; describe('EventAttachments', function () { const {routerContext, organization, project} = initializeOrg({ organization: { features: ['event-attachments'], orgRole: 'member', attachmentsRole: 'member', }, } as any); const event = TestStubs.Event({metadata: {stripped_crash: false}}); const props = { projectSlug: project.slug, event, }; const attachmentsUrl = `/projects/${organization.slug}/${project.slug}/events/${event.id}/attachments/`; beforeEach(() => { MockApiClient.clearMockResponses(); }); it('shows attachments limit reached notice with stripped_crash: true', async function () { MockApiClient.addMockResponse({ url: attachmentsUrl, body: [], }); const strippedCrashEvent = {...event, metadata: {stripped_crash: true}}; render(, { context: routerContext, organization, }); expect(await screen.findByText('Attachments (0)')).toBeInTheDocument(); await tick(); expect(screen.getByRole('link', {name: 'View crashes'})).toHaveAttribute( 'href', '/organizations/org-slug/issues/1/attachments/?types=event.minidump&types=event.applecrashreport' ); expect(screen.getByRole('link', {name: 'configure limit'})).toHaveAttribute( 'href', `/settings/org-slug/projects/${props.projectSlug}/security-and-privacy/` ); expect( screen.getByText( 'Your limit of stored crash reports has been reached for this issue.', {exact: false} ) ).toBeInTheDocument(); }); it('does not render anything if no attachments (nor stripped) are available', async function () { MockApiClient.addMockResponse({ url: attachmentsUrl, body: [], }); const {container} = render( , {context: routerContext, organization} ); // No loading state to wait for await tick(); expect(container).toBeEmptyDOMElement(); }); it('displays message when user lacks permission to preview an attachment', async function () { const {routerContext: newRouterContext, organization: orgWithWrongAttachmentRole} = initializeOrg({ organization: { features: ['event-attachments'], orgRole: 'member', attachmentsRole: 'admin', }, } as any); const attachment = TestStubs.EventAttachment({ name: 'some_file.txt', headers: { 'Content-Type': 'text/plain', }, mimetype: 'text/plain', size: 100, }); MockApiClient.addMockResponse({ url: attachmentsUrl, body: [attachment], }); MockApiClient.addMockResponse({ url: `/projects/org-slug/events/${event.id}/attachments/?download`, body: 'file contents', }); render(, { context: newRouterContext, organization: orgWithWrongAttachmentRole, }); expect(await screen.findByText('Attachments (1)')).toBeInTheDocument(); expect(screen.getByRole('button', {name: /preview/i})).toBeDisabled(); await userEvent.hover(screen.getByRole('button', {name: /preview/i})); await screen.findByText(/insufficient permissions to preview attachments/i); }); it('can open attachment previews', async function () { const attachment = TestStubs.EventAttachment({ name: 'some_file.txt', headers: { 'Content-Type': 'text/plain', }, mimetype: 'text/plain', size: 100, }); MockApiClient.addMockResponse({ url: attachmentsUrl, body: [attachment], }); MockApiClient.addMockResponse({ url: '/projects/org-slug/project-slug/events/1/attachments/1/?download', body: 'file contents', }); render(, {context: routerContext, organization}); expect(await screen.findByText('Attachments (1)')).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: /preview/i})); expect(screen.getByText('file contents')).toBeInTheDocument(); }); it('can delete attachments', async function () { const attachment1 = TestStubs.EventAttachment({ id: '1', name: 'pic_1.png', }); const attachment2 = TestStubs.EventAttachment({ id: '2', name: 'pic_2.png', }); MockApiClient.addMockResponse({ url: attachmentsUrl, body: [attachment1, attachment2], }); const deleteMock = MockApiClient.addMockResponse({ url: '/projects/org-slug/project-slug/events/1/attachments/1/', method: 'DELETE', }); render(, {context: routerContext, organization}); renderGlobalModal(); expect(await screen.findByText('Attachments (2)')).toBeInTheDocument(); await userEvent.click(screen.getAllByRole('button', {name: 'Delete'})[0]); await userEvent.click( within(screen.getByRole('dialog')).getByRole('button', {name: /delete/i}) ); // Should make the delete request and remove the attachment optimistically await waitFor(() => { expect(deleteMock).toHaveBeenCalled(); expect(screen.queryByTestId('pic_1.png')).not.toBeInTheDocument(); }); }); });