time_series.test.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. import TimeSeries from 'app/core/time_series2';
  2. import { updateLegendValues } from 'app/core/time_series2';
  3. describe('TimeSeries', () => {
  4. let points, series;
  5. const yAxisFormats = ['short', 'ms'];
  6. let testData;
  7. beforeEach(() => {
  8. testData = {
  9. alias: 'test',
  10. datapoints: [[1, 2], [null, 3], [10, 4], [8, 5]],
  11. };
  12. });
  13. describe('when getting flot pairs', () => {
  14. it('with connected style, should ignore nulls', () => {
  15. series = new TimeSeries(testData);
  16. points = series.getFlotPairs('connected', yAxisFormats);
  17. expect(points.length).toBe(3);
  18. });
  19. it('with null as zero style, should replace nulls with zero', () => {
  20. series = new TimeSeries(testData);
  21. points = series.getFlotPairs('null as zero', yAxisFormats);
  22. expect(points.length).toBe(4);
  23. expect(points[1][1]).toBe(0);
  24. });
  25. it('if last is null current should pick next to last', () => {
  26. series = new TimeSeries({
  27. datapoints: [[10, 1], [null, 2]],
  28. });
  29. series.getFlotPairs('null', yAxisFormats);
  30. expect(series.stats.current).toBe(10);
  31. });
  32. it('max value should work for negative values', () => {
  33. series = new TimeSeries({
  34. datapoints: [[-10, 1], [-4, 2]],
  35. });
  36. series.getFlotPairs('null', yAxisFormats);
  37. expect(series.stats.max).toBe(-4);
  38. });
  39. it('average value should ignore nulls', () => {
  40. series = new TimeSeries(testData);
  41. series.getFlotPairs('null', yAxisFormats);
  42. expect(series.stats.avg).toBe(6.333333333333333);
  43. });
  44. it('the delta value should account for nulls', () => {
  45. series = new TimeSeries({
  46. datapoints: [[1, 2], [3, 3], [null, 4], [10, 5], [15, 6]],
  47. });
  48. series.getFlotPairs('null', yAxisFormats);
  49. expect(series.stats.delta).toBe(14);
  50. });
  51. it('the delta value should account for nulls on first', () => {
  52. series = new TimeSeries({
  53. datapoints: [[null, 2], [1, 3], [10, 4], [15, 5]],
  54. });
  55. series.getFlotPairs('null', yAxisFormats);
  56. expect(series.stats.delta).toBe(14);
  57. });
  58. it('the delta value should account for nulls on last', () => {
  59. series = new TimeSeries({
  60. datapoints: [[1, 2], [5, 3], [10, 4], [null, 5]],
  61. });
  62. series.getFlotPairs('null', yAxisFormats);
  63. expect(series.stats.delta).toBe(9);
  64. });
  65. it('the delta value should account for resets', () => {
  66. series = new TimeSeries({
  67. datapoints: [[1, 2], [5, 3], [10, 4], [0, 5], [10, 6]],
  68. });
  69. series.getFlotPairs('null', yAxisFormats);
  70. expect(series.stats.delta).toBe(19);
  71. });
  72. it('the delta value should account for resets on last', () => {
  73. series = new TimeSeries({
  74. datapoints: [[1, 2], [2, 3], [10, 4], [8, 5]],
  75. });
  76. series.getFlotPairs('null', yAxisFormats);
  77. expect(series.stats.delta).toBe(17);
  78. });
  79. it('the range value should be max - min', () => {
  80. series = new TimeSeries(testData);
  81. series.getFlotPairs('null', yAxisFormats);
  82. expect(series.stats.range).toBe(9);
  83. });
  84. it('first value should ingone nulls', () => {
  85. series = new TimeSeries(testData);
  86. series.getFlotPairs('null', yAxisFormats);
  87. expect(series.stats.first).toBe(1);
  88. series = new TimeSeries({
  89. datapoints: [[null, 2], [1, 3], [10, 4], [8, 5]],
  90. });
  91. series.getFlotPairs('null', yAxisFormats);
  92. expect(series.stats.first).toBe(1);
  93. });
  94. it('with null as zero style, average value should treat nulls as 0', () => {
  95. series = new TimeSeries(testData);
  96. series.getFlotPairs('null as zero', yAxisFormats);
  97. expect(series.stats.avg).toBe(4.75);
  98. });
  99. it('average value should be null if all values is null', () => {
  100. series = new TimeSeries({
  101. datapoints: [[null, 2], [null, 3], [null, 4], [null, 5]],
  102. });
  103. series.getFlotPairs('null');
  104. expect(series.stats.avg).toBe(null);
  105. });
  106. it('calculates timeStep', () => {
  107. series = new TimeSeries({
  108. datapoints: [[null, 1], [null, 2], [null, 3]],
  109. });
  110. series.getFlotPairs('null');
  111. expect(series.stats.timeStep).toBe(1);
  112. series = new TimeSeries({
  113. datapoints: [[0, 1530529290], [0, 1530529305], [0, 1530529320]],
  114. });
  115. series.getFlotPairs('null');
  116. expect(series.stats.timeStep).toBe(15);
  117. });
  118. });
  119. describe('When checking if ms resolution is needed', () => {
  120. describe('msResolution with second resolution timestamps', () => {
  121. beforeEach(() => {
  122. series = new TimeSeries({
  123. datapoints: [[45, 1234567890], [60, 1234567899]],
  124. });
  125. });
  126. it('should set hasMsResolution to false', () => {
  127. expect(series.hasMsResolution).toBe(false);
  128. });
  129. });
  130. describe('msResolution with millisecond resolution timestamps', () => {
  131. beforeEach(() => {
  132. series = new TimeSeries({
  133. datapoints: [[55, 1236547890001], [90, 1234456709000]],
  134. });
  135. });
  136. it('should show millisecond resolution tooltip', () => {
  137. expect(series.hasMsResolution).toBe(true);
  138. });
  139. });
  140. describe('msResolution with millisecond resolution timestamps but with trailing zeroes', () => {
  141. beforeEach(() => {
  142. series = new TimeSeries({
  143. datapoints: [[45, 1234567890000], [60, 1234567899000]],
  144. });
  145. });
  146. it('should not show millisecond resolution tooltip', () => {
  147. expect(series.hasMsResolution).toBe(false);
  148. });
  149. });
  150. });
  151. describe('can detect if series contains ms precision', () => {
  152. let fakedata;
  153. beforeEach(() => {
  154. fakedata = testData;
  155. });
  156. it('missing datapoint with ms precision', () => {
  157. fakedata.datapoints[0] = [1337, 1234567890000];
  158. series = new TimeSeries(fakedata);
  159. expect(series.isMsResolutionNeeded()).toBe(false);
  160. });
  161. it('contains datapoint with ms precision', () => {
  162. fakedata.datapoints[0] = [1337, 1236547890001];
  163. series = new TimeSeries(fakedata);
  164. expect(series.isMsResolutionNeeded()).toBe(true);
  165. });
  166. });
  167. describe('series overrides', () => {
  168. let series;
  169. beforeEach(() => {
  170. series = new TimeSeries(testData);
  171. });
  172. describe('fill & points', () => {
  173. beforeEach(() => {
  174. series.alias = 'test';
  175. series.applySeriesOverrides([{ alias: 'test', fill: 0, points: true }]);
  176. });
  177. it('should set fill zero, and enable points', () => {
  178. expect(series.lines.fill).toBe(0.001);
  179. expect(series.points.show).toBe(true);
  180. });
  181. });
  182. describe('series option overrides, bars, true & lines false', () => {
  183. beforeEach(() => {
  184. series.alias = 'test';
  185. series.applySeriesOverrides([{ alias: 'test', bars: true, lines: false }]);
  186. });
  187. it('should disable lines, and enable bars', () => {
  188. expect(series.lines.show).toBe(false);
  189. expect(series.bars.show).toBe(true);
  190. });
  191. });
  192. describe('series option overrides, linewidth, stack', () => {
  193. beforeEach(() => {
  194. series.alias = 'test';
  195. series.applySeriesOverrides([{ alias: 'test', linewidth: 5, stack: false }]);
  196. });
  197. it('should disable stack, and set lineWidth', () => {
  198. expect(series.stack).toBe(false);
  199. expect(series.lines.lineWidth).toBe(5);
  200. });
  201. });
  202. describe('series option overrides, dashes and lineWidth', () => {
  203. beforeEach(() => {
  204. series.alias = 'test';
  205. series.applySeriesOverrides([{ alias: 'test', linewidth: 5, dashes: true }]);
  206. });
  207. it('should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0', () => {
  208. expect(series.dashes.show).toBe(true);
  209. expect(series.dashes.lineWidth).toBe(5);
  210. expect(series.lines.lineWidth).toBe(0);
  211. });
  212. });
  213. describe('series option overrides, fill below to', () => {
  214. beforeEach(() => {
  215. series.alias = 'test';
  216. series.applySeriesOverrides([{ alias: 'test', fillBelowTo: 'min' }]);
  217. });
  218. it('should disable line fill and add fillBelowTo', () => {
  219. expect(series.fillBelowTo).toBe('min');
  220. });
  221. });
  222. describe('series option overrides, pointradius, steppedLine', () => {
  223. beforeEach(() => {
  224. series.alias = 'test';
  225. series.applySeriesOverrides([{ alias: 'test', pointradius: 5, steppedLine: true }]);
  226. });
  227. it('should set pointradius, and set steppedLine', () => {
  228. expect(series.points.radius).toBe(5);
  229. expect(series.lines.steps).toBe(true);
  230. });
  231. });
  232. describe('override match on regex', () => {
  233. beforeEach(() => {
  234. series.alias = 'test_01';
  235. series.applySeriesOverrides([{ alias: '/.*01/', lines: false }]);
  236. });
  237. it('should match second series', () => {
  238. expect(series.lines.show).toBe(false);
  239. });
  240. });
  241. describe('override series y-axis, and z-index', () => {
  242. beforeEach(() => {
  243. series.alias = 'test';
  244. series.applySeriesOverrides([{ alias: 'test', yaxis: 2, zindex: 2 }]);
  245. });
  246. it('should set yaxis', () => {
  247. expect(series.yaxis).toBe(2);
  248. });
  249. it('should set zindex', () => {
  250. expect(series.zindex).toBe(2);
  251. });
  252. });
  253. describe('override color', () => {
  254. beforeEach(() => {
  255. series.applySeriesOverrides([{ alias: 'test', color: '#112233' }]);
  256. });
  257. it('should set color', () => {
  258. expect(series.color).toBe('#112233');
  259. });
  260. it('should set bars.fillColor', () => {
  261. expect(series.bars.fillColor).toBe('#112233');
  262. });
  263. });
  264. });
  265. describe('value formatter', () => {
  266. let series;
  267. beforeEach(() => {
  268. series = new TimeSeries(testData);
  269. });
  270. it('should format non-numeric values as empty string', () => {
  271. expect(series.formatValue(null)).toBe('');
  272. expect(series.formatValue(undefined)).toBe('');
  273. expect(series.formatValue(NaN)).toBe('');
  274. expect(series.formatValue(Infinity)).toBe('');
  275. expect(series.formatValue(-Infinity)).toBe('');
  276. });
  277. });
  278. describe('legend decimals', () => {
  279. let series, panel;
  280. const height = 200;
  281. beforeEach(() => {
  282. testData = {
  283. alias: 'test',
  284. datapoints: [[1, 2], [0, 3], [10, 4], [8, 5]],
  285. };
  286. series = new TimeSeries(testData);
  287. series.getFlotPairs();
  288. panel = {
  289. decimals: null,
  290. yaxes: [
  291. {
  292. decimals: null,
  293. },
  294. ],
  295. };
  296. });
  297. it('should set decimals based on Y axis (expect calculated decimals = 1)', () => {
  298. const data = [series];
  299. // Expect ticks with this data will have decimals = 1
  300. updateLegendValues(data, panel, height);
  301. expect(data[0].decimals).toBe(2);
  302. });
  303. it('should set decimals based on Y axis to 0 if calculated decimals = 0)', () => {
  304. testData.datapoints = [[10, 2], [0, 3], [100, 4], [80, 5]];
  305. series = new TimeSeries(testData);
  306. series.getFlotPairs();
  307. const data = [series];
  308. updateLegendValues(data, panel, height);
  309. expect(data[0].decimals).toBe(0);
  310. });
  311. it('should set decimals to Y axis decimals + 1', () => {
  312. panel.yaxes[0].decimals = 2;
  313. const data = [series];
  314. updateLegendValues(data, panel, height);
  315. expect(data[0].decimals).toBe(3);
  316. });
  317. it('should set decimals to legend decimals value if it was set explicitly', () => {
  318. panel.decimals = 3;
  319. const data = [series];
  320. updateLegendValues(data, panel, height);
  321. expect(data[0].decimals).toBe(3);
  322. });
  323. });
  324. });