group.spec.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import {GroupFixture} from 'sentry-fixture/group';
  2. import {ProjectFixture} from 'sentry-fixture/project';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {act, render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
  5. import StreamGroup from 'sentry/components/stream/group';
  6. import GroupStore from 'sentry/stores/groupStore';
  7. import GuideStore from 'sentry/stores/guideStore';
  8. import {EventOrGroupType} from 'sentry/types/event';
  9. import type {Group, GroupStatusResolution, MarkReviewed} from 'sentry/types/group';
  10. import {GroupStatus, PriorityLevel} from 'sentry/types/group';
  11. import {trackAnalytics} from 'sentry/utils/analytics';
  12. jest.mock('sentry/utils/analytics');
  13. describe('StreamGroup', function () {
  14. let group1!: Group;
  15. beforeEach(function () {
  16. group1 = GroupFixture({
  17. id: '1337',
  18. project: ProjectFixture({
  19. id: '13',
  20. slug: 'foo-project',
  21. }),
  22. type: EventOrGroupType.ERROR,
  23. inbox: {
  24. date_added: '2020-11-24T13:17:42.248751Z',
  25. reason: 0,
  26. reason_details: null,
  27. },
  28. });
  29. MockApiClient.addMockResponse({
  30. url: '/organizations/org-slug/projects/',
  31. body: [ProjectFixture({slug: 'foo-project'})],
  32. });
  33. GroupStore.loadInitialData([group1]);
  34. });
  35. afterEach(function () {
  36. jest.mocked(trackAnalytics).mockClear();
  37. GroupStore.reset();
  38. });
  39. it('renders with anchors', async function () {
  40. const {router, organization} = initializeOrg();
  41. render(<StreamGroup id="1337" hasGuideAnchor />, {
  42. router,
  43. organization,
  44. });
  45. expect(await screen.findByTestId('group')).toBeInTheDocument();
  46. expect(GuideStore.state.anchors).toEqual(new Set(['dynamic_counts', 'issue_stream']));
  47. });
  48. it('marks as reviewed', async function () {
  49. const {router, organization} = initializeOrg();
  50. render(
  51. <StreamGroup
  52. id="1337"
  53. query="is:unresolved is:for_review assigned_or_suggested:[me, none]"
  54. />,
  55. {router, organization}
  56. );
  57. expect(await screen.findByTestId('group')).toHaveAttribute(
  58. 'data-test-reviewed',
  59. 'false'
  60. );
  61. const data: MarkReviewed = {inbox: false};
  62. act(() => GroupStore.onUpdate('1337', undefined, data));
  63. act(() => GroupStore.onUpdateSuccess('1337', undefined, data));
  64. // Reviewed only applies styles, difficult to select with RTL
  65. expect(screen.getByTestId('group')).toHaveAttribute('data-test-reviewed', 'true');
  66. });
  67. it('marks as resolved', async function () {
  68. const {router, organization} = initializeOrg();
  69. render(<StreamGroup id="1337" query="is:unresolved" />, {
  70. router,
  71. organization,
  72. });
  73. expect(await screen.findByTestId('group')).toBeInTheDocument();
  74. expect(screen.queryByTestId('resolved-issue')).not.toBeInTheDocument();
  75. const data: GroupStatusResolution = {
  76. status: GroupStatus.RESOLVED,
  77. statusDetails: {},
  78. };
  79. act(() => GroupStore.onUpdate('1337', undefined, data));
  80. act(() => GroupStore.onUpdateSuccess('1337', undefined, data));
  81. expect(screen.getByTestId('resolved-issue')).toBeInTheDocument();
  82. });
  83. it('can change priority', async function () {
  84. MockApiClient.addMockResponse({
  85. url: '/organizations/org-slug/prompts-activity/',
  86. body: {data: {dismissed_ts: null}},
  87. });
  88. const mockModifyGroup = MockApiClient.addMockResponse({
  89. url: '/organizations/org-slug/issues/',
  90. method: 'PUT',
  91. body: {priority: PriorityLevel.HIGH},
  92. });
  93. render(<StreamGroup id="1337" query="is:unresolved" />);
  94. const priorityDropdown = screen.getByRole('button', {name: 'Modify issue priority'});
  95. expect(within(priorityDropdown).getByText('Med')).toBeInTheDocument();
  96. await userEvent.click(priorityDropdown);
  97. await userEvent.click(screen.getByRole('menuitemradio', {name: 'High'}));
  98. expect(within(priorityDropdown).getByText('High')).toBeInTheDocument();
  99. expect(mockModifyGroup).toHaveBeenCalledWith(
  100. '/organizations/org-slug/issues/',
  101. expect.objectContaining({
  102. data: expect.objectContaining({
  103. priority: 'high',
  104. }),
  105. })
  106. );
  107. });
  108. it('tracks clicks from issues stream', async function () {
  109. const {router, organization} = initializeOrg();
  110. render(
  111. <StreamGroup
  112. id="1337"
  113. query="is:unresolved is:for_review assigned_or_suggested:[me, none]"
  114. />,
  115. {router, organization}
  116. );
  117. // skipHover - Prevent stacktrace preview from being rendered
  118. await userEvent.click(screen.getByText('RequestError'), {skipHover: true});
  119. });
  120. it('can select row', async function () {
  121. const {router, organization} = initializeOrg();
  122. render(<StreamGroup id="1337" query="is:unresolved" />, {router, organization});
  123. expect(await screen.findByTestId('group')).toBeInTheDocument();
  124. const checkbox = screen.getByRole('checkbox', {name: 'Select Issue'});
  125. expect(checkbox).not.toBeChecked();
  126. await userEvent.click(checkbox);
  127. expect(checkbox).toBeChecked();
  128. await userEvent.click(checkbox);
  129. expect(checkbox).not.toBeChecked();
  130. });
  131. it('does not error when group is not in GroupStore', function () {
  132. const {router, organization} = initializeOrg();
  133. GroupStore.reset();
  134. const {container} = render(
  135. <StreamGroup
  136. id="1337"
  137. query="is:unresolved is:for_review assigned_or_suggested:[me, none]"
  138. />,
  139. {router, organization}
  140. );
  141. expect(container).toBeEmptyDOMElement();
  142. });
  143. });