transformProps.test.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 { AxisType, ChartProps, supersetTheme } from '@superset-ui/core';
  20. import {
  21. LegendOrientation,
  22. LegendType,
  23. } from '@superset-ui/plugin-chart-echarts';
  24. import transformProps from '../../src/Gantt/transformProps';
  25. import {
  26. EchartsGanttChartProps,
  27. EchartsGanttFormData,
  28. } from '../../src/Gantt/types';
  29. const formData: EchartsGanttFormData = {
  30. viz_type: 'gantt_chart',
  31. datasource: '1__table',
  32. startTime: 'startTime',
  33. endTime: 'endTime',
  34. yAxis: {
  35. label: 'Y Axis',
  36. sqlExpression: 'y_axis',
  37. expressionType: 'SQL',
  38. },
  39. tooltipMetrics: ['tooltip_metric'],
  40. tooltipColumns: ['tooltip_column'],
  41. series: 'series',
  42. xAxisTimeFormat: '%H:%M',
  43. tooltipTimeFormat: '%H:%M',
  44. tooltipValuesFormat: 'DURATION_SEC',
  45. colorScheme: 'bnbColors',
  46. zoomable: true,
  47. xAxisTitleMargin: undefined,
  48. yAxisTitleMargin: undefined,
  49. xAxisTimeBounds: [null, '19:00:00'],
  50. subcategories: true,
  51. legendMargin: 0,
  52. legendOrientation: LegendOrientation.Top,
  53. legendType: LegendType.Scroll,
  54. showLegend: true,
  55. sortSeriesAscending: true,
  56. legendSort: null,
  57. };
  58. const queriesData = [
  59. {
  60. data: [
  61. {
  62. startTime: Date.UTC(2025, 1, 1, 13, 0, 0),
  63. endTime: Date.UTC(2025, 1, 1, 14, 0, 0),
  64. 'Y Axis': 'first',
  65. tooltip_column: 'tooltip value 1',
  66. series: 'series value 1',
  67. },
  68. {
  69. startTime: Date.UTC(2025, 1, 1, 18, 0, 0),
  70. endTime: Date.UTC(2025, 1, 1, 20, 0, 0),
  71. 'Y Axis': 'second',
  72. tooltip_column: 'tooltip value 2',
  73. series: 'series value 2',
  74. },
  75. ],
  76. colnames: ['startTime', 'endTime', 'Y Axis', 'tooltip_column', 'series'],
  77. },
  78. ];
  79. const chartPropsConfig = {
  80. formData,
  81. queriesData,
  82. theme: supersetTheme,
  83. };
  84. describe('Gantt transformProps', () => {
  85. it('should transform chart props', () => {
  86. const chartProps = new ChartProps(chartPropsConfig);
  87. const transformedProps = transformProps(
  88. chartProps as EchartsGanttChartProps,
  89. );
  90. expect(transformedProps.echartOptions.series).toHaveLength(4);
  91. const series = transformedProps.echartOptions.series as any[];
  92. const series0 = series[0];
  93. const series1 = series[1];
  94. // exclude renderItem because it can't be serialized
  95. expect(typeof series0.renderItem).toBe('function');
  96. delete series0.renderItem;
  97. expect(typeof series1.renderItem).toBe('function');
  98. delete series1.renderItem;
  99. delete transformedProps.echartOptions.series;
  100. expect(transformedProps).toEqual(
  101. expect.objectContaining({
  102. echartOptions: expect.objectContaining({
  103. useUTC: true,
  104. xAxis: {
  105. name: '',
  106. nameGap: 0,
  107. nameLocation: 'middle',
  108. max: Date.UTC(2025, 1, 1, 19, 0, 0),
  109. min: undefined,
  110. type: AxisType.Time,
  111. axisLabel: {
  112. hideOverlap: true,
  113. formatter: expect.anything(),
  114. },
  115. },
  116. yAxis: {
  117. name: '',
  118. nameGap: 0,
  119. nameLocation: 'middle',
  120. type: AxisType.Value,
  121. // always 0
  122. min: 0,
  123. // equals unique categories count
  124. max: 2,
  125. axisLabel: {
  126. show: false,
  127. },
  128. splitLine: {
  129. show: false,
  130. },
  131. },
  132. legend: expect.objectContaining({
  133. show: true,
  134. type: 'scroll',
  135. selector: ['all', 'inverse'],
  136. }),
  137. tooltip: {
  138. formatter: expect.anything(),
  139. },
  140. dataZoom: [
  141. expect.objectContaining({
  142. type: 'slider',
  143. filterMode: 'none',
  144. }),
  145. ],
  146. }),
  147. }),
  148. );
  149. expect(series0).toEqual({
  150. name: 'series value 1',
  151. type: 'custom',
  152. progressive: 0,
  153. itemStyle: {
  154. color: expect.anything(),
  155. },
  156. data: [
  157. {
  158. value: [
  159. Date.UTC(2025, 1, 1, 13, 0, 0),
  160. Date.UTC(2025, 1, 1, 14, 0, 0),
  161. 0,
  162. 2,
  163. Date.UTC(2025, 1, 1, 13, 0, 0),
  164. Date.UTC(2025, 1, 1, 14, 0, 0),
  165. 'first',
  166. 'tooltip value 1',
  167. 'series value 1',
  168. ],
  169. },
  170. ],
  171. dimensions: [
  172. 'startTime',
  173. 'endTime',
  174. 'index',
  175. 'seriesCount',
  176. 'startTime',
  177. 'endTime',
  178. 'Y Axis',
  179. 'tooltip_column',
  180. 'series',
  181. ],
  182. encode: {
  183. x: [0, 1],
  184. },
  185. });
  186. expect(series1).toEqual({
  187. name: 'series value 2',
  188. type: 'custom',
  189. progressive: 0,
  190. itemStyle: {
  191. color: expect.anything(),
  192. },
  193. data: [
  194. {
  195. value: [
  196. Date.UTC(2025, 1, 1, 18, 0, 0),
  197. Date.UTC(2025, 1, 1, 20, 0, 0),
  198. 1,
  199. 2,
  200. Date.UTC(2025, 1, 1, 18, 0, 0),
  201. Date.UTC(2025, 1, 1, 20, 0, 0),
  202. 'second',
  203. 'tooltip value 2',
  204. 'series value 2',
  205. ],
  206. },
  207. ],
  208. dimensions: [
  209. 'startTime',
  210. 'endTime',
  211. 'index',
  212. 'seriesCount',
  213. 'startTime',
  214. 'endTime',
  215. 'Y Axis',
  216. 'tooltip_column',
  217. 'series',
  218. ],
  219. encode: {
  220. x: [0, 1],
  221. },
  222. });
  223. expect(series[2]).toEqual({
  224. // just for markLines
  225. type: 'line',
  226. animation: false,
  227. markLine: {
  228. data: [{ yAxis: 1 }, { yAxis: 0 }],
  229. label: {
  230. show: false,
  231. },
  232. silent: true,
  233. symbol: ['none', 'none'],
  234. lineStyle: {
  235. type: 'dashed',
  236. color: '#dbe0ea',
  237. },
  238. },
  239. });
  240. expect(series[3]).toEqual({
  241. type: 'line',
  242. animation: false,
  243. markLine: {
  244. data: [
  245. { yAxis: 1.5, name: 'first' },
  246. { yAxis: 0.5, name: 'second' },
  247. ],
  248. label: {
  249. show: true,
  250. position: 'start',
  251. formatter: '{b}',
  252. color: 'rgba(0,0,0,0.88)',
  253. },
  254. lineStyle: expect.objectContaining({
  255. color: '#00000000',
  256. type: 'solid',
  257. }),
  258. silent: true,
  259. symbol: ['none', 'none'],
  260. },
  261. });
  262. });
  263. });
  264. describe('legend sorting', () => {
  265. const createChartProps = (overrides = {}) =>
  266. new ChartProps({
  267. ...chartPropsConfig,
  268. formData: {
  269. ...formData,
  270. ...overrides,
  271. },
  272. });
  273. it('preserves original data order when no sort specified', () => {
  274. const props = createChartProps({ legendSort: null });
  275. const result = transformProps(props as EchartsGanttChartProps);
  276. const legendData = (result.echartOptions.legend as any).data;
  277. expect(legendData).toEqual(['series value 1', 'series value 2']);
  278. });
  279. it('sorts alphabetically ascending when legendSort is "asc"', () => {
  280. const props = createChartProps({ legendSort: 'asc' });
  281. const result = transformProps(props as EchartsGanttChartProps);
  282. const legendData = (result.echartOptions.legend as any).data;
  283. expect(legendData).toEqual(['series value 1', 'series value 2']);
  284. });
  285. it('sorts alphabetically descending when legendSort is "desc"', () => {
  286. const props = createChartProps({ legendSort: 'desc' });
  287. const result = transformProps(props as EchartsGanttChartProps);
  288. const legendData = (result.echartOptions.legend as any).data;
  289. expect(legendData).toEqual(['series value 2', 'series value 1']);
  290. });
  291. });