groupActivity.spec.jsx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {
  3. act,
  4. render,
  5. renderGlobalModal,
  6. screen,
  7. userEvent,
  8. waitFor,
  9. } from 'sentry-test/reactTestingLibrary';
  10. import ConfigStore from 'sentry/stores/configStore';
  11. import GroupStore from 'sentry/stores/groupStore';
  12. import OrganizationStore from 'sentry/stores/organizationStore';
  13. import ProjectsStore from 'sentry/stores/projectsStore';
  14. import TeamStore from 'sentry/stores/teamStore';
  15. import {GroupActivity} from 'sentry/views/organizationGroupDetails/groupActivity';
  16. describe('GroupActivity', function () {
  17. let project;
  18. beforeEach(function () {
  19. project = TestStubs.Project();
  20. ProjectsStore.loadInitialData([project]);
  21. ConfigStore.init();
  22. ConfigStore.set('user', {id: '123'});
  23. GroupStore.init();
  24. });
  25. afterEach(() => {
  26. MockApiClient.clearMockResponses();
  27. jest.clearAllMocks();
  28. ProjectsStore.teardown();
  29. });
  30. function createWrapper({activity, organization: additionalOrg} = {}) {
  31. const group = TestStubs.Group({
  32. id: '1337',
  33. activity: activity ?? [
  34. {type: 'note', id: 'note-1', data: {text: 'Test Note'}, user: TestStubs.User()},
  35. ],
  36. project,
  37. });
  38. const {organization, routerContext} = initializeOrg({
  39. organization: additionalOrg,
  40. group,
  41. });
  42. GroupStore.add([group]);
  43. TeamStore.loadInitialData([TestStubs.Team({id: '999', slug: 'no-team'})]);
  44. OrganizationStore.onUpdate(organization, {replace: true});
  45. return render(
  46. <GroupActivity
  47. api={new MockApiClient()}
  48. params={{orgId: 'org-slug'}}
  49. group={group}
  50. organization={organization}
  51. />,
  52. {context: routerContext}
  53. );
  54. }
  55. it('renders a NoteInput', function () {
  56. createWrapper();
  57. expect(screen.getByTestId('activity-note-body')).toBeInTheDocument();
  58. });
  59. it('renders a marked reviewed activity', function () {
  60. const user = TestStubs.User({name: 'Samwise'});
  61. createWrapper({
  62. activity: [{type: 'mark_reviewed', id: 'reviewed-1', data: {}, user}],
  63. });
  64. expect(screen.getByText('marked this issue as reviewed')).toBeInTheDocument();
  65. expect(screen.getByText(user.name)).toBeInTheDocument();
  66. });
  67. it('renders a assigned to self activity', function () {
  68. const user = TestStubs.User({id: '301', name: 'Mark'});
  69. createWrapper({
  70. activity: [
  71. {
  72. data: {
  73. assignee: user.id,
  74. assigneeEmail: user.email,
  75. assigneeType: 'user',
  76. },
  77. dateCreated: '2021-10-01T15:31:38.950115Z',
  78. id: '117',
  79. type: 'assigned',
  80. user,
  81. },
  82. ],
  83. });
  84. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  85. /Mark assigned this issue to themselves/
  86. );
  87. });
  88. it('renders an assigned via codeowners activity', function () {
  89. createWrapper({
  90. activity: [
  91. {
  92. data: {
  93. assignee: '123',
  94. assigneeEmail: 'anotheruser@sentry.io',
  95. assigneeType: 'user',
  96. integration: 'codeowners',
  97. rule: 'path:something/*.py #workflow',
  98. },
  99. dateCreated: '2021-10-01T15:31:38.950115Z',
  100. id: '117',
  101. type: 'assigned',
  102. user: null,
  103. },
  104. ],
  105. });
  106. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  107. /Sentry auto-assigned this issue to anotheruser@sentry.io/
  108. );
  109. });
  110. it('renders an assigned via slack activity', function () {
  111. const user = TestStubs.User({id: '301', name: 'Mark'});
  112. createWrapper({
  113. activity: [
  114. {
  115. data: {
  116. assignee: '123',
  117. assigneeEmail: 'anotheruser@sentry.io',
  118. assigneeType: 'user',
  119. integration: 'slack',
  120. },
  121. dateCreated: '2021-10-01T15:31:38.950115Z',
  122. id: '117',
  123. type: 'assigned',
  124. user,
  125. },
  126. ],
  127. });
  128. const item = screen.getAllByTestId('activity-item').at(-1);
  129. expect(item).toHaveTextContent(/Mark assigned this issue to anotheruser@sentry.io/);
  130. expect(item).toHaveTextContent(/Assigned via Slack/);
  131. });
  132. it('resolved in commit with no releases', function () {
  133. createWrapper({
  134. activity: [
  135. {
  136. type: 'set_resolved_in_commit',
  137. id: '123',
  138. data: {
  139. author: 'hello',
  140. commit: {
  141. id: 'komal-commit',
  142. repository: {},
  143. releases: [],
  144. },
  145. },
  146. user: TestStubs.User(),
  147. },
  148. ],
  149. });
  150. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  151. 'Foo Bar marked this issue as resolved in komal-commit'
  152. );
  153. });
  154. it('resolved in commit with one release', function () {
  155. createWrapper({
  156. activity: [
  157. {
  158. type: 'set_resolved_in_commit',
  159. id: '123',
  160. data: {
  161. author: 'hello',
  162. commit: {
  163. id: 'komal-commit',
  164. repository: {},
  165. releases: [
  166. {
  167. dateCreated: '2022-05-01',
  168. dateReleased: '2022-05-02',
  169. version: 'random',
  170. },
  171. ],
  172. },
  173. },
  174. user: TestStubs.User(),
  175. },
  176. ],
  177. });
  178. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  179. 'Foo Bar marked this issue as resolved in komal-commit This commit was released in random'
  180. );
  181. });
  182. it('resolved in commit with multiple releases', function () {
  183. createWrapper({
  184. activity: [
  185. {
  186. type: 'set_resolved_in_commit',
  187. id: '123',
  188. data: {
  189. commit: {
  190. id: 'komal-commit',
  191. repository: {},
  192. releases: [
  193. {
  194. dateCreated: '2022-05-01',
  195. dateReleased: '2022-05-02',
  196. version: 'random',
  197. },
  198. {
  199. dateCreated: '2022-06-01',
  200. dateReleased: '2022-06-02',
  201. version: 'newest',
  202. },
  203. {
  204. dateCreated: '2021-08-03',
  205. dateReleased: '2021-08-03',
  206. version: 'oldest-release',
  207. },
  208. {
  209. dateCreated: '2022-04-21',
  210. dateReleased: '2022-04-21',
  211. version: 'randomTwo',
  212. },
  213. ],
  214. },
  215. },
  216. user: TestStubs.User(),
  217. },
  218. ],
  219. });
  220. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  221. 'Foo Bar marked this issue as resolved in komal-commit This commit was released in oldest-release and 3 others'
  222. );
  223. });
  224. it('requests assignees that are not in the team store', async function () {
  225. const team = TestStubs.Team({id: '123', name: 'workflow'});
  226. const teamRequest = MockApiClient.addMockResponse({
  227. url: `/organizations/org-slug/teams/`,
  228. body: [team],
  229. });
  230. createWrapper({
  231. activity: [
  232. {
  233. id: '123',
  234. user: null,
  235. type: 'assigned',
  236. data: {
  237. assignee: team.id,
  238. assigneeEmail: null,
  239. assigneeType: 'team',
  240. },
  241. dateCreated: '2021-10-28T13:40:10.634821Z',
  242. },
  243. ],
  244. });
  245. await waitFor(() => expect(teamRequest).toHaveBeenCalledTimes(1));
  246. expect(await screen.findByText(`#${team.slug}`)).toBeInTheDocument();
  247. expect(screen.getAllByTestId('activity-item').at(-1)).toHaveTextContent(
  248. /Sentry assigned this issue to #team-slug/
  249. );
  250. });
  251. describe('Delete', function () {
  252. let deleteMock;
  253. beforeEach(function () {
  254. deleteMock = MockApiClient.addMockResponse({
  255. url: '/issues/1337/comments/note-1/',
  256. method: 'DELETE',
  257. });
  258. ConfigStore.set('user', {id: '123', isSuperuser: true});
  259. });
  260. it('should do nothing if not present in GroupStore', function () {
  261. createWrapper();
  262. renderGlobalModal();
  263. act(() => {
  264. // Remove note from group activity
  265. GroupStore.removeActivity('1337', 'note-1');
  266. });
  267. userEvent.click(screen.getByText('Remove'));
  268. expect(
  269. screen.getByText('Are you sure you wish to delete this comment?')
  270. ).toBeInTheDocument();
  271. userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
  272. expect(deleteMock).not.toHaveBeenCalled();
  273. });
  274. it('should remove remove the item from the GroupStore make a DELETE API request', function () {
  275. createWrapper();
  276. renderGlobalModal();
  277. userEvent.click(screen.getByText('Remove'));
  278. expect(
  279. screen.getByText('Are you sure you wish to delete this comment?')
  280. ).toBeInTheDocument();
  281. userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
  282. expect(deleteMock).toHaveBeenCalledTimes(1);
  283. });
  284. });
  285. });