orgDashboards.spec.tsx 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import {browserHistory} from 'react-router';
  2. import {LocationFixture} from 'sentry-fixture/locationFixture';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {initializeOrg} from 'sentry-test/initializeOrg';
  5. import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
  6. import DashboardDetail from 'sentry/views/dashboards/detail';
  7. import OrgDashboards from 'sentry/views/dashboards/orgDashboards';
  8. import {DashboardState} from 'sentry/views/dashboards/types';
  9. describe('OrgDashboards', () => {
  10. const api = new MockApiClient();
  11. const organization = OrganizationFixture({
  12. features: ['dashboards-basic', 'dashboards-edit'],
  13. });
  14. let initialData;
  15. beforeEach(() => {
  16. initialData = initializeOrg({
  17. organization,
  18. projects: [],
  19. router: {
  20. location: LocationFixture(),
  21. params: {orgId: 'org-slug'},
  22. },
  23. });
  24. const mockDashboard = {
  25. dateCreated: '2021-08-10T21:20:46.798237Z',
  26. id: '1',
  27. title: 'Test Dashboard',
  28. widgets: [],
  29. projects: [],
  30. filters: {},
  31. };
  32. MockApiClient.addMockResponse({
  33. url: `/organizations/org-slug/dashboards/1/`,
  34. method: 'GET',
  35. body: mockDashboard,
  36. });
  37. MockApiClient.addMockResponse({
  38. url: '/organizations/org-slug/dashboards/',
  39. body: [mockDashboard],
  40. });
  41. });
  42. afterEach(() => {
  43. MockApiClient.clearMockResponses();
  44. jest.clearAllMocks();
  45. });
  46. it('redirects to add query params for page filters if any are saved', async () => {
  47. const mockDashboardWithFilters = {
  48. dateCreated: '2021-08-10T21:20:46.798237Z',
  49. id: '1',
  50. title: 'Test Dashboard',
  51. widgets: [],
  52. projects: [1, 2],
  53. environment: ['alpha'],
  54. period: '7d',
  55. filters: {},
  56. };
  57. MockApiClient.addMockResponse({
  58. url: `/organizations/org-slug/dashboards/1/`,
  59. method: 'GET',
  60. body: mockDashboardWithFilters,
  61. });
  62. MockApiClient.addMockResponse({
  63. url: '/organizations/org-slug/dashboards/',
  64. body: [mockDashboardWithFilters],
  65. });
  66. render(
  67. <OrgDashboards
  68. api={api}
  69. location={LocationFixture()}
  70. organization={initialData.organization}
  71. params={{orgId: 'org-slug', dashboardId: '1'}}
  72. >
  73. {({dashboard, dashboards}) => {
  74. return dashboard ? (
  75. <DashboardDetail
  76. api={api}
  77. initialState={DashboardState.VIEW}
  78. location={initialData.routerContext.location}
  79. router={initialData.router}
  80. dashboard={dashboard}
  81. dashboards={dashboards}
  82. {...initialData.router}
  83. />
  84. ) : (
  85. <div>loading</div>
  86. );
  87. }}
  88. </OrgDashboards>,
  89. {context: initialData.routerContext}
  90. );
  91. await waitFor(() =>
  92. expect(browserHistory.replace).toHaveBeenCalledWith(
  93. expect.objectContaining({
  94. query: expect.objectContaining({
  95. project: [1, 2],
  96. environment: ['alpha'],
  97. statsPeriod: '7d',
  98. }),
  99. })
  100. )
  101. );
  102. });
  103. it('ignores query params that are not page filters for redirection', async () => {
  104. const mockDashboardWithFilters = {
  105. dateCreated: '2021-08-10T21:20:46.798237Z',
  106. id: '1',
  107. title: 'Test Dashboard',
  108. widgets: [],
  109. projects: [1, 2],
  110. environment: ['alpha'],
  111. period: '7d',
  112. filters: {},
  113. };
  114. MockApiClient.addMockResponse({
  115. url: `/organizations/org-slug/dashboards/1/`,
  116. method: 'GET',
  117. body: mockDashboardWithFilters,
  118. });
  119. MockApiClient.addMockResponse({
  120. url: '/organizations/org-slug/dashboards/',
  121. body: [mockDashboardWithFilters],
  122. });
  123. render(
  124. <OrgDashboards
  125. api={api}
  126. location={{
  127. ...LocationFixture(),
  128. query: {
  129. // This query param is not a page filter, so it should not interfere
  130. // with the redirect logic
  131. sort: 'recentlyViewed',
  132. },
  133. }}
  134. organization={initialData.organization}
  135. params={{orgId: 'org-slug', dashboardId: '1'}}
  136. >
  137. {({dashboard, dashboards}) => {
  138. return dashboard ? (
  139. <DashboardDetail
  140. api={api}
  141. initialState={DashboardState.VIEW}
  142. location={initialData.router.location}
  143. router={initialData.router}
  144. dashboard={dashboard}
  145. dashboards={dashboards}
  146. {...initialData.router}
  147. />
  148. ) : (
  149. <div>loading</div>
  150. );
  151. }}
  152. </OrgDashboards>,
  153. {context: initialData.routerContext}
  154. );
  155. await waitFor(() =>
  156. expect(browserHistory.replace).toHaveBeenCalledWith(
  157. expect.objectContaining({
  158. query: expect.objectContaining({
  159. project: [1, 2],
  160. environment: ['alpha'],
  161. statsPeriod: '7d',
  162. }),
  163. })
  164. )
  165. );
  166. });
  167. it('does not add query params for page filters if one of the filters is defined', () => {
  168. initialData = initializeOrg({
  169. organization,
  170. projects: [],
  171. router: {
  172. location: {
  173. ...LocationFixture(),
  174. query: {
  175. // project is supplied in the URL, so we should avoid redirecting
  176. project: ['1'],
  177. },
  178. },
  179. params: {orgId: 'org-slug'},
  180. },
  181. });
  182. const mockDashboardWithFilters = {
  183. dateCreated: '2021-08-10T21:20:46.798237Z',
  184. id: '1',
  185. title: 'Test Dashboard',
  186. widgets: [],
  187. projects: [1, 2],
  188. environment: ['alpha'],
  189. period: '7d',
  190. filters: {},
  191. };
  192. MockApiClient.addMockResponse({
  193. url: `/organizations/org-slug/dashboards/1/`,
  194. method: 'GET',
  195. body: mockDashboardWithFilters,
  196. });
  197. MockApiClient.addMockResponse({
  198. url: '/organizations/org-slug/dashboards/',
  199. body: [mockDashboardWithFilters],
  200. });
  201. render(
  202. <OrgDashboards
  203. api={api}
  204. location={initialData.router.location}
  205. organization={initialData.organization}
  206. params={{orgId: 'org-slug', dashboardId: '1'}}
  207. >
  208. {({dashboard, dashboards}) => {
  209. return dashboard ? (
  210. <DashboardDetail
  211. api={api}
  212. initialState={DashboardState.VIEW}
  213. location={initialData.router.location}
  214. router={initialData.router}
  215. dashboard={dashboard}
  216. dashboards={dashboards}
  217. {...initialData.router}
  218. />
  219. ) : (
  220. <div>loading</div>
  221. );
  222. }}
  223. </OrgDashboards>,
  224. {context: initialData.routerContext}
  225. );
  226. expect(browserHistory.replace).not.toHaveBeenCalled();
  227. });
  228. it('does not add query params for page filters if none are saved', () => {
  229. render(
  230. <OrgDashboards
  231. api={api}
  232. location={LocationFixture()}
  233. organization={initialData.organization}
  234. params={{orgId: 'org-slug', dashboardId: '1'}}
  235. >
  236. {({dashboard, dashboards}) => {
  237. return dashboard ? (
  238. <DashboardDetail
  239. api={api}
  240. initialState={DashboardState.VIEW}
  241. location={initialData.routerContext.location}
  242. router={initialData.router}
  243. dashboard={dashboard}
  244. dashboards={dashboards}
  245. {...initialData.router}
  246. />
  247. ) : (
  248. <div>loading</div>
  249. );
  250. }}
  251. </OrgDashboards>,
  252. {context: initialData.routerContext}
  253. );
  254. expect(browserHistory.replace).not.toHaveBeenCalled();
  255. });
  256. it('does not redirect to add query params if location is cleared manually', async () => {
  257. const mockDashboardWithFilters = {
  258. dateCreated: '2021-08-10T21:20:46.798237Z',
  259. id: '1',
  260. title: 'Test Dashboard',
  261. widgets: [],
  262. projects: [1],
  263. filters: {},
  264. };
  265. MockApiClient.addMockResponse({
  266. url: `/organizations/org-slug/dashboards/1/`,
  267. method: 'GET',
  268. body: mockDashboardWithFilters,
  269. });
  270. MockApiClient.addMockResponse({
  271. url: '/organizations/org-slug/dashboards/',
  272. body: [mockDashboardWithFilters],
  273. });
  274. const {rerender} = render(
  275. <OrgDashboards
  276. api={api}
  277. location={LocationFixture()}
  278. organization={initialData.organization}
  279. params={{orgId: 'org-slug', dashboardId: '1'}}
  280. >
  281. {({dashboard, dashboards}) => {
  282. return dashboard ? (
  283. <DashboardDetail
  284. api={api}
  285. initialState={DashboardState.VIEW}
  286. location={initialData.routerContext.location}
  287. router={initialData.router}
  288. dashboard={dashboard}
  289. dashboards={dashboards}
  290. {...initialData.router}
  291. />
  292. ) : (
  293. <div>loading</div>
  294. );
  295. }}
  296. </OrgDashboards>,
  297. {context: initialData.routerContext}
  298. );
  299. await waitFor(() => expect(browserHistory.replace).toHaveBeenCalledTimes(1));
  300. rerender(
  301. <OrgDashboards
  302. api={api}
  303. location={{...initialData.routerContext.location, query: {}}}
  304. organization={initialData.organization}
  305. params={{orgId: 'org-slug', dashboardId: '1'}}
  306. >
  307. {({dashboard, dashboards}) => {
  308. return dashboard ? (
  309. <DashboardDetail
  310. api={api}
  311. initialState={DashboardState.VIEW}
  312. location={initialData.routerContext.location}
  313. router={initialData.router}
  314. dashboard={dashboard}
  315. dashboards={dashboards}
  316. {...initialData.router}
  317. />
  318. ) : (
  319. <div>loading</div>
  320. );
  321. }}
  322. </OrgDashboards>
  323. );
  324. expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument();
  325. expect(browserHistory.replace).toHaveBeenCalledTimes(1);
  326. });
  327. });