import {GroupFixture} from 'sentry-fixture/group'; import {ProjectFixture} from 'sentry-fixture/project'; import {UserFixture} from 'sentry-fixture/user'; import { render, renderGlobalModal, screen, userEvent, } from 'sentry-test/reactTestingLibrary'; import ConfigStore from 'sentry/stores/configStore'; import GroupStore from 'sentry/stores/groupStore'; import ProjectsStore from 'sentry/stores/projectsStore'; import type {GroupActivity} from 'sentry/types/group'; import {GroupActivityType} from 'sentry/types/group'; import StreamlinedActivitySection from 'sentry/views/issueDetails/streamline/sidebar/activitySection'; describe('StreamlinedActivitySection', function () { const project = ProjectFixture(); const user = UserFixture(); user.options.prefersIssueDetailsStreamlinedUI = true; ConfigStore.set('user', user); ProjectsStore.loadInitialData([project]); GroupStore.init(); const group = GroupFixture({ id: '1337', activity: [ { type: GroupActivityType.NOTE, id: 'note-1', data: {text: 'Test Note'}, dateCreated: '2020-01-01T00:00:00', user: user, project, }, ], project, }); GroupStore.add([group]); beforeEach(() => { jest.restoreAllMocks(); MockApiClient.clearMockResponses(); }); it('renders the input with a comment button', async function () { const comment = 'nice work friends'; const postMock = MockApiClient.addMockResponse({ url: '/organizations/org-slug/issues/1337/comments/', method: 'POST', body: { id: 'note-2', user: UserFixture({id: '2'}), type: 'note', data: {text: comment}, dateCreated: '2024-10-31T00:00:00.000000Z', }, }); render(); const commentInput = screen.getByRole('textbox', {name: 'Add a comment'}); expect(commentInput).toBeInTheDocument(); expect( screen.queryByRole('button', {name: 'Submit comment'}) ).not.toBeInTheDocument(); await userEvent.click(commentInput); // Button appears after input is focused const submitButton = await screen.findByRole('button', {name: 'Submit comment'}); expect(submitButton).toBeInTheDocument(); expect(submitButton).toBeDisabled(); await userEvent.type(commentInput, comment); expect(submitButton).toBeEnabled(); await userEvent.click(submitButton); expect(postMock).toHaveBeenCalled(); }); it('allows submitting the comment field with hotkeys', async function () { const comment = 'nice work friends'; const postMock = MockApiClient.addMockResponse({ url: '/organizations/org-slug/issues/1337/comments/', method: 'POST', body: { id: 'note-3', user: UserFixture({id: '2'}), type: 'note', data: {text: comment}, dateCreated: '2024-10-31T00:00:00.000000Z', }, }); render(); const commentInput = screen.getByRole('textbox', {name: 'Add a comment'}); await userEvent.type(commentInput, comment); await userEvent.keyboard('{Meta>}{Enter}{/Meta}'); expect(postMock).toHaveBeenCalled(); }); it('renders note and allows for delete', async function () { const deleteMock = MockApiClient.addMockResponse({ url: '/organizations/org-slug/issues/1337/comments/note-1/', method: 'DELETE', }); render(); renderGlobalModal(); expect(await screen.findByText('Test Note')).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Comment Actions'})).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'Comment Actions'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Remove'})); expect( screen.getByText('Are you sure you want to remove this comment?') ).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'Remove comment'})); expect(deleteMock).toHaveBeenCalledTimes(1); expect(screen.queryByText('Test Note')).not.toBeInTheDocument(); }); it('renders note but does not allow for deletion if written by someone else', async function () { const updatedActivityGroup = GroupFixture({ id: '1338', activity: [ { type: GroupActivityType.NOTE, id: 'note-1', data: {text: 'Test Note'}, dateCreated: '2020-01-01T00:00:00', user: UserFixture({id: '2'}), project, }, ], project, }); render(); expect(await screen.findByText('Test Note')).toBeInTheDocument(); expect( screen.queryByRole('button', {name: 'Comment Actions'}) ).not.toBeInTheDocument(); }); it('collapses activity when there are more than 5 items', async function () { const activities: GroupActivity[] = Array.from({length: 7}, (_, index) => ({ type: GroupActivityType.NOTE, id: `note-${index + 1}`, data: {text: `Test Note ${index + 1}`}, dateCreated: '2020-01-01T00:00:00', user: UserFixture({id: '2'}), project, })); const updatedActivityGroup = GroupFixture({ id: '1338', activity: activities, project, }); render(); expect(await screen.findByText('Test Note 1')).toBeInTheDocument(); expect(await screen.findByText('Test Note 3')).toBeInTheDocument(); expect(screen.queryByText('Test Note 7')).not.toBeInTheDocument(); expect(await screen.findByText('View 4 more')).toBeInTheDocument(); }); it('does not collapse activity when rendered in the drawer', function () { const activities: GroupActivity[] = Array.from({length: 7}, (_, index) => ({ type: GroupActivityType.NOTE, id: `note-${index + 1}`, data: {text: `Test Note ${index + 1}`}, dateCreated: '2020-01-01T00:00:00', user: UserFixture({id: '2'}), project, })); const updatedActivityGroup = GroupFixture({ id: '1338', activity: activities, project, }); render(); for (const activity of activities) { expect( screen.getByText((activity.data as {text: string}).text) ).toBeInTheDocument(); } expect(screen.queryByRole('button')).not.toBeInTheDocument(); }); });