index.spec.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import {GroupFixture} from 'sentry-fixture/group';
  2. import {LocationFixture} from 'sentry-fixture/locationFixture';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {ProjectFixture} from 'sentry-fixture/project';
  5. import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
  6. import {initializeOrg} from 'sentry-test/initializeOrg';
  7. import {act, render, screen} from 'sentry-test/reactTestingLibrary';
  8. import ProjectsStore from 'sentry/stores/projectsStore';
  9. import EventView from 'sentry/utils/discover/eventView';
  10. import {ALL_VIEWS, DEFAULT_EVENT_VIEW} from 'sentry/views/discover/data';
  11. import EventDetails from 'sentry/views/discover/eventDetails';
  12. describe('Discover > EventDetails', function () {
  13. const allEventsView = EventView.fromSavedQuery(DEFAULT_EVENT_VIEW);
  14. const errorsView = EventView.fromSavedQuery(
  15. ALL_VIEWS.find(view => view.name === 'Errors by Title')!
  16. );
  17. beforeEach(function () {
  18. act(() => ProjectsStore.loadInitialData([ProjectFixture()]));
  19. MockApiClient.addMockResponse({
  20. url: '/organizations/org-slug/projects/',
  21. body: [],
  22. });
  23. MockApiClient.addMockResponse({
  24. url: '/organizations/org-slug/discover/',
  25. body: {
  26. meta: {
  27. id: 'string',
  28. title: 'string',
  29. 'project.name': 'string',
  30. timestamp: 'date',
  31. },
  32. data: [
  33. {
  34. id: 'deadbeef',
  35. title: 'Oh no something bad',
  36. 'project.name': 'project-slug',
  37. timestamp: '2019-05-23T22:12:48+00:00',
  38. },
  39. ],
  40. },
  41. });
  42. MockApiClient.addMockResponse({
  43. url: '/organizations/org-slug/events/project-slug:deadbeef/',
  44. method: 'GET',
  45. body: {
  46. id: '1234',
  47. size: 1200,
  48. projectSlug: 'project-slug',
  49. eventID: 'deadbeef',
  50. groupID: '123',
  51. title: 'Oh no something bad',
  52. location: '/users/login',
  53. message: 'It was not good',
  54. dateCreated: '2019-05-23T22:12:48+00:00',
  55. entries: [
  56. {
  57. type: 'message',
  58. message: 'bad stuff',
  59. data: {},
  60. },
  61. ],
  62. tags: [
  63. {key: 'browser', value: 'Firefox'},
  64. {key: 'device.uuid', value: 'test-uuid'},
  65. {key: 'release', value: '82ebf297206a'},
  66. ],
  67. },
  68. });
  69. MockApiClient.addMockResponse({
  70. url: '/issues/123/',
  71. method: 'GET',
  72. body: GroupFixture({id: '123'}),
  73. });
  74. MockApiClient.addMockResponse({
  75. url: '/organizations/org-slug/events-stats/',
  76. method: 'GET',
  77. body: {
  78. data: [
  79. [1234561700, [1]],
  80. [1234561800, [1]],
  81. ],
  82. },
  83. });
  84. MockApiClient.addMockResponse({
  85. url: '/projects/org-slug/project-slug/events/1234/committers/',
  86. method: 'GET',
  87. statusCode: 404,
  88. body: {},
  89. });
  90. MockApiClient.addMockResponse({
  91. url: '/projects/org-slug/project-slug/events/1234/grouping-info/',
  92. body: {},
  93. });
  94. // Missing event
  95. MockApiClient.addMockResponse({
  96. url: '/organizations/org-slug/events/project-slug:abad1/',
  97. method: 'GET',
  98. statusCode: 404,
  99. body: {},
  100. });
  101. });
  102. it('renders', async function () {
  103. render(
  104. <EventDetails
  105. {...RouteComponentPropsFixture()}
  106. organization={OrganizationFixture()}
  107. params={{eventSlug: 'project-slug:deadbeef'}}
  108. location={{
  109. ...LocationFixture(),
  110. query: allEventsView.generateQueryStringObject(),
  111. }}
  112. />
  113. );
  114. expect(await screen.findByText('Oh no something bad')).toBeInTheDocument();
  115. });
  116. it('renders a 404', async function () {
  117. render(
  118. <EventDetails
  119. {...RouteComponentPropsFixture()}
  120. organization={OrganizationFixture()}
  121. params={{eventSlug: 'project-slug:abad1'}}
  122. location={{
  123. ...LocationFixture(),
  124. query: allEventsView.generateQueryStringObject(),
  125. }}
  126. />
  127. );
  128. expect(await screen.findByText('Page Not Found')).toBeInTheDocument();
  129. });
  130. it('renders a chart in grouped view', async function () {
  131. render(
  132. <EventDetails
  133. {...RouteComponentPropsFixture()}
  134. organization={OrganizationFixture()}
  135. params={{eventSlug: 'project-slug:deadbeef'}}
  136. location={{
  137. ...LocationFixture(),
  138. query: errorsView.generateQueryStringObject(),
  139. }}
  140. />
  141. );
  142. expect(await screen.findByText('Oh no something bad')).toBeInTheDocument();
  143. });
  144. it('renders an alert when linked issues are missing', async function () {
  145. MockApiClient.addMockResponse({
  146. url: '/issues/123/',
  147. statusCode: 404,
  148. method: 'GET',
  149. body: {},
  150. });
  151. render(
  152. <EventDetails
  153. {...RouteComponentPropsFixture()}
  154. organization={OrganizationFixture()}
  155. params={{eventSlug: 'project-slug:deadbeef'}}
  156. location={{
  157. ...LocationFixture(),
  158. query: allEventsView.generateQueryStringObject(),
  159. }}
  160. />
  161. );
  162. expect(
  163. await screen.findByText(
  164. 'The linked issue cannot be found. It may have been deleted, or merged.'
  165. )
  166. ).toBeInTheDocument();
  167. });
  168. it('navigates when tag values are clicked', async function () {
  169. const {organization, routerContext} = initializeOrg({
  170. organization: OrganizationFixture(),
  171. router: {
  172. location: {
  173. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  174. query: {},
  175. },
  176. },
  177. });
  178. render(
  179. <EventDetails
  180. {...RouteComponentPropsFixture()}
  181. organization={organization}
  182. params={{eventSlug: 'project-slug:deadbeef'}}
  183. location={{
  184. ...LocationFixture(),
  185. query: allEventsView.generateQueryStringObject(),
  186. }}
  187. />,
  188. {context: routerContext}
  189. );
  190. // Get the first link as we wrap react-router's link
  191. expect(await screen.findByText('Firefox')).toBeInTheDocument();
  192. expect(screen.getByRole('link', {name: 'Firefox'})).toHaveAttribute(
  193. 'href',
  194. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=browser%3AFirefox%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  195. );
  196. // Get the second link
  197. expect(screen.getByRole('link', {name: 'test-uuid'})).toHaveAttribute(
  198. 'href',
  199. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=tags%5Bdevice.uuid%5D%3Atest-uuid%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  200. );
  201. // Get the third link
  202. expect(screen.getByRole('link', {name: '82ebf297206a'})).toHaveAttribute(
  203. 'href',
  204. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=release%3A82ebf297206a%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  205. );
  206. });
  207. it('navigates to homepage when tag values are clicked', async function () {
  208. const {organization, routerContext, router} = initializeOrg({
  209. organization: OrganizationFixture(),
  210. router: {
  211. location: {
  212. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  213. query: {...allEventsView.generateQueryStringObject(), homepage: 'true'},
  214. },
  215. },
  216. });
  217. render(
  218. <EventDetails
  219. {...RouteComponentPropsFixture()}
  220. organization={organization}
  221. params={{eventSlug: 'project-slug:deadbeef'}}
  222. location={router.location}
  223. />,
  224. {context: routerContext}
  225. );
  226. // Get the first link as we wrap react-router's link
  227. expect(await screen.findByText('Firefox')).toBeInTheDocument();
  228. expect(screen.getByRole('link', {name: 'Firefox'})).toHaveAttribute(
  229. 'href',
  230. '/organizations/org-slug/discover/homepage/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=browser%3AFirefox%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  231. );
  232. // Get the second link
  233. expect(screen.getByRole('link', {name: 'test-uuid'})).toHaveAttribute(
  234. 'href',
  235. '/organizations/org-slug/discover/homepage/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=tags%5Bdevice.uuid%5D%3Atest-uuid%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  236. );
  237. // Get the third link
  238. expect(screen.getByRole('link', {name: '82ebf297206a'})).toHaveAttribute(
  239. 'href',
  240. '/organizations/org-slug/discover/homepage/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=release%3A82ebf297206a%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  241. );
  242. });
  243. it('appends tag value to existing query when clicked', async function () {
  244. const {organization, routerContext} = initializeOrg({
  245. organization: OrganizationFixture(),
  246. router: {
  247. location: {
  248. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  249. query: {},
  250. },
  251. },
  252. });
  253. render(
  254. <EventDetails
  255. {...RouteComponentPropsFixture()}
  256. organization={organization}
  257. params={{eventSlug: 'project-slug:deadbeef'}}
  258. location={{
  259. ...LocationFixture(),
  260. query: {...allEventsView.generateQueryStringObject(), query: 'Dumpster'},
  261. }}
  262. />,
  263. {context: routerContext}
  264. );
  265. // Get the first link as we wrap react-router's link
  266. expect(await screen.findByText('Firefox')).toBeInTheDocument();
  267. expect(screen.getByRole('link', {name: 'Firefox'})).toHaveAttribute(
  268. 'href',
  269. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=Dumpster%20browser%3AFirefox%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  270. );
  271. // Get the second link
  272. expect(screen.getByRole('link', {name: 'test-uuid'})).toHaveAttribute(
  273. 'href',
  274. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=Dumpster%20tags%5Bdevice.uuid%5D%3Atest-uuid%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  275. );
  276. // Get the third link
  277. expect(screen.getByRole('link', {name: '82ebf297206a'})).toHaveAttribute(
  278. 'href',
  279. '/organizations/org-slug/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All%20Events&query=Dumpster%20release%3A82ebf297206a%20title%3A%22Oh%20no%20something%20bad%22&sort=-timestamp&statsPeriod=24h&yAxis=count%28%29'
  280. );
  281. });
  282. it('links back to the homepage if the query param contains homepage flag', async () => {
  283. const {organization, router, routerContext} = initializeOrg({
  284. organization: OrganizationFixture(),
  285. router: {
  286. location: {
  287. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  288. query: {...allEventsView.generateQueryStringObject(), homepage: '1'},
  289. },
  290. },
  291. });
  292. render(
  293. <EventDetails
  294. {...RouteComponentPropsFixture()}
  295. organization={organization}
  296. params={{eventSlug: 'project-slug:deadbeef'}}
  297. location={router.location}
  298. />,
  299. {context: routerContext, organization}
  300. );
  301. const breadcrumb = await screen.findByTestId('breadcrumb-link');
  302. expect(breadcrumb).toHaveTextContent('Discover');
  303. expect(breadcrumb).toHaveAttribute(
  304. 'href',
  305. expect.stringMatching(new RegExp('^/organizations/org-slug/discover/homepage/?'))
  306. );
  307. });
  308. });