homepage.spec.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. import {browserHistory} from 'react-router';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {
  4. render,
  5. renderGlobalModal,
  6. screen,
  7. userEvent,
  8. waitFor,
  9. } from 'sentry-test/reactTestingLibrary';
  10. import * as pageFilterUtils from 'sentry/components/organizations/pageFilters/persistence';
  11. import ProjectsStore from 'sentry/stores/projectsStore';
  12. import EventView from 'sentry/utils/discover/eventView';
  13. import {DEFAULT_EVENT_VIEW} from './data';
  14. import Homepage from './homepage';
  15. describe('Discover > Homepage', () => {
  16. const features = ['global-views', 'discover-query'];
  17. let initialData, organization, mockHomepage;
  18. beforeEach(() => {
  19. organization = TestStubs.Organization({
  20. features,
  21. });
  22. initialData = initializeOrg({
  23. organization,
  24. router: {
  25. location: TestStubs.location(),
  26. },
  27. });
  28. MockApiClient.addMockResponse({
  29. url: '/organizations/org-slug/events/',
  30. body: [],
  31. });
  32. MockApiClient.addMockResponse({
  33. url: '/organizations/org-slug/events-meta/',
  34. body: {
  35. count: 2,
  36. },
  37. });
  38. MockApiClient.addMockResponse({
  39. url: '/organizations/org-slug/events-stats/',
  40. body: {data: [[123, []]]},
  41. });
  42. MockApiClient.addMockResponse({
  43. url: '/organizations/org-slug/tags/',
  44. body: [],
  45. });
  46. MockApiClient.addMockResponse({
  47. url: '/organizations/org-slug/releases/stats/',
  48. body: [],
  49. });
  50. mockHomepage = MockApiClient.addMockResponse({
  51. url: '/organizations/org-slug/discover/homepage/',
  52. method: 'GET',
  53. statusCode: 200,
  54. body: {
  55. id: '2',
  56. name: 'homepage query',
  57. projects: [],
  58. version: 2,
  59. expired: false,
  60. dateCreated: '2021-04-08T17:53:25.195782Z',
  61. dateUpdated: '2021-04-09T12:13:18.567264Z',
  62. createdBy: {
  63. id: '2',
  64. },
  65. environment: ['alpha'],
  66. fields: ['environment'],
  67. widths: ['-1'],
  68. range: '24h',
  69. orderby: '-environment',
  70. display: 'previous',
  71. query: 'event.type:error',
  72. },
  73. });
  74. });
  75. it('renders the Discover banner', async () => {
  76. render(
  77. <Homepage
  78. organization={organization}
  79. location={initialData.router.location}
  80. router={initialData.router}
  81. setSavedQuery={jest.fn()}
  82. loading={false}
  83. />,
  84. {context: initialData.routerContext, organization: initialData.organization}
  85. );
  86. await screen.findByText('Discover Trends');
  87. screen.getByText('Get a Tour');
  88. expect(screen.queryByText('Build a new query')).not.toBeInTheDocument();
  89. });
  90. it('fetches from the homepage URL and renders fields, async page filters, async and chart information', async () => {
  91. render(
  92. <Homepage
  93. organization={organization}
  94. location={initialData.router.location}
  95. router={initialData.router}
  96. setSavedQuery={jest.fn()}
  97. loading={false}
  98. />,
  99. {context: initialData.routerContext, organization: initialData.organization}
  100. );
  101. expect(mockHomepage).toHaveBeenCalled();
  102. await screen.findByText('environment');
  103. // Only the environment field
  104. expect(screen.getAllByTestId('grid-head-cell').length).toEqual(1);
  105. screen.getByText('Previous Period');
  106. screen.getByText('event.type:error');
  107. });
  108. it('renders event view from URL params over homepage query', async () => {
  109. initialData = initializeOrg({
  110. organization,
  111. router: {
  112. location: {
  113. ...TestStubs.location(),
  114. query: {
  115. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  116. field: ['project'],
  117. },
  118. },
  119. },
  120. });
  121. render(
  122. <Homepage
  123. organization={organization}
  124. location={initialData.router.location}
  125. router={initialData.router}
  126. setSavedQuery={jest.fn()}
  127. loading={false}
  128. />,
  129. {context: initialData.routerContext, organization: initialData.organization}
  130. );
  131. expect(mockHomepage).toHaveBeenCalled();
  132. await screen.findByText('project');
  133. // This is the field in the mocked response for the homepage
  134. expect(screen.queryByText('environment')).not.toBeInTheDocument();
  135. });
  136. it('applies URL changes with the homepage pathname', async () => {
  137. render(
  138. <Homepage
  139. organization={organization}
  140. location={initialData.router.location}
  141. router={initialData.router}
  142. setSavedQuery={jest.fn()}
  143. loading={false}
  144. />,
  145. {context: initialData.routerContext, organization: initialData.organization}
  146. );
  147. renderGlobalModal();
  148. await userEvent.click(await screen.findByText('Columns'));
  149. await userEvent.click(screen.getByTestId('label'));
  150. await userEvent.click(screen.getByText('event.type'));
  151. await userEvent.click(screen.getByText('Apply'));
  152. expect(browserHistory.push).toHaveBeenCalledWith(
  153. expect.objectContaining({
  154. pathname: '/organizations/org-slug/discover/homepage/',
  155. query: expect.objectContaining({
  156. field: ['event.type'],
  157. }),
  158. })
  159. );
  160. });
  161. it('does not show an editable header or author information', () => {
  162. render(
  163. <Homepage
  164. organization={organization}
  165. location={initialData.router.location}
  166. router={initialData.router}
  167. setSavedQuery={jest.fn()}
  168. loading={false}
  169. />,
  170. {context: initialData.routerContext, organization: initialData.organization}
  171. );
  172. // 'Discover' is the header for the homepage
  173. expect(screen.getByText('Discover')).toBeInTheDocument();
  174. expect(screen.queryByText(/Created by:/)).not.toBeInTheDocument();
  175. expect(screen.queryByText(/Last edited:/)).not.toBeInTheDocument();
  176. });
  177. it('shows the Remove Default button on initial load', async () => {
  178. MockApiClient.addMockResponse({
  179. url: '/organizations/org-slug/discover/homepage/',
  180. method: 'GET',
  181. statusCode: 200,
  182. body: {
  183. id: '2',
  184. name: 'homepage query',
  185. projects: [],
  186. version: 2,
  187. expired: false,
  188. dateCreated: '2021-04-08T17:53:25.195782Z',
  189. dateUpdated: '2021-04-09T12:13:18.567264Z',
  190. createdBy: {
  191. id: '2',
  192. },
  193. environment: [],
  194. fields: ['environment'],
  195. widths: ['-1'],
  196. range: '14d',
  197. orderby: '-environment',
  198. display: 'previous',
  199. query: 'event.type:error',
  200. topEvents: '5',
  201. },
  202. });
  203. render(
  204. <Homepage
  205. organization={organization}
  206. location={initialData.router.location}
  207. router={initialData.router}
  208. setSavedQuery={jest.fn()}
  209. loading={false}
  210. />,
  211. {context: initialData.routerContext, organization: initialData.organization}
  212. );
  213. expect(await screen.findByText('Remove Default')).toBeInTheDocument();
  214. expect(screen.queryByText('Set as Default')).not.toBeInTheDocument();
  215. });
  216. it('Disables the Set as Default button when no saved homepage', () => {
  217. initialData = initializeOrg({
  218. organization,
  219. router: {
  220. location: {
  221. ...TestStubs.location(),
  222. query: {
  223. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  224. },
  225. },
  226. },
  227. });
  228. mockHomepage = MockApiClient.addMockResponse({
  229. url: '/organizations/org-slug/discover/homepage/',
  230. method: 'GET',
  231. statusCode: 200,
  232. });
  233. render(
  234. <Homepage
  235. organization={organization}
  236. location={initialData.router.location}
  237. router={initialData.router}
  238. setSavedQuery={jest.fn()}
  239. loading={false}
  240. />,
  241. {context: initialData.routerContext, organization: initialData.organization}
  242. );
  243. expect(mockHomepage).toHaveBeenCalled();
  244. expect(screen.getByRole('button', {name: /set as default/i})).toBeDisabled();
  245. });
  246. it('follows absolute date selection', async () => {
  247. initialData = initializeOrg({
  248. organization,
  249. router: {
  250. location: {
  251. ...TestStubs.location(),
  252. query: {
  253. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  254. },
  255. },
  256. },
  257. });
  258. MockApiClient.addMockResponse({
  259. url: '/organizations/org-slug/discover/homepage/',
  260. method: 'GET',
  261. statusCode: 200,
  262. });
  263. render(
  264. <Homepage
  265. organization={organization}
  266. location={initialData.router.location}
  267. router={initialData.router}
  268. setSavedQuery={jest.fn()}
  269. loading={false}
  270. />,
  271. {context: initialData.routerContext, organization: initialData.organization}
  272. );
  273. await userEvent.click(await screen.findByText('24H'));
  274. await userEvent.click(await screen.findByText('Absolute date'));
  275. await userEvent.click(screen.getByText('Apply'));
  276. expect(screen.queryByText('14D')).not.toBeInTheDocument();
  277. });
  278. it('renders changes to the discover query when no homepage', () => {
  279. initialData = initializeOrg({
  280. organization,
  281. router: {
  282. location: {
  283. ...TestStubs.location(),
  284. query: {
  285. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  286. field: ['title'],
  287. },
  288. },
  289. },
  290. });
  291. MockApiClient.addMockResponse({
  292. url: '/organizations/org-slug/discover/homepage/',
  293. method: 'GET',
  294. statusCode: 200,
  295. body: '',
  296. });
  297. const {rerender} = render(
  298. <Homepage
  299. organization={organization}
  300. location={initialData.router.location}
  301. router={initialData.router}
  302. setSavedQuery={jest.fn()}
  303. loading={false}
  304. />,
  305. {context: initialData.routerContext, organization: initialData.organization}
  306. );
  307. renderGlobalModal();
  308. // Simulate an update to the columns by changing the URL params
  309. const rerenderData = initializeOrg({
  310. organization,
  311. router: {
  312. location: {
  313. ...TestStubs.location(),
  314. query: {
  315. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  316. field: ['event.type'],
  317. },
  318. },
  319. },
  320. });
  321. rerender(
  322. <Homepage
  323. organization={organization}
  324. location={rerenderData.router.location}
  325. router={rerenderData.router}
  326. setSavedQuery={jest.fn()}
  327. loading={false}
  328. />
  329. );
  330. expect(screen.getByText('event.type')).toBeInTheDocument();
  331. });
  332. it('renders changes to the discover query when loaded with valid event view in url params', () => {
  333. initialData = initializeOrg({
  334. organization,
  335. router: {
  336. location: {
  337. ...TestStubs.location(),
  338. query: {
  339. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  340. field: ['title'],
  341. },
  342. },
  343. },
  344. });
  345. const {rerender} = render(
  346. <Homepage
  347. organization={organization}
  348. location={initialData.router.location}
  349. router={initialData.router}
  350. setSavedQuery={jest.fn()}
  351. loading={false}
  352. />,
  353. {context: initialData.routerContext, organization: initialData.organization}
  354. );
  355. renderGlobalModal();
  356. // Simulate an update to the columns by changing the URL params
  357. const rerenderData = initializeOrg({
  358. organization,
  359. router: {
  360. location: {
  361. ...TestStubs.location(),
  362. query: {
  363. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  364. field: ['event.type'],
  365. },
  366. },
  367. },
  368. });
  369. rerender(
  370. <Homepage
  371. organization={organization}
  372. location={rerenderData.router.location}
  373. router={rerenderData.router}
  374. setSavedQuery={jest.fn()}
  375. loading={false}
  376. />
  377. );
  378. expect(screen.getByText('event.type')).toBeInTheDocument();
  379. });
  380. it('overrides homepage filters with pinned filters if they exist', () => {
  381. ProjectsStore.loadInitialData([TestStubs.Project({id: 2})]);
  382. jest.spyOn(pageFilterUtils, 'getPageFilterStorage').mockReturnValueOnce({
  383. pinnedFilters: new Set(['projects']),
  384. state: {
  385. project: [2],
  386. environment: [],
  387. start: null,
  388. end: null,
  389. period: '14d',
  390. utc: null,
  391. },
  392. });
  393. render(
  394. <Homepage
  395. organization={organization}
  396. location={initialData.router.location}
  397. router={initialData.router}
  398. setSavedQuery={jest.fn()}
  399. loading={false}
  400. />,
  401. {context: initialData.routerContext, organization: initialData.organization}
  402. );
  403. expect(screen.getByText('project-slug')).toBeInTheDocument();
  404. });
  405. it('allows users to set the All Events query as default', async () => {
  406. initialData = initializeOrg({
  407. organization,
  408. router: {
  409. location: {
  410. ...TestStubs.location(),
  411. query: {
  412. ...EventView.fromSavedQuery(DEFAULT_EVENT_VIEW).generateQueryStringObject(),
  413. },
  414. },
  415. },
  416. });
  417. mockHomepage = MockApiClient.addMockResponse({
  418. url: '/organizations/org-slug/discover/homepage/',
  419. method: 'GET',
  420. statusCode: 200,
  421. });
  422. render(
  423. <Homepage
  424. organization={organization}
  425. location={initialData.router.location}
  426. router={initialData.router}
  427. setSavedQuery={jest.fn()}
  428. loading={false}
  429. />,
  430. {context: initialData.routerContext, organization: initialData.organization}
  431. );
  432. await waitFor(() => expect(screen.getByTestId('set-as-default')).toBeEnabled());
  433. });
  434. });