parseMetricWidgetsQueryParam.spec.tsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. import {emptyMetricsQueryWidget} from 'sentry/utils/metrics/constants';
  2. import {MetricQueryType} from 'sentry/utils/metrics/types';
  3. import {parseMetricWidgetsQueryParam} from 'sentry/views/ddm/utils/parseMetricWidgetsQueryParam';
  4. describe('parseMetricWidgetQueryParam', () => {
  5. const defaultState = [{...emptyMetricsQueryWidget, id: 0}];
  6. it('returns default widget for invalid param', () => {
  7. expect(parseMetricWidgetsQueryParam(undefined)).toStrictEqual(defaultState);
  8. expect(parseMetricWidgetsQueryParam('')).toStrictEqual(defaultState);
  9. expect(parseMetricWidgetsQueryParam('{}')).toStrictEqual(defaultState);
  10. expect(parseMetricWidgetsQueryParam('true')).toStrictEqual(defaultState);
  11. expect(parseMetricWidgetsQueryParam('2')).toStrictEqual(defaultState);
  12. expect(parseMetricWidgetsQueryParam('"test"')).toStrictEqual(defaultState);
  13. // empty array is not valid
  14. expect(parseMetricWidgetsQueryParam('[]')).toStrictEqual(defaultState);
  15. });
  16. it('returns a single widget', () => {
  17. expect(
  18. parseMetricWidgetsQueryParam(
  19. JSON.stringify([
  20. {
  21. id: 0,
  22. type: MetricQueryType.QUERY,
  23. mri: 'd:transactions/duration@millisecond',
  24. op: 'sum',
  25. query: 'test:query',
  26. groupBy: ['dist'],
  27. displayType: 'line',
  28. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  29. powerUserMode: true,
  30. sort: {order: 'asc'},
  31. },
  32. ])
  33. )
  34. ).toStrictEqual([
  35. {
  36. id: 0,
  37. type: MetricQueryType.QUERY,
  38. mri: 'd:transactions/duration@millisecond',
  39. op: 'sum',
  40. query: 'test:query',
  41. groupBy: ['dist'],
  42. displayType: 'line',
  43. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  44. powerUserMode: true,
  45. sort: {name: undefined, order: 'asc'},
  46. },
  47. ]);
  48. });
  49. it('returns multiple widgets', () => {
  50. expect(
  51. parseMetricWidgetsQueryParam(
  52. JSON.stringify([
  53. {
  54. id: 0,
  55. type: MetricQueryType.QUERY,
  56. mri: 'd:transactions/duration@millisecond',
  57. op: 'sum',
  58. query: 'test:query',
  59. groupBy: ['dist'],
  60. displayType: 'line',
  61. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  62. powerUserMode: true,
  63. sort: {name: 'avg', order: 'desc'},
  64. },
  65. {
  66. id: 1,
  67. type: MetricQueryType.QUERY,
  68. mri: 'd:custom/sentry.event_manager.save@second',
  69. op: 'avg',
  70. query: '',
  71. groupBy: ['event_type'],
  72. displayType: 'line',
  73. powerUserMode: false,
  74. focusedSeries: [{id: 'default', groupBy: {event_type: 'default'}}],
  75. sort: {name: 'sum', order: 'asc'},
  76. },
  77. {
  78. id: 2,
  79. type: MetricQueryType.FORMULA,
  80. formula: 'a + b',
  81. displayType: 'line',
  82. sort: {name: 'avg', order: 'desc'},
  83. focusedSeries: [],
  84. },
  85. ])
  86. )
  87. ).toStrictEqual([
  88. {
  89. id: 0,
  90. type: MetricQueryType.QUERY,
  91. mri: 'd:transactions/duration@millisecond',
  92. op: 'sum',
  93. query: 'test:query',
  94. groupBy: ['dist'],
  95. displayType: 'line',
  96. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  97. powerUserMode: true,
  98. sort: {name: 'avg', order: 'desc'},
  99. },
  100. {
  101. id: 1,
  102. type: MetricQueryType.QUERY,
  103. mri: 'd:custom/sentry.event_manager.save@second',
  104. op: 'avg',
  105. query: '',
  106. groupBy: ['event_type'],
  107. displayType: 'line',
  108. powerUserMode: false,
  109. focusedSeries: [{id: 'default', groupBy: {event_type: 'default'}}],
  110. sort: {name: 'sum', order: 'asc'},
  111. },
  112. {
  113. id: 2,
  114. type: MetricQueryType.FORMULA,
  115. formula: 'a + b',
  116. displayType: 'line',
  117. sort: {name: 'avg', order: 'desc'},
  118. focusedSeries: [],
  119. },
  120. ]);
  121. });
  122. it('falls back to defaults', () => {
  123. // Missing values
  124. expect(
  125. parseMetricWidgetsQueryParam(
  126. JSON.stringify([
  127. {
  128. mri: 'd:transactions/duration@millisecond',
  129. },
  130. {
  131. type: MetricQueryType.FORMULA,
  132. formula: 'a * 2',
  133. },
  134. ])
  135. )
  136. ).toStrictEqual([
  137. {
  138. id: 0,
  139. type: MetricQueryType.QUERY,
  140. mri: 'd:transactions/duration@millisecond',
  141. op: 'avg',
  142. query: '',
  143. groupBy: [],
  144. displayType: 'line',
  145. focusedSeries: [],
  146. powerUserMode: false,
  147. sort: {name: undefined, order: 'asc'},
  148. },
  149. {
  150. id: 1,
  151. type: MetricQueryType.FORMULA,
  152. formula: 'a * 2',
  153. displayType: 'line',
  154. focusedSeries: [],
  155. sort: {name: undefined, order: 'asc'},
  156. },
  157. ]);
  158. // Invalid values
  159. expect(
  160. parseMetricWidgetsQueryParam(
  161. JSON.stringify([
  162. {
  163. id: 'invalid',
  164. type: 123,
  165. mri: 'd:transactions/duration@millisecond',
  166. op: 1,
  167. query: 12,
  168. groupBy: true,
  169. displayType: 'aasfcsdf',
  170. focusedSeries: {},
  171. powerUserMode: 1,
  172. sort: {name: 1, order: 'invalid'},
  173. },
  174. ])
  175. )
  176. ).toStrictEqual([
  177. {
  178. id: 0,
  179. type: MetricQueryType.QUERY,
  180. mri: 'd:transactions/duration@millisecond',
  181. op: 'avg',
  182. query: '',
  183. groupBy: [],
  184. displayType: 'line',
  185. focusedSeries: [],
  186. powerUserMode: false,
  187. sort: {name: undefined, order: 'asc'},
  188. },
  189. ]);
  190. });
  191. it('ignores invalid widgets', () => {
  192. expect(
  193. parseMetricWidgetsQueryParam(
  194. JSON.stringify([
  195. {
  196. id: 0,
  197. mri: 'd:transactions/duration@millisecond',
  198. },
  199. {
  200. // Missing MRI
  201. },
  202. {
  203. // Mallformed MRI
  204. mri: 'transactions/duration@millisecond',
  205. },
  206. {
  207. // Duplicate id
  208. id: 0,
  209. mri: 'd:transactions/duration@second',
  210. },
  211. {
  212. // Missing formula
  213. type: MetricQueryType.FORMULA,
  214. },
  215. ])
  216. )
  217. ).toStrictEqual([
  218. {
  219. id: 0,
  220. type: MetricQueryType.QUERY,
  221. mri: 'd:transactions/duration@millisecond',
  222. op: 'avg',
  223. query: '',
  224. groupBy: [],
  225. displayType: 'line',
  226. focusedSeries: [],
  227. powerUserMode: false,
  228. sort: {name: undefined, order: 'asc'},
  229. },
  230. ]);
  231. });
  232. it('returns default widget if there is no valid widget', () => {
  233. expect(
  234. parseMetricWidgetsQueryParam(
  235. JSON.stringify([
  236. {
  237. // Missing MRI
  238. },
  239. {
  240. // Missing formula
  241. type: MetricQueryType.FORMULA,
  242. },
  243. ])
  244. )
  245. ).toStrictEqual(defaultState);
  246. });
  247. it('handles missing array in array params', () => {
  248. expect(
  249. parseMetricWidgetsQueryParam(
  250. JSON.stringify([
  251. {
  252. id: 0,
  253. type: MetricQueryType.QUERY,
  254. mri: 'd:transactions/duration@millisecond',
  255. op: 'sum',
  256. query: 'test:query',
  257. groupBy: 'dist',
  258. displayType: 'line',
  259. focusedSeries: {id: 'default', groupBy: {dist: 'default'}},
  260. powerUserMode: true,
  261. sort: {order: 'asc'},
  262. },
  263. ])
  264. )
  265. ).toStrictEqual([
  266. {
  267. id: 0,
  268. type: MetricQueryType.QUERY,
  269. mri: 'd:transactions/duration@millisecond',
  270. op: 'sum',
  271. query: 'test:query',
  272. groupBy: ['dist'],
  273. displayType: 'line',
  274. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  275. powerUserMode: true,
  276. sort: {name: undefined, order: 'asc'},
  277. },
  278. ]);
  279. });
  280. it('adds missing ids', () => {
  281. const widgetWithId = (id: number | undefined) => ({
  282. id,
  283. type: MetricQueryType.QUERY,
  284. mri: 'd:transactions/duration@millisecond',
  285. op: 'sum',
  286. query: 'test:query',
  287. groupBy: ['dist'],
  288. displayType: 'line',
  289. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  290. powerUserMode: true,
  291. sort: {name: 'avg', order: 'desc'},
  292. });
  293. expect(
  294. parseMetricWidgetsQueryParam(
  295. JSON.stringify([
  296. widgetWithId(0),
  297. widgetWithId(undefined),
  298. widgetWithId(2),
  299. {
  300. // Invalid widget
  301. },
  302. widgetWithId(undefined),
  303. widgetWithId(3),
  304. ])
  305. )
  306. ).toStrictEqual([
  307. widgetWithId(0),
  308. widgetWithId(1),
  309. widgetWithId(2),
  310. widgetWithId(4),
  311. widgetWithId(3),
  312. ]);
  313. });
  314. it('resets the id of a single widget to 0', () => {
  315. expect(
  316. parseMetricWidgetsQueryParam(
  317. JSON.stringify([
  318. {
  319. id: 5,
  320. type: MetricQueryType.QUERY,
  321. mri: 'd:transactions/duration@millisecond',
  322. op: 'sum',
  323. query: 'test:query',
  324. groupBy: ['dist'],
  325. displayType: 'line',
  326. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  327. powerUserMode: true,
  328. sort: {name: 'avg', order: 'desc'},
  329. },
  330. ])
  331. )
  332. ).toStrictEqual([
  333. {
  334. id: 0,
  335. type: MetricQueryType.QUERY,
  336. mri: 'd:transactions/duration@millisecond',
  337. op: 'sum',
  338. query: 'test:query',
  339. groupBy: ['dist'],
  340. displayType: 'line',
  341. focusedSeries: [{id: 'default', groupBy: {dist: 'default'}}],
  342. powerUserMode: true,
  343. sort: {name: 'avg', order: 'desc'},
  344. },
  345. ]);
  346. });
  347. });