useAddToDashboard.spec.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  2. import {openAddToDashboardModal} from 'sentry/actionCreators/modal';
  3. import {DisplayType, WidgetType} from 'sentry/views/dashboards/types';
  4. import {
  5. PageParamsProvider,
  6. useSetExploreMode,
  7. useSetExploreVisualizes,
  8. } from 'sentry/views/explore/contexts/pageParamsContext';
  9. import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
  10. import {useAddToDashboard} from 'sentry/views/explore/hooks/useAddToDashboard';
  11. import {ChartType} from 'sentry/views/insights/common/components/chart';
  12. jest.mock('sentry/actionCreators/modal');
  13. describe('AddToDashboardButton', () => {
  14. let setMode: ReturnType<typeof useSetExploreMode>;
  15. let setVisualizes: ReturnType<typeof useSetExploreVisualizes>;
  16. function TestPage({visualizeIndex}: {visualizeIndex: number}) {
  17. setMode = useSetExploreMode();
  18. setVisualizes = useSetExploreVisualizes();
  19. const {addToDashboard} = useAddToDashboard();
  20. return (
  21. <button onClick={() => addToDashboard(visualizeIndex)}>Add to Dashboard</button>
  22. );
  23. }
  24. beforeEach(() => {
  25. jest.clearAllMocks();
  26. });
  27. it('opens the dashboard modal with the correct query for samples mode', async () => {
  28. render(
  29. <PageParamsProvider>
  30. <TestPage visualizeIndex={0} />
  31. </PageParamsProvider>
  32. );
  33. await userEvent.click(screen.getByText('Add to Dashboard'));
  34. // The table columns are encoded as the fields for the defaultWidgetQuery
  35. expect(openAddToDashboardModal).toHaveBeenCalledWith(
  36. expect.objectContaining({
  37. // For Add + Stay on Page
  38. widget: {
  39. title: 'Custom Widget',
  40. displayType: DisplayType.LINE,
  41. interval: undefined,
  42. limit: undefined,
  43. widgetType: WidgetType.SPANS,
  44. queries: [
  45. {
  46. aggregates: ['avg(span.duration)'],
  47. columns: [],
  48. fields: ['avg(span.duration)'],
  49. conditions: '',
  50. orderby: '-timestamp',
  51. name: '',
  52. },
  53. ],
  54. },
  55. // For Open in Widget Builder
  56. widgetAsQueryParams: expect.objectContaining({
  57. dataset: WidgetType.SPANS,
  58. defaultTableColumns: [
  59. 'id',
  60. 'span.op',
  61. 'span.description',
  62. 'span.duration',
  63. 'transaction',
  64. 'timestamp',
  65. ],
  66. defaultTitle: 'Custom Widget',
  67. defaultWidgetQuery:
  68. 'name=&aggregates=avg(span.duration)&columns=&fields=avg(span.duration)&conditions=&orderby=-timestamp',
  69. displayType: DisplayType.LINE,
  70. field: [
  71. 'id',
  72. 'span.op',
  73. 'span.description',
  74. 'span.duration',
  75. 'transaction',
  76. 'timestamp',
  77. ],
  78. }),
  79. })
  80. );
  81. });
  82. it.each([
  83. {
  84. chartType: ChartType.AREA,
  85. expectedDisplayType: DisplayType.AREA,
  86. },
  87. {
  88. chartType: ChartType.BAR,
  89. expectedDisplayType: DisplayType.BAR,
  90. },
  91. {
  92. chartType: ChartType.LINE,
  93. expectedDisplayType: DisplayType.LINE,
  94. },
  95. ])(
  96. 'opens the dashboard modal with display type $expectedDisplayType for chart type $chartType',
  97. async ({chartType, expectedDisplayType}) => {
  98. render(
  99. <PageParamsProvider>
  100. <TestPage visualizeIndex={1} />
  101. </PageParamsProvider>,
  102. {disableRouterMocks: true}
  103. );
  104. act(() =>
  105. setVisualizes([
  106. {
  107. yAxes: ['avg(span.duration)'],
  108. chartType: ChartType.AREA,
  109. },
  110. {
  111. yAxes: ['max(span.duration)'],
  112. chartType,
  113. },
  114. ])
  115. );
  116. await userEvent.click(screen.getByText('Add to Dashboard'));
  117. // The group by and the yAxes are encoded as the fields for the defaultTableQuery
  118. expect(openAddToDashboardModal).toHaveBeenCalledWith(
  119. expect.objectContaining({
  120. // For Add + Stay on Page
  121. widget: {
  122. title: 'Custom Widget',
  123. displayType: expectedDisplayType,
  124. interval: undefined,
  125. limit: undefined,
  126. widgetType: WidgetType.SPANS,
  127. queries: [
  128. {
  129. aggregates: ['max(span.duration)'],
  130. columns: [],
  131. fields: ['max(span.duration)'],
  132. conditions: '',
  133. orderby: '-timestamp',
  134. name: '',
  135. },
  136. ],
  137. },
  138. // For Open in Widget Builder
  139. widgetAsQueryParams: expect.objectContaining({
  140. dataset: WidgetType.SPANS,
  141. defaultTableColumns: [
  142. 'id',
  143. 'span.op',
  144. 'span.description',
  145. 'span.duration',
  146. 'transaction',
  147. 'timestamp',
  148. ],
  149. defaultTitle: 'Custom Widget',
  150. defaultWidgetQuery:
  151. 'name=&aggregates=max(span.duration)&columns=&fields=max(span.duration)&conditions=&orderby=-timestamp',
  152. displayType: expectedDisplayType,
  153. field: [
  154. 'id',
  155. 'span.op',
  156. 'span.description',
  157. 'span.duration',
  158. 'transaction',
  159. 'timestamp',
  160. ],
  161. }),
  162. })
  163. );
  164. }
  165. );
  166. it('opens the dashboard modal with the correct query based on the visualize index', async () => {
  167. render(
  168. <PageParamsProvider>
  169. <TestPage visualizeIndex={1} />
  170. </PageParamsProvider>,
  171. {disableRouterMocks: true}
  172. );
  173. act(() =>
  174. setVisualizes([
  175. {
  176. yAxes: ['avg(span.duration)'],
  177. chartType: ChartType.LINE,
  178. },
  179. {
  180. yAxes: ['max(span.duration)'],
  181. chartType: ChartType.LINE,
  182. },
  183. ])
  184. );
  185. await userEvent.click(screen.getByText('Add to Dashboard'));
  186. // The group by and the yAxes are encoded as the fields for the defaultTableQuery
  187. expect(openAddToDashboardModal).toHaveBeenCalledWith(
  188. expect.objectContaining({
  189. // For Add + Stay on Page
  190. widget: {
  191. title: 'Custom Widget',
  192. displayType: DisplayType.LINE,
  193. interval: undefined,
  194. limit: undefined,
  195. widgetType: WidgetType.SPANS,
  196. queries: [
  197. {
  198. aggregates: ['max(span.duration)'],
  199. columns: [],
  200. fields: ['max(span.duration)'],
  201. conditions: '',
  202. orderby: '-timestamp',
  203. name: '',
  204. },
  205. ],
  206. },
  207. // For Open in Widget Builder
  208. widgetAsQueryParams: expect.objectContaining({
  209. dataset: WidgetType.SPANS,
  210. defaultTableColumns: [
  211. 'id',
  212. 'span.op',
  213. 'span.description',
  214. 'span.duration',
  215. 'transaction',
  216. 'timestamp',
  217. ],
  218. defaultTitle: 'Custom Widget',
  219. defaultWidgetQuery:
  220. 'name=&aggregates=max(span.duration)&columns=&fields=max(span.duration)&conditions=&orderby=-timestamp',
  221. displayType: DisplayType.LINE,
  222. field: [
  223. 'id',
  224. 'span.op',
  225. 'span.description',
  226. 'span.duration',
  227. 'transaction',
  228. 'timestamp',
  229. ],
  230. }),
  231. })
  232. );
  233. });
  234. it('uses the yAxes for the aggregate mode', async () => {
  235. render(
  236. <PageParamsProvider>
  237. <TestPage visualizeIndex={0} />
  238. </PageParamsProvider>,
  239. {disableRouterMocks: true}
  240. );
  241. act(() => setMode(Mode.AGGREGATE));
  242. await userEvent.click(screen.getByText('Add to Dashboard'));
  243. expect(openAddToDashboardModal).toHaveBeenCalledWith(
  244. expect.objectContaining({
  245. // For Add + Stay on Page
  246. widget: {
  247. title: 'Custom Widget',
  248. displayType: DisplayType.LINE,
  249. interval: undefined,
  250. limit: undefined,
  251. widgetType: WidgetType.SPANS,
  252. queries: [
  253. {
  254. aggregates: ['avg(span.duration)'],
  255. columns: [],
  256. fields: ['avg(span.duration)'],
  257. conditions: '',
  258. orderby: '-avg(span.duration)',
  259. name: '',
  260. },
  261. ],
  262. },
  263. // For Open in Widget Builder
  264. widgetAsQueryParams: expect.objectContaining({
  265. dataset: WidgetType.SPANS,
  266. defaultTableColumns: ['span.op', 'avg(span.duration)'],
  267. defaultTitle: 'Custom Widget',
  268. defaultWidgetQuery:
  269. 'name=&aggregates=avg(span.duration)&columns=&fields=avg(span.duration)&conditions=&orderby=-avg(span.duration)',
  270. displayType: DisplayType.LINE,
  271. field: ['span.op', 'avg(span.duration)'],
  272. }),
  273. })
  274. );
  275. });
  276. it('takes the first 3 yAxes', async () => {
  277. render(
  278. <PageParamsProvider>
  279. <TestPage visualizeIndex={0} />
  280. </PageParamsProvider>,
  281. {disableRouterMocks: true}
  282. );
  283. act(() => setMode(Mode.AGGREGATE));
  284. act(() =>
  285. setVisualizes([
  286. {
  287. yAxes: [
  288. 'avg(span.duration)',
  289. 'max(span.duration)',
  290. 'min(span.duration)',
  291. 'p90(span.duration)',
  292. ],
  293. chartType: ChartType.LINE,
  294. },
  295. ])
  296. );
  297. await userEvent.click(screen.getByText('Add to Dashboard'));
  298. expect(openAddToDashboardModal).toHaveBeenCalledWith(
  299. expect.objectContaining({
  300. // For Add + Stay on Page
  301. widget: {
  302. title: 'Custom Widget',
  303. displayType: DisplayType.LINE,
  304. interval: undefined,
  305. limit: undefined,
  306. widgetType: WidgetType.SPANS,
  307. queries: [
  308. {
  309. aggregates: [
  310. 'avg(span.duration)',
  311. 'max(span.duration)',
  312. 'min(span.duration)',
  313. ],
  314. columns: [],
  315. fields: ['avg(span.duration)', 'max(span.duration)', 'min(span.duration)'],
  316. conditions: '',
  317. orderby: '-avg(span.duration)',
  318. name: '',
  319. },
  320. ],
  321. },
  322. // For Open in Widget Builder
  323. widgetAsQueryParams: expect.objectContaining({
  324. dataset: WidgetType.SPANS,
  325. defaultTableColumns: [
  326. 'span.op',
  327. 'avg(span.duration)',
  328. 'max(span.duration)',
  329. 'min(span.duration)',
  330. ],
  331. defaultTitle: 'Custom Widget',
  332. defaultWidgetQuery:
  333. 'name=&aggregates=avg(span.duration)%2Cmax(span.duration)%2Cmin(span.duration)&columns=&fields=avg(span.duration)%2Cmax(span.duration)%2Cmin(span.duration)&conditions=&orderby=-avg(span.duration)',
  334. displayType: DisplayType.LINE,
  335. field: [
  336. 'span.op',
  337. 'avg(span.duration)',
  338. 'max(span.duration)',
  339. 'min(span.duration)',
  340. ],
  341. }),
  342. })
  343. );
  344. });
  345. });