transformProps.test.ts 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import {
  20. DatasourceType,
  21. supersetTheme,
  22. TimeGranularity,
  23. VizType,
  24. } from '@superset-ui/core';
  25. import transformProps from '../../src/BigNumber/BigNumberWithTrendline/transformProps';
  26. import {
  27. BigNumberDatum,
  28. BigNumberWithTrendlineChartProps,
  29. BigNumberWithTrendlineFormData,
  30. } from '../../src/BigNumber/types';
  31. const formData = {
  32. metric: 'value',
  33. colorPicker: {
  34. r: 0,
  35. g: 122,
  36. b: 135,
  37. a: 1,
  38. },
  39. compareLag: 1,
  40. timeGrainSqla: TimeGranularity.QUARTER,
  41. granularitySqla: 'ds',
  42. compareSuffix: 'over last quarter',
  43. viz_type: VizType.BigNumber,
  44. yAxisFormat: '.3s',
  45. datasource: 'test_datasource',
  46. };
  47. const rawFormData: BigNumberWithTrendlineFormData = {
  48. colorPicker: { b: 0, g: 0, r: 0 },
  49. datasource: '1__table',
  50. metric: 'value',
  51. color_picker: {
  52. r: 0,
  53. g: 122,
  54. b: 135,
  55. a: 1,
  56. },
  57. compare_lag: 1,
  58. time_grain_sqla: TimeGranularity.QUARTER,
  59. granularity_sqla: 'ds',
  60. compare_suffix: 'over last quarter',
  61. viz_type: VizType.BigNumber,
  62. y_axis_format: '.3s',
  63. };
  64. function generateProps(
  65. data: BigNumberDatum[],
  66. extraFormData = {},
  67. extraQueryData: any = {},
  68. ): BigNumberWithTrendlineChartProps {
  69. return {
  70. width: 200,
  71. height: 500,
  72. annotationData: {},
  73. datasource: {
  74. id: 0,
  75. name: '',
  76. type: DatasourceType.Table,
  77. columns: [],
  78. metrics: [],
  79. columnFormats: {},
  80. verboseMap: {},
  81. },
  82. rawDatasource: {},
  83. rawFormData,
  84. hooks: {},
  85. initialValues: {},
  86. formData: {
  87. ...formData,
  88. ...extraFormData,
  89. },
  90. queriesData: [
  91. {
  92. data,
  93. ...extraQueryData,
  94. },
  95. ],
  96. ownState: {},
  97. filterState: {},
  98. behaviors: [],
  99. theme: supersetTheme,
  100. };
  101. }
  102. describe('BigNumberWithTrendline', () => {
  103. const props = generateProps(
  104. [
  105. {
  106. __timestamp: 0,
  107. value: 1.2345,
  108. },
  109. {
  110. __timestamp: 100,
  111. value: null,
  112. },
  113. ],
  114. { showTrendLine: true },
  115. );
  116. describe('transformProps()', () => {
  117. it('should fallback and format time', () => {
  118. const transformed = transformProps(props);
  119. // the first item is the last item sorted by __timestamp
  120. const lastDatum = transformed.trendLineData?.pop();
  121. // should use last available value
  122. expect(lastDatum?.[0]).toStrictEqual(100);
  123. expect(lastDatum?.[1]).toBeNull();
  124. // should get the last non-null value
  125. expect(transformed.bigNumber).toStrictEqual(1.2345);
  126. // bigNumberFallback is only set when bigNumber is null after aggregation
  127. expect(transformed.bigNumberFallback).toBeNull();
  128. // should successfully formatTime by granularity
  129. // @ts-ignore
  130. expect(transformed.formatTime(new Date('2020-01-01'))).toStrictEqual(
  131. '2020-01-01 00:00:00',
  132. );
  133. });
  134. it('should respect datasource d3 format', () => {
  135. const propsWithDatasource = {
  136. ...props,
  137. datasource: {
  138. ...props.datasource,
  139. metrics: [
  140. {
  141. label: 'value',
  142. metric_name: 'value',
  143. d3format: '.2f',
  144. uuid: '1',
  145. },
  146. ],
  147. },
  148. };
  149. const transformed = transformProps(propsWithDatasource);
  150. // @ts-ignore
  151. expect(transformed.headerFormatter(transformed.bigNumber)).toStrictEqual(
  152. '1.23',
  153. );
  154. });
  155. it('should format with datasource currency', () => {
  156. const propsWithDatasource = {
  157. ...props,
  158. datasource: {
  159. ...props.datasource,
  160. currencyFormats: {
  161. value: { symbol: 'USD', symbolPosition: 'prefix' },
  162. },
  163. metrics: [
  164. {
  165. label: 'value',
  166. metric_name: 'value',
  167. d3format: '.2f',
  168. currency: { symbol: 'USD', symbolPosition: 'prefix' },
  169. uuid: '1',
  170. },
  171. ],
  172. },
  173. };
  174. const transformed = transformProps(propsWithDatasource);
  175. // @ts-ignore
  176. expect(transformed.headerFormatter(transformed.bigNumber)).toStrictEqual(
  177. '$ 1.23',
  178. );
  179. });
  180. });
  181. });
  182. describe('BigNumberWithTrendline - Aggregation Tests', () => {
  183. const baseProps = {
  184. width: 800,
  185. height: 600,
  186. formData: {
  187. colorPicker: { r: 0, g: 0, b: 0, a: 1 },
  188. metric: 'metric',
  189. aggregation: 'LAST_VALUE',
  190. },
  191. queriesData: [
  192. {
  193. data: [
  194. { __timestamp: 1607558400000, metric: 10 },
  195. { __timestamp: 1607558500000, metric: 30 },
  196. { __timestamp: 1607558600000, metric: 50 },
  197. { __timestamp: 1607558700000, metric: 60 },
  198. ],
  199. colnames: ['__timestamp', 'metric'],
  200. coltypes: ['TIMESTAMP', 'BIGINT'],
  201. },
  202. ],
  203. hooks: {},
  204. filterState: {},
  205. datasource: {
  206. columnFormats: {},
  207. currencyFormats: {},
  208. },
  209. rawDatasource: {},
  210. rawFormData: {},
  211. theme: {
  212. colors: {
  213. grayscale: {
  214. light5: '#fafafa',
  215. },
  216. },
  217. },
  218. } as unknown as BigNumberWithTrendlineChartProps;
  219. const propsWithEvenData = {
  220. ...baseProps,
  221. queriesData: [
  222. {
  223. data: [
  224. { __timestamp: 1607558400000, metric: 10 },
  225. { __timestamp: 1607558500000, metric: 20 },
  226. { __timestamp: 1607558600000, metric: 30 },
  227. { __timestamp: 1607558700000, metric: 40 },
  228. ],
  229. colnames: ['__timestamp', 'metric'],
  230. coltypes: ['TIMESTAMP', 'BIGINT'],
  231. },
  232. ],
  233. } as unknown as BigNumberWithTrendlineChartProps;
  234. it('should correctly calculate SUM', () => {
  235. const props = {
  236. ...baseProps,
  237. formData: { ...baseProps.formData, aggregation: 'sum' },
  238. queriesData: [
  239. baseProps.queriesData[0],
  240. {
  241. data: [{ metric: 150 }],
  242. colnames: ['metric'],
  243. coltypes: ['BIGINT'],
  244. },
  245. ],
  246. } as unknown as BigNumberWithTrendlineChartProps;
  247. const transformed = transformProps(props);
  248. expect(transformed.bigNumber).toStrictEqual(150);
  249. });
  250. it('should correctly calculate AVG', () => {
  251. const props = {
  252. ...baseProps,
  253. formData: { ...baseProps.formData, aggregation: 'mean' },
  254. queriesData: [
  255. baseProps.queriesData[0],
  256. {
  257. data: [{ metric: 37.5 }],
  258. colnames: ['metric'],
  259. coltypes: ['BIGINT'],
  260. },
  261. ],
  262. } as unknown as BigNumberWithTrendlineChartProps;
  263. const transformed = transformProps(props);
  264. expect(transformed.bigNumber).toStrictEqual(37.5);
  265. });
  266. it('should correctly calculate MIN', () => {
  267. const props = {
  268. ...baseProps,
  269. formData: { ...baseProps.formData, aggregation: 'min' },
  270. queriesData: [
  271. baseProps.queriesData[0],
  272. {
  273. data: [{ metric: 10 }],
  274. colnames: ['metric'],
  275. coltypes: ['BIGINT'],
  276. },
  277. ],
  278. } as unknown as BigNumberWithTrendlineChartProps;
  279. const transformed = transformProps(props);
  280. expect(transformed.bigNumber).toStrictEqual(10);
  281. });
  282. it('should correctly calculate MAX', () => {
  283. const props = {
  284. ...baseProps,
  285. formData: { ...baseProps.formData, aggregation: 'max' },
  286. queriesData: [
  287. baseProps.queriesData[0],
  288. {
  289. data: [{ metric: 60 }],
  290. colnames: ['metric'],
  291. coltypes: ['BIGINT'],
  292. },
  293. ],
  294. } as unknown as BigNumberWithTrendlineChartProps;
  295. const transformed = transformProps(props);
  296. expect(transformed.bigNumber).toStrictEqual(60);
  297. });
  298. it('should correctly calculate MEDIAN (odd count)', () => {
  299. const oddCountProps = {
  300. ...baseProps,
  301. queriesData: [
  302. {
  303. data: [
  304. { __timestamp: 1607558300000, metric: 10 },
  305. { __timestamp: 1607558400000, metric: 20 },
  306. { __timestamp: 1607558500000, metric: 30 },
  307. { __timestamp: 1607558600000, metric: 40 },
  308. { __timestamp: 1607558700000, metric: 50 },
  309. ],
  310. colnames: ['__timestamp', 'metric'],
  311. coltypes: ['TIMESTAMP', 'BIGINT'],
  312. },
  313. ],
  314. } as unknown as BigNumberWithTrendlineChartProps;
  315. const props = {
  316. ...oddCountProps,
  317. formData: { ...oddCountProps.formData, aggregation: 'median' },
  318. queriesData: [
  319. oddCountProps.queriesData[0],
  320. {
  321. data: [{ metric: 30 }],
  322. colnames: ['metric'],
  323. coltypes: ['BIGINT'],
  324. },
  325. ],
  326. } as unknown as BigNumberWithTrendlineChartProps;
  327. const transformed = transformProps(props);
  328. expect(transformed.bigNumber).toStrictEqual(30);
  329. });
  330. it('should correctly calculate MEDIAN (even count)', () => {
  331. const props = {
  332. ...propsWithEvenData,
  333. formData: { ...propsWithEvenData.formData, aggregation: 'median' },
  334. queriesData: [
  335. propsWithEvenData.queriesData[0],
  336. {
  337. data: [{ metric: 25 }],
  338. colnames: ['metric'],
  339. coltypes: ['BIGINT'],
  340. },
  341. ],
  342. } as unknown as BigNumberWithTrendlineChartProps;
  343. const transformed = transformProps(props);
  344. expect(transformed.bigNumber).toStrictEqual(25);
  345. });
  346. it('should return the LAST_VALUE correctly', () => {
  347. const transformed = transformProps(baseProps);
  348. expect(transformed.bigNumber).toStrictEqual(10);
  349. });
  350. });