groupDetails.spec.jsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. import {browserHistory} from 'react-router';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {act, render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import GroupStore from 'sentry/stores/groupStore';
  5. import PageFiltersStore from 'sentry/stores/pageFiltersStore';
  6. import ProjectsStore from 'sentry/stores/projectsStore';
  7. import {IssueCategory} from 'sentry/types';
  8. import {OrganizationContext} from 'sentry/views/organizationContext';
  9. import GroupDetails from 'sentry/views/organizationGroupDetails';
  10. import {RouteContext} from 'sentry/views/routeContext';
  11. jest.unmock('sentry/utils/recreateRoute');
  12. const SAMPLE_EVENT_ALERT_TEXT =
  13. 'You are viewing a sample error. Configure Sentry to start viewing real errors.';
  14. describe('groupDetails', () => {
  15. const group = TestStubs.Group({issueCategory: IssueCategory.ERROR});
  16. const event = TestStubs.Event();
  17. const project = TestStubs.Project({teams: [TestStubs.Team()]});
  18. const selection = {environments: []};
  19. const routes = [
  20. {path: '/', childRoutes: [], component: null},
  21. {childRoutes: [], component: null},
  22. {
  23. path: '/organizations/:orgId/issues/:groupId/',
  24. indexRoute: null,
  25. childRoutes: [],
  26. componentPromise: () => {},
  27. component: null,
  28. },
  29. {
  30. componentPromise: null,
  31. component: null,
  32. },
  33. ];
  34. const {organization, router, routerContext} = initializeOrg({
  35. project,
  36. router: {
  37. location: {
  38. pathname: `/organizations/org-slug/issues/${group.id}/`,
  39. query: {},
  40. search: '?foo=bar',
  41. hash: '#hash',
  42. },
  43. params: {
  44. groupId: group.id,
  45. },
  46. routes,
  47. },
  48. });
  49. function MockComponent({group: groupProp, environments, eventError}) {
  50. return (
  51. <div>
  52. Group Details Mock
  53. <div>title: {groupProp.title}</div>
  54. <div>environment: {environments.join(' ')}</div>
  55. {eventError && <div>eventError</div>}
  56. </div>
  57. );
  58. }
  59. const createWrapper = (props = {selection}) => {
  60. return render(
  61. <RouteContext.Provider
  62. value={{
  63. router,
  64. location: router.location,
  65. params: {},
  66. routes: [],
  67. }}
  68. >
  69. <OrganizationContext.Provider value={organization}>
  70. <GroupDetails {...router} router={router} selection={props.selection}>
  71. <MockComponent />
  72. </GroupDetails>
  73. </OrganizationContext.Provider>
  74. </RouteContext.Provider>,
  75. {context: routerContext}
  76. );
  77. };
  78. beforeEach(() => {
  79. act(() => ProjectsStore.loadInitialData(organization.projects));
  80. MockApiClient.addMockResponse({
  81. url: `/issues/${group.id}/`,
  82. body: {...group},
  83. });
  84. MockApiClient.addMockResponse({
  85. url: `/issues/${group.id}/events/latest/`,
  86. statusCode: 200,
  87. body: {
  88. ...event,
  89. },
  90. });
  91. MockApiClient.addMockResponse({
  92. url: `/projects/org-slug/${project.slug}/issues/`,
  93. method: 'PUT',
  94. body: {
  95. hasSeen: false,
  96. },
  97. });
  98. MockApiClient.addMockResponse({
  99. url: '/organizations/org-slug/projects/',
  100. body: [project],
  101. });
  102. MockApiClient.addMockResponse({
  103. url: '/organizations/org-slug/users/',
  104. body: [],
  105. });
  106. MockApiClient.addMockResponse({
  107. url: `/issues/${group.id}/first-last-release/`,
  108. body: {firstRelease: group.firstRelease, lastRelease: group.lastRelease},
  109. });
  110. MockApiClient.addMockResponse({
  111. url: `/organizations/${organization.slug}/events/`,
  112. statusCode: 200,
  113. body: {
  114. data: [
  115. {
  116. 'count()': 1,
  117. },
  118. ],
  119. },
  120. });
  121. });
  122. afterEach(() => {
  123. act(() => ProjectsStore.reset());
  124. GroupStore.reset();
  125. PageFiltersStore.reset();
  126. MockApiClient.clearMockResponses();
  127. });
  128. it('renders', async function () {
  129. act(() => ProjectsStore.reset());
  130. createWrapper();
  131. expect(screen.queryByText(group.title)).not.toBeInTheDocument();
  132. act(() => ProjectsStore.loadInitialData(organization.projects));
  133. expect(await screen.findByText(group.title, {exact: false})).toBeInTheDocument();
  134. // Sample event alert should not show up
  135. expect(screen.queryByText(SAMPLE_EVENT_ALERT_TEXT)).not.toBeInTheDocument();
  136. });
  137. it('renders error when issue is not found', async function () {
  138. MockApiClient.addMockResponse({
  139. url: `/issues/${group.id}/`,
  140. statusCode: 404,
  141. });
  142. MockApiClient.addMockResponse({
  143. url: `/issues/${group.id}/events/latest/`,
  144. statusCode: 404,
  145. });
  146. createWrapper();
  147. await waitFor(() =>
  148. expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument()
  149. );
  150. expect(
  151. await screen.findByText('The issue you were looking for was not found.')
  152. ).toBeInTheDocument();
  153. });
  154. it('renders MissingProjectMembership when trying to access issue in project the user does not belong to', async function () {
  155. MockApiClient.addMockResponse({
  156. url: `/issues/${group.id}/`,
  157. statusCode: 403,
  158. });
  159. MockApiClient.addMockResponse({
  160. url: `/issues/${group.id}/events/latest/`,
  161. statusCode: 403,
  162. });
  163. createWrapper();
  164. await waitFor(() =>
  165. expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument()
  166. );
  167. expect(
  168. await screen.findByText(
  169. 'No teams have access to this project yet. Ask an admin to add your team to this project.'
  170. )
  171. ).toBeInTheDocument();
  172. });
  173. it('fetches issue details for a given environment', async function () {
  174. createWrapper({
  175. selection: {environments: ['staging']},
  176. });
  177. await waitFor(() =>
  178. expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument()
  179. );
  180. expect(await screen.findByText('environment: staging')).toBeInTheDocument();
  181. });
  182. /**
  183. * This is legacy code that I'm not even sure still happens
  184. */
  185. it('redirects to new issue if params id !== id returned from API request', async function () {
  186. MockApiClient.addMockResponse({
  187. url: `/issues/${group.id}/`,
  188. body: {...group, id: 'new-id'},
  189. });
  190. createWrapper();
  191. expect(screen.queryByText('Group Details Mock')).not.toBeInTheDocument();
  192. await waitFor(() => {
  193. expect(browserHistory.push).toHaveBeenCalledTimes(1);
  194. });
  195. expect(browserHistory.push).toHaveBeenCalledWith(
  196. '/organizations/org-slug/issues/new-id/?foo=bar#hash'
  197. );
  198. });
  199. it('renders issue event error', async function () {
  200. MockApiClient.addMockResponse({
  201. url: `/issues/${group.id}/events/latest/`,
  202. statusCode: 404,
  203. });
  204. createWrapper();
  205. expect(await screen.findByText('eventError')).toBeInTheDocument();
  206. });
  207. it('renders for review reason', async function () {
  208. MockApiClient.addMockResponse({
  209. url: `/issues/${group.id}/`,
  210. body: {
  211. ...group,
  212. inbox: {
  213. date_added: '2020-11-24T13:17:42.248751Z',
  214. reason: 0,
  215. reason_details: null,
  216. },
  217. },
  218. });
  219. act(() => ProjectsStore.reset());
  220. createWrapper();
  221. act(() => ProjectsStore.loadInitialData(organization.projects));
  222. expect(await screen.findByText('New Issue')).toBeInTheDocument();
  223. });
  224. it('renders alert for sample event', async function () {
  225. const sampleGroup = TestStubs.Group({issueCategory: IssueCategory.ERROR});
  226. sampleGroup.tags.push({key: 'sample_event'});
  227. MockApiClient.addMockResponse({
  228. url: `/issues/${group.id}/`,
  229. body: {...sampleGroup},
  230. });
  231. createWrapper();
  232. expect(await screen.findByText(SAMPLE_EVENT_ALERT_TEXT)).toBeInTheDocument();
  233. });
  234. });