parseMetricWidgetsQueryParam.spec.tsx 10 KB

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