import {initializeOrg} from 'sentry-test/initializeOrg'; import { act, render, renderGlobalModal, screen, userEvent, waitFor, } from 'sentry-test/reactTestingLibrary'; import PullRequestLink from 'sentry/components/pullRequestLink'; import ConfigStore from 'sentry/stores/configStore'; import GroupStore from 'sentry/stores/groupStore'; import OrganizationStore from 'sentry/stores/organizationStore'; import ProjectsStore from 'sentry/stores/projectsStore'; import TeamStore from 'sentry/stores/teamStore'; import {GroupActivityType} from 'sentry/types'; import {GroupActivity} from 'sentry/views/issueDetails/groupActivity'; describe('GroupActivity', function () { let project; const dateCreated = '2021-10-01T15:31:38.950115Z'; beforeEach(function () { project = TestStubs.Project(); ProjectsStore.loadInitialData([project]); ConfigStore.init(); ConfigStore.set('user', {id: '123'}); GroupStore.init(); }); afterEach(() => { MockApiClient.clearMockResponses(); jest.clearAllMocks(); }); function createWrapper({activity, organization: additionalOrg} = {}) { const group = TestStubs.Group({ id: '1337', activity: activity ?? [ {type: 'note', id: 'note-1', data: {text: 'Test Note'}, user: TestStubs.User()}, ], project, }); const {organization, routerContext} = initializeOrg({ organization: additionalOrg, group, }); GroupStore.add([group]); TeamStore.loadInitialData([TestStubs.Team({id: '999', slug: 'no-team'})]); OrganizationStore.onUpdate(organization, {replace: true}); return render( , {context: routerContext} ); } it('renders a NoteInput', function () { createWrapper(); expect(screen.getByTestId('activity-note-body')).toBeInTheDocument(); }); it('renders a marked reviewed activity', function () { const user = TestStubs.User({name: 'Samwise'}); createWrapper({ activity: [{type: 'mark_reviewed', id: 'reviewed-1', data: {}, user}], }); expect(screen.getByText('marked this issue as reviewed')).toBeInTheDocument(); expect(screen.getByText(user.name)).toBeInTheDocument(); }); it('renders a pr activity', function () { const user = TestStubs.User({name: 'Test User'}); const repository = TestStubs.Repository(); const pullRequest = TestStubs.PullRequest({message: 'Fixes ISSUE-1'}); createWrapper({ activity: [ { type: 'set_resolved_in_pull_request', id: 'pr-1', data: { pullRequest: { author: 'Test User', version: ( ), repository: {repository}, }, }, user, }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Test User has created a PR for this issue:' ); }); it('renders a assigned to self activity', function () { const user = TestStubs.User({id: '301', name: 'Mark'}); createWrapper({ activity: [ { data: { assignee: user.id, assigneeEmail: user.email, assigneeType: 'user', }, dateCreated: '2021-10-01T15:31:38.950115Z', id: '117', type: 'assigned', user, }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( /Mark assigned this issue to themselves/ ); }); it('renders an assigned via codeowners activity', function () { createWrapper({ activity: [ { data: { assignee: '123', assigneeEmail: 'anotheruser@sentry.io', assigneeType: 'user', integration: 'codeowners', rule: 'path:something/*.py #workflow', }, dateCreated: '2021-10-01T15:31:38.950115Z', id: '117', type: 'assigned', user: null, }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( /Sentry auto-assigned this issue to anotheruser@sentry.io/ ); }); it('renders an assigned via slack activity', function () { const user = TestStubs.User({id: '301', name: 'Mark'}); createWrapper({ activity: [ { data: { assignee: '123', assigneeEmail: 'anotheruser@sentry.io', assigneeType: 'user', integration: 'slack', }, dateCreated: '2021-10-01T15:31:38.950115Z', id: '117', type: 'assigned', user, }, ], }); const item = screen.getAllByTestId('activity-item').at(-1); expect(item).toHaveTextContent(/Mark assigned this issue to anotheruser@sentry.io/); expect(item).toHaveTextContent(/Assigned via Slack/); }); it('resolved in commit with no releases', function () { createWrapper({ activity: [ { type: 'set_resolved_in_commit', id: '123', data: { author: 'hello', commit: { id: 'komal-commit', repository: {}, releases: [], }, }, user: TestStubs.User(), }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar marked this issue as resolved in komal-commit' ); }); it('resolved in commit with one release', function () { createWrapper({ activity: [ { type: 'set_resolved_in_commit', id: '123', data: { author: 'hello', commit: { id: 'komal-commit', repository: {}, releases: [ { dateCreated: '2022-05-01', dateReleased: '2022-05-02', version: 'random', }, ], }, }, user: TestStubs.User(), }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar marked this issue as resolved in komal-commit This commit was released in random' ); }); it('resolved in commit with multiple releases', function () { createWrapper({ activity: [ { type: 'set_resolved_in_commit', id: '123', data: { commit: { id: 'komal-commit', repository: {}, releases: [ { dateCreated: '2022-05-01', dateReleased: '2022-05-02', version: 'random', }, { dateCreated: '2022-06-01', dateReleased: '2022-06-02', version: 'newest', }, { dateCreated: '2021-08-03', dateReleased: '2021-08-03', version: 'oldest-release', }, { dateCreated: '2022-04-21', dateReleased: '2022-04-21', version: 'randomTwo', }, ], }, }, user: TestStubs.User(), }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar marked this issue as resolved in komal-commit This commit was released in oldest-release and 3 others' ); }); it('requests assignees that are not in the team store', async function () { const team = TestStubs.Team({id: '123', name: 'workflow'}); const teamRequest = MockApiClient.addMockResponse({ url: `/organizations/org-slug/teams/`, body: [team], }); createWrapper({ activity: [ { id: '123', user: null, type: 'assigned', data: { assignee: team.id, assigneeEmail: null, assigneeType: 'team', }, dateCreated: '2021-10-28T13:40:10.634821Z', }, ], }); await waitFor(() => expect(teamRequest).toHaveBeenCalledTimes(1)); expect( await screen.findByText(`assigned this issue to #${team.slug}`) ).toBeInTheDocument(); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( /Sentry assigned this issue to #team-slug/ ); }); describe('Delete', function () { let deleteMock; beforeEach(function () { deleteMock = MockApiClient.addMockResponse({ url: '/issues/1337/comments/note-1/', method: 'DELETE', }); ConfigStore.set('user', {id: '123', isSuperuser: true}); }); it('should do nothing if not present in GroupStore', async function () { createWrapper(); renderGlobalModal(); act(() => { // Remove note from group activity GroupStore.removeActivity('1337', 'note-1'); }); await userEvent.click(screen.getByRole('button', {name: 'Comment Actions'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Remove'})); expect( screen.getByText('Are you sure you wish to delete this comment?') ).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'Confirm'})); expect(deleteMock).not.toHaveBeenCalled(); }); it('should remove remove the item from the GroupStore make a DELETE API request', async function () { createWrapper(); renderGlobalModal(); await userEvent.click(screen.getByRole('button', {name: 'Comment Actions'})); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Remove'})); expect( screen.getByText('Are you sure you wish to delete this comment?') ).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'Confirm'})); expect(deleteMock).toHaveBeenCalledTimes(1); }); }); it('renders ignored', function () { createWrapper({ activity: [ { id: '123', type: GroupActivityType.SET_IGNORED, data: { ignoreUntilEscalating: true, }, user: TestStubs.User(), dateCreated, }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar ignored this issue' ); }); it('renders archived until escalating if org has `escalating-issues-ui` feature', function () { createWrapper({ activity: [ { id: '123', type: GroupActivityType.SET_IGNORED, data: { ignoreUntilEscalating: true, }, user: TestStubs.User(), dateCreated, }, ], organization: {features: ['escalating-issues-ui']}, }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar archived this issue until it escalates' ); }); it('renders escalating with forecast and plural events if org has `escalating-issues-ui` feature', function () { createWrapper({ activity: [ { id: '123', type: GroupActivityType.SET_UNRESOLVED, data: { forecast: 200, }, user: null, dateCreated, }, { id: '124', type: GroupActivityType.SET_ESCALATING, data: { forecast: 400, }, user: null, dateCreated: '2021-10-05T15:31:38.950115Z', }, ], organization: {features: ['escalating-issues-ui']}, }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Sentry flagged this issue as escalating because over 400 events happened in an hour' ); expect(screen.getAllByTestId('activity-item').at(-2)).toHaveTextContent( 'Sentry flagged this issue as escalating because over 200 events happened in an hour' ); }); it('renders escalating with forecast and singular event if org has `escalating-issues-ui` feature', function () { createWrapper({ activity: [ { id: '123', type: GroupActivityType.SET_UNRESOLVED, data: { forecast: 1, }, user: null, dateCreated, }, ], organization: {features: ['escalating-issues-ui']}, }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Sentry flagged this issue as escalating because over 1 event happened in an hour' ); }); it('renders ignored until it happens x times in time window', function () { createWrapper({ activity: [ { id: '123', type: GroupActivityType.SET_IGNORED, data: { ignoreCount: 400, ignoreWindow: 1, }, user: TestStubs.User(), dateCreated, }, ], }); expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent( 'Foo Bar ignored this issue until it happens 400 time(s) in 1 minute' ); }); });