1import TimeSeries, { updateLegendValues } from 'app/core/time_series2'; 2 3describe('TimeSeries', () => { 4 let points, series: any; 5 const yAxisFormats = ['short', 'ms']; 6 let testData: { alias?: string; datapoints: any }; 7 8 beforeEach(() => { 9 testData = { 10 alias: 'test', 11 datapoints: [ 12 [1, 2], 13 [null, 3], 14 [10, 4], 15 [8, 5], 16 ], 17 }; 18 }); 19 20 describe('when getting flot pairs', () => { 21 it('with connected style, should ignore nulls', () => { 22 series = new TimeSeries(testData); 23 points = series.getFlotPairs('connected', yAxisFormats); 24 expect(points.length).toBe(3); 25 }); 26 27 it('with null as zero style, should replace nulls with zero', () => { 28 series = new TimeSeries(testData); 29 points = series.getFlotPairs('null as zero', yAxisFormats); 30 expect(points.length).toBe(4); 31 expect(points[1][1]).toBe(0); 32 }); 33 34 it('if last is null current should pick next to last', () => { 35 series = new TimeSeries({ 36 datapoints: [ 37 [10, 1], 38 [null, 2], 39 ], 40 }); 41 series.getFlotPairs('null', yAxisFormats); 42 expect(series.stats.current).toBe(10); 43 }); 44 45 it('max value should work for negative values', () => { 46 series = new TimeSeries({ 47 datapoints: [ 48 [-10, 1], 49 [-4, 2], 50 ], 51 }); 52 series.getFlotPairs('null', yAxisFormats); 53 expect(series.stats.max).toBe(-4); 54 }); 55 56 it('average value should ignore nulls', () => { 57 series = new TimeSeries(testData); 58 series.getFlotPairs('null', yAxisFormats); 59 expect(series.stats.avg).toBe(6.333333333333333); 60 }); 61 62 it('the delta value should account for nulls', () => { 63 series = new TimeSeries({ 64 datapoints: [ 65 [1, 2], 66 [3, 3], 67 [null, 4], 68 [10, 5], 69 [15, 6], 70 ], 71 }); 72 series.getFlotPairs('null', yAxisFormats); 73 expect(series.stats.delta).toBe(14); 74 }); 75 76 it('the delta value should account for nulls on first', () => { 77 series = new TimeSeries({ 78 datapoints: [ 79 [null, 2], 80 [1, 3], 81 [10, 4], 82 [15, 5], 83 ], 84 }); 85 series.getFlotPairs('null', yAxisFormats); 86 expect(series.stats.delta).toBe(14); 87 }); 88 89 it('the delta value should account for nulls on last', () => { 90 series = new TimeSeries({ 91 datapoints: [ 92 [1, 2], 93 [5, 3], 94 [10, 4], 95 [null, 5], 96 ], 97 }); 98 series.getFlotPairs('null', yAxisFormats); 99 expect(series.stats.delta).toBe(9); 100 }); 101 102 it('the delta value should account for resets', () => { 103 series = new TimeSeries({ 104 datapoints: [ 105 [1, 2], 106 [5, 3], 107 [10, 4], 108 [0, 5], 109 [10, 6], 110 ], 111 }); 112 series.getFlotPairs('null', yAxisFormats); 113 expect(series.stats.delta).toBe(19); 114 }); 115 116 it('the delta value should account for resets on last', () => { 117 series = new TimeSeries({ 118 datapoints: [ 119 [1, 2], 120 [2, 3], 121 [10, 4], 122 [8, 5], 123 ], 124 }); 125 series.getFlotPairs('null', yAxisFormats); 126 expect(series.stats.delta).toBe(17); 127 }); 128 129 it('the range value should be max - min', () => { 130 series = new TimeSeries(testData); 131 series.getFlotPairs('null', yAxisFormats); 132 expect(series.stats.range).toBe(9); 133 }); 134 135 it('first value should ingone nulls', () => { 136 series = new TimeSeries(testData); 137 series.getFlotPairs('null', yAxisFormats); 138 expect(series.stats.first).toBe(1); 139 series = new TimeSeries({ 140 datapoints: [ 141 [null, 2], 142 [1, 3], 143 [10, 4], 144 [8, 5], 145 ], 146 }); 147 series.getFlotPairs('null', yAxisFormats); 148 expect(series.stats.first).toBe(1); 149 }); 150 151 it('with null as zero style, average value should treat nulls as 0', () => { 152 series = new TimeSeries(testData); 153 series.getFlotPairs('null as zero', yAxisFormats); 154 expect(series.stats.avg).toBe(4.75); 155 }); 156 157 it('average value should be null if all values is null', () => { 158 series = new TimeSeries({ 159 datapoints: [ 160 [null, 2], 161 [null, 3], 162 [null, 4], 163 [null, 5], 164 ], 165 }); 166 series.getFlotPairs('null'); 167 expect(series.stats.avg).toBe(null); 168 }); 169 170 it('calculates timeStep', () => { 171 series = new TimeSeries({ 172 datapoints: [ 173 [null, 1], 174 [null, 2], 175 [null, 3], 176 ], 177 }); 178 series.getFlotPairs('null'); 179 expect(series.stats.timeStep).toBe(1); 180 181 series = new TimeSeries({ 182 datapoints: [ 183 [0, 1530529290], 184 [0, 1530529305], 185 [0, 1530529320], 186 ], 187 }); 188 series.getFlotPairs('null'); 189 expect(series.stats.timeStep).toBe(15); 190 }); 191 }); 192 193 describe('When checking if ms resolution is needed', () => { 194 describe('msResolution with second resolution timestamps', () => { 195 beforeEach(() => { 196 series = new TimeSeries({ 197 datapoints: [ 198 [45, 1234567890], 199 [60, 1234567899], 200 ], 201 }); 202 }); 203 204 it('should set hasMsResolution to false', () => { 205 expect(series.hasMsResolution).toBe(false); 206 }); 207 }); 208 209 describe('msResolution with millisecond resolution timestamps', () => { 210 beforeEach(() => { 211 series = new TimeSeries({ 212 datapoints: [ 213 [55, 1236547890001], 214 [90, 1234456709000], 215 ], 216 }); 217 }); 218 219 it('should show millisecond resolution tooltip', () => { 220 expect(series.hasMsResolution).toBe(true); 221 }); 222 }); 223 224 describe('msResolution with millisecond resolution timestamps but with trailing zeroes', () => { 225 beforeEach(() => { 226 series = new TimeSeries({ 227 datapoints: [ 228 [45, 1234567890000], 229 [60, 1234567899000], 230 ], 231 }); 232 }); 233 234 it('should not show millisecond resolution tooltip', () => { 235 expect(series.hasMsResolution).toBe(false); 236 }); 237 }); 238 }); 239 240 describe('can detect if series contains ms precision', () => { 241 let fakedata: any; 242 243 beforeEach(() => { 244 fakedata = testData; 245 }); 246 247 it('missing datapoint with ms precision', () => { 248 fakedata.datapoints[0] = [1337, 1234567890000]; 249 series = new TimeSeries(fakedata); 250 expect(series.isMsResolutionNeeded()).toBe(false); 251 }); 252 253 it('contains datapoint with ms precision', () => { 254 fakedata.datapoints[0] = [1337, 1236547890001]; 255 series = new TimeSeries(fakedata); 256 expect(series.isMsResolutionNeeded()).toBe(true); 257 }); 258 }); 259 260 describe('series overrides', () => { 261 let series: any; 262 beforeEach(() => { 263 series = new TimeSeries(testData); 264 }); 265 266 describe('fill & points', () => { 267 beforeEach(() => { 268 series.alias = 'test'; 269 series.applySeriesOverrides([{ alias: 'test', fill: 0, points: true }]); 270 }); 271 272 it('should set fill zero, and enable points', () => { 273 expect(series.lines.fill).toBe(0.001); 274 expect(series.points.show).toBe(true); 275 }); 276 }); 277 278 describe('fillGradient', () => { 279 beforeEach(() => { 280 series.alias = 'test'; 281 series.applySeriesOverrides([{ alias: 'test', fill: 10, fillGradient: 10 }]); 282 }); 283 284 it('should set fillcolor to gradient', () => { 285 expect(series.lines.fillColor).toMatchObject({ 286 colors: [{ opacity: 0.0 }, { opacity: 1 }], 287 }); 288 }); 289 }); 290 291 describe('series option overrides, bars, true & lines false', () => { 292 beforeEach(() => { 293 series.alias = 'test'; 294 series.applySeriesOverrides([{ alias: 'test', bars: true, lines: false }]); 295 }); 296 297 it('should disable lines, and enable bars', () => { 298 expect(series.lines.show).toBe(false); 299 expect(series.bars.show).toBe(true); 300 }); 301 }); 302 303 describe('series option overrides, linewidth, stack', () => { 304 beforeEach(() => { 305 series.alias = 'test'; 306 series.applySeriesOverrides([{ alias: 'test', linewidth: 5, stack: false }]); 307 }); 308 309 it('should disable stack, and set lineWidth', () => { 310 expect(series.stack).toBe(false); 311 expect(series.lines.lineWidth).toBe(5); 312 }); 313 }); 314 315 describe('series option overrides, dashes and lineWidth', () => { 316 beforeEach(() => { 317 series.alias = 'test'; 318 series.applySeriesOverrides([{ alias: 'test', linewidth: 5, dashes: true }]); 319 }); 320 321 it('should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0', () => { 322 expect(series.dashes.show).toBe(true); 323 expect(series.dashes.lineWidth).toBe(5); 324 expect(series.lines.lineWidth).toBe(0); 325 }); 326 }); 327 328 describe('series option overrides, fill below to', () => { 329 beforeEach(() => { 330 series.alias = 'test'; 331 series.applySeriesOverrides([{ alias: 'test', fillBelowTo: 'min' }]); 332 }); 333 334 it('should disable line fill and add fillBelowTo', () => { 335 expect(series.fillBelowTo).toBe('min'); 336 }); 337 }); 338 339 describe('series option overrides, pointradius, steppedLine', () => { 340 beforeEach(() => { 341 series.alias = 'test'; 342 series.applySeriesOverrides([{ alias: 'test', pointradius: 5, steppedLine: true }]); 343 }); 344 345 it('should set pointradius, and set steppedLine', () => { 346 expect(series.points.radius).toBe(5); 347 expect(series.lines.steps).toBe(true); 348 }); 349 }); 350 351 describe('override match on regex', () => { 352 beforeEach(() => { 353 series.alias = 'test_01'; 354 series.applySeriesOverrides([{ alias: '/.*01/', lines: false }]); 355 }); 356 357 it('should match second series', () => { 358 expect(series.lines.show).toBe(false); 359 }); 360 }); 361 362 describe('override series y-axis, and z-index', () => { 363 beforeEach(() => { 364 series.alias = 'test'; 365 series.applySeriesOverrides([{ alias: 'test', yaxis: 2, zindex: 2 }]); 366 }); 367 368 it('should set yaxis', () => { 369 expect(series.yaxis).toBe(2); 370 }); 371 372 it('should set zindex', () => { 373 expect(series.zindex).toBe(2); 374 }); 375 }); 376 377 describe('override color', () => { 378 beforeEach(() => { 379 series.applySeriesOverrides([{ alias: 'test', color: '#112233' }]); 380 }); 381 382 it('should set color', () => { 383 expect(series.color).toBe('#112233'); 384 }); 385 386 it('should set bars.fillColor', () => { 387 expect(series.bars.fillColor).toBe('#112233'); 388 }); 389 }); 390 }); 391 392 describe('value formatter', () => { 393 let series: any; 394 beforeEach(() => { 395 series = new TimeSeries(testData); 396 }); 397 398 it('should format non-numeric values as empty string', () => { 399 expect(series.formatValue(null)).toBe(''); 400 expect(series.formatValue(undefined)).toBe(''); 401 expect(series.formatValue(NaN)).toBe(''); 402 expect(series.formatValue(Infinity)).toBe(''); 403 expect(series.formatValue(-Infinity)).toBe(''); 404 }); 405 }); 406 407 describe('legend decimals', () => { 408 let series: any, panel: any; 409 const height = 200; 410 beforeEach(() => { 411 testData = { 412 alias: 'test', 413 datapoints: [ 414 [1, 2], 415 [0, 3], 416 [10, 4], 417 [8, 5], 418 ], 419 }; 420 series = new TimeSeries(testData); 421 series.getFlotPairs(); 422 panel = { 423 decimals: null, 424 yaxes: [ 425 { 426 decimals: null, 427 }, 428 ], 429 }; 430 }); 431 432 it('should set decimals to null if no decimals set', () => { 433 const data = [series]; 434 // Expect ticks with this data will have decimals = 1 435 updateLegendValues(data, panel, height); 436 expect(data[0].decimals).toBe(null); 437 }); 438 439 it('should set decimals to Y axis decimals + 1', () => { 440 panel.yaxes[0].decimals = 2; 441 const data = [series]; 442 updateLegendValues(data, panel, height); 443 expect(data[0].decimals).toBe(3); 444 }); 445 446 it('should set decimals to legend decimals value if it was set explicitly', () => { 447 panel.decimals = 3; 448 const data = [series]; 449 updateLegendValues(data, panel, height); 450 expect(data[0].decimals).toBe(3); 451 }); 452 }); 453}); 454