homepage.spec.tsx 14 KB

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