eventDetails.spec.jsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {act} from 'sentry-test/reactTestingLibrary';
  4. import ProjectsStore from 'sentry/stores/projectsStore';
  5. import EventView from 'sentry/utils/discover/eventView';
  6. import {ALL_VIEWS, DEFAULT_EVENT_VIEW} from 'sentry/views/eventsV2/data';
  7. import EventDetails from 'sentry/views/eventsV2/eventDetails';
  8. import {OrganizationContext} from 'sentry/views/organizationContext';
  9. const WrappedEventDetails = ({organization, ...rest}) => {
  10. return (
  11. <OrganizationContext.Provider value={organization}>
  12. <EventDetails organization={organization} {...rest} />
  13. </OrganizationContext.Provider>
  14. );
  15. };
  16. describe('EventsV2 > EventDetails', function () {
  17. const allEventsView = EventView.fromSavedQuery(DEFAULT_EVENT_VIEW);
  18. const errorsView = EventView.fromSavedQuery(
  19. ALL_VIEWS.find(view => view.name === 'Errors by Title')
  20. );
  21. beforeEach(function () {
  22. act(() => ProjectsStore.loadInitialData([TestStubs.Project()]));
  23. MockApiClient.addMockResponse({
  24. url: '/organizations/org-slug/projects/',
  25. body: [],
  26. });
  27. MockApiClient.addMockResponse({
  28. url: '/organizations/org-slug/discover/',
  29. body: {
  30. meta: {
  31. id: 'string',
  32. title: 'string',
  33. 'project.name': 'string',
  34. timestamp: 'date',
  35. },
  36. data: [
  37. {
  38. id: 'deadbeef',
  39. title: 'Oh no something bad',
  40. 'project.name': 'project-slug',
  41. timestamp: '2019-05-23T22:12:48+00:00',
  42. },
  43. ],
  44. },
  45. });
  46. MockApiClient.addMockResponse({
  47. url: '/organizations/org-slug/events/project-slug:deadbeef/',
  48. method: 'GET',
  49. body: {
  50. id: '1234',
  51. size: 1200,
  52. projectSlug: 'project-slug',
  53. eventID: 'deadbeef',
  54. groupID: '123',
  55. title: 'Oh no something bad',
  56. location: '/users/login',
  57. message: 'It was not good',
  58. dateCreated: '2019-05-23T22:12:48+00:00',
  59. entries: [
  60. {
  61. type: 'message',
  62. message: 'bad stuff',
  63. data: {},
  64. },
  65. ],
  66. tags: [
  67. {key: 'browser', value: 'Firefox'},
  68. {key: 'device.uuid', value: 'test-uuid'},
  69. {key: 'release', value: '82ebf297206a'},
  70. ],
  71. },
  72. });
  73. MockApiClient.addMockResponse({
  74. url: '/issues/123/',
  75. method: 'GET',
  76. body: TestStubs.Group({id: '123'}),
  77. });
  78. MockApiClient.addMockResponse({
  79. url: '/organizations/org-slug/events-stats/',
  80. method: 'GET',
  81. body: {
  82. data: [
  83. [1234561700, [1]],
  84. [1234561800, [1]],
  85. ],
  86. },
  87. });
  88. MockApiClient.addMockResponse({
  89. url: '/projects/org-slug/project-slug/events/1234/committers/',
  90. method: 'GET',
  91. statusCode: 404,
  92. body: {},
  93. });
  94. MockApiClient.addMockResponse({
  95. url: '/projects/org-slug/project-slug/events/1234/grouping-info/',
  96. body: {},
  97. });
  98. // Missing event
  99. MockApiClient.addMockResponse({
  100. url: '/organizations/org-slug/events/project-slug:abad1/',
  101. method: 'GET',
  102. statusCode: 404,
  103. body: {},
  104. });
  105. });
  106. it('renders', function () {
  107. const wrapper = mountWithTheme(
  108. <WrappedEventDetails
  109. organization={TestStubs.Organization()}
  110. params={{eventSlug: 'project-slug:deadbeef'}}
  111. location={{query: allEventsView.generateQueryStringObject()}}
  112. />
  113. );
  114. const content = wrapper.find('EventHeader');
  115. expect(content.text()).toContain('Oh no something bad');
  116. });
  117. it('renders a 404', function () {
  118. const wrapper = mountWithTheme(
  119. <WrappedEventDetails
  120. organization={TestStubs.Organization()}
  121. params={{eventSlug: 'project-slug:abad1'}}
  122. location={{query: allEventsView.generateQueryStringObject()}}
  123. />
  124. );
  125. const content = wrapper.find('NotFound');
  126. expect(content).toHaveLength(1);
  127. });
  128. it('renders a chart in grouped view', async function () {
  129. const wrapper = mountWithTheme(
  130. <WrappedEventDetails
  131. organization={TestStubs.Organization()}
  132. params={{eventSlug: 'project-slug:deadbeef'}}
  133. location={{query: errorsView.generateQueryStringObject()}}
  134. />
  135. );
  136. // loading state
  137. await tick();
  138. wrapper.update();
  139. const content = wrapper.find('EventHeader');
  140. expect(content.text()).toContain('Oh no something bad');
  141. });
  142. it('renders an alert when linked issues are missing', function () {
  143. MockApiClient.addMockResponse({
  144. url: '/issues/123/',
  145. statusCode: 404,
  146. method: 'GET',
  147. body: {},
  148. });
  149. const wrapper = mountWithTheme(
  150. <WrappedEventDetails
  151. organization={TestStubs.Organization()}
  152. params={{eventSlug: 'project-slug:deadbeef'}}
  153. location={{query: allEventsView.generateQueryStringObject()}}
  154. />
  155. );
  156. const alert = wrapper.find('Alert');
  157. expect(alert).toHaveLength(1);
  158. expect(alert.text()).toContain('linked issue cannot be found');
  159. });
  160. it('navigates when tag values are clicked', async function () {
  161. const {organization, routerContext} = initializeOrg({
  162. organization: TestStubs.Organization(),
  163. router: {
  164. location: {
  165. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  166. query: {},
  167. },
  168. },
  169. });
  170. const wrapper = mountWithTheme(
  171. <WrappedEventDetails
  172. organization={organization}
  173. params={{eventSlug: 'project-slug:deadbeef'}}
  174. location={{query: allEventsView.generateQueryStringObject()}}
  175. />,
  176. routerContext
  177. );
  178. await tick();
  179. wrapper.update();
  180. // Get the first link as we wrap react-router's link
  181. const browserTagLink = wrapper
  182. .find('WrappedEventDetails KeyValueTable Value Link')
  183. .first();
  184. // Should append tag value and other event attributes to results view query.
  185. const browserTagTarget = browserTagLink.props().to;
  186. expect(browserTagTarget.pathname).toEqual(
  187. '/organizations/org-slug/discover/results/'
  188. );
  189. expect(browserTagTarget.query.query).toEqual(
  190. 'browser:Firefox title:"Oh no something bad"'
  191. );
  192. // Get the second link
  193. const deviceUUIDTagLink = wrapper
  194. .find('WrappedEventDetails KeyValueTable Value Link')
  195. .at(2);
  196. // Should append tag value wrapped with tags[] as device.uuid is part of our fields
  197. const deviceUUIDTagTarget = deviceUUIDTagLink.props().to;
  198. expect(deviceUUIDTagTarget.pathname).toEqual(
  199. '/organizations/org-slug/discover/results/'
  200. );
  201. expect(deviceUUIDTagTarget.query.query).toEqual(
  202. 'tags[device.uuid]:test-uuid title:"Oh no something bad"'
  203. );
  204. // Get the third link
  205. const releaseTagLink = wrapper
  206. .find('WrappedEventDetails KeyValueTable Value Link')
  207. .at(4);
  208. // Should append raw tag value without tags[] as release is exempt from being wrapped
  209. const releaseTagTarget = releaseTagLink.props().to;
  210. expect(releaseTagTarget.pathname).toEqual(
  211. '/organizations/org-slug/discover/results/'
  212. );
  213. expect(releaseTagTarget.query.query).toEqual(
  214. 'release:82ebf297206a title:"Oh no something bad"'
  215. );
  216. });
  217. it('appends tag value to existing query when clicked', async function () {
  218. const {organization, routerContext} = initializeOrg({
  219. organization: TestStubs.Organization(),
  220. router: {
  221. location: {
  222. pathname: '/organizations/org-slug/discover/project-slug:deadbeef',
  223. query: {},
  224. },
  225. },
  226. });
  227. const wrapper = mountWithTheme(
  228. <WrappedEventDetails
  229. organization={organization}
  230. params={{eventSlug: 'project-slug:deadbeef'}}
  231. location={{
  232. query: {...allEventsView.generateQueryStringObject(), query: 'Dumpster'},
  233. }}
  234. />,
  235. routerContext
  236. );
  237. await tick();
  238. wrapper.update();
  239. // Get the first link as we wrap react-router's link
  240. const browserTagLink = wrapper
  241. .find('WrappedEventDetails KeyValueTable Value Link')
  242. .first();
  243. // Should append tag value and other event attributes to results view query.
  244. const browserTagTarget = browserTagLink.props().to;
  245. expect(browserTagTarget.pathname).toEqual(
  246. '/organizations/org-slug/discover/results/'
  247. );
  248. expect(browserTagTarget.query.query).toEqual(
  249. 'Dumpster browser:Firefox title:"Oh no something bad"'
  250. );
  251. // Get the second link
  252. const deviceUUIDTagLink = wrapper
  253. .find('WrappedEventDetails KeyValueTable Value Link')
  254. .at(2);
  255. // Should append tag value wrapped with tags[] as device.uuid is part of our fields
  256. const deviceUUIDTagTarget = deviceUUIDTagLink.props().to;
  257. expect(deviceUUIDTagTarget.pathname).toEqual(
  258. '/organizations/org-slug/discover/results/'
  259. );
  260. expect(deviceUUIDTagTarget.query.query).toEqual(
  261. 'Dumpster tags[device.uuid]:test-uuid title:"Oh no something bad"'
  262. );
  263. // Get the third link
  264. const releaseTagLink = wrapper
  265. .find('WrappedEventDetails KeyValueTable Value Link')
  266. .at(4);
  267. // Should append raw tag value without tags[] as release is exempt from being wrapped
  268. const releaseTagTarget = releaseTagLink.props().to;
  269. expect(releaseTagTarget.pathname).toEqual(
  270. '/organizations/org-slug/discover/results/'
  271. );
  272. expect(releaseTagTarget.query.query).toEqual(
  273. 'Dumpster release:82ebf297206a title:"Oh no something bad"'
  274. );
  275. });
  276. });