UNPKG

@netdata/charts

Version:

Netdata frontend SDK and chart utilities

217 lines (208 loc) 8.24 kB
"use strict"; var _numeric = _interopRequireDefault(require("./numeric")); var _units = require("../../../helpers/units"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } describe("numericTicker", function () { var mockOpts; var mockDygraph; beforeEach(function () { mockOpts = jest.fn(function (key) { var options = { pixelsPerLabel: 50, axisLabelFormatter: jest.fn(function (value) { return "".concat(value); }) }; return options[key]; }); mockDygraph = { yAxisRange: jest.fn(function () { return [0, 100]; }), getArea: jest.fn(function () { return { h: 300 }; }) }; }); it("generates ticks when vals parameter is provided", function () { var vals = [0, 25, 50, 75, 100]; var ticks = (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, vals, { units: [""] }); expect(ticks.length).toBeGreaterThan(vals.length); // includes boundary ticks and anomaly SVG // Check that vals are included in ticks vals.forEach(function (val) { expect(ticks.some(function (tick) { return tick.v === val; })).toBe(true); }); }); it("generates ticks automatically when vals is not provided", function () { var ticks = (0, _numeric["default"])(0, 100, 400, mockOpts, mockDygraph, null, { units: [""] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); // At least boundary ticks expect(ticks[0]).toHaveProperty("label_v"); // Anomaly SVG tick expect(ticks[ticks.length - 1]).toHaveProperty("label_v"); // Bottom boundary }); it("uses binary multiples for binary units", function () { var ticks = (0, _numeric["default"])(0, 1024, 400, mockOpts, mockDygraph, null, { units: ["By"] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); // Verify ticks are using binary spacing (powers of 2) var dataTicks = ticks.filter(function (tick) { return tick.v !== undefined && !tick.label_v; }).map(function (t) { return t.v; }); if (dataTicks.length > 2) { var spacing = dataTicks[1] - dataTicks[0]; // Binary units should use nice round numbers, not necessarily exact powers of 2 expect(spacing).toBeGreaterThan(0); expect(spacing).toBeLessThanOrEqual(512); } }); it("uses decimal multiples for non-binary units", function () { var ticks = (0, _numeric["default"])(0, 100, 400, mockOpts, mockDygraph, null, { units: ["percent"] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); // Verify ticks are using decimal spacing var dataTicks = ticks.filter(function (tick) { return tick.v !== undefined && !tick.label_v; }).map(function (t) { return t.v; }); if (dataTicks.length > 2) { var spacing = dataTicks[1] - dataTicks[0]; // Decimal units typically use 1, 2, 5, 10, 20, 50, 100 spacing expect([1, 2, 5, 10, 20, 25, 50, 100].some(function (v) { return Math.abs(spacing - v) < 0.01; })).toBe(true); } }); it("calculates appropriate number of ticks based on pixels", function () { var pixels = 500; var pixelsPerLabel = 50; mockOpts.mockImplementation(function (key) { if (key === "pixelsPerLabel") return pixelsPerLabel; if (key === "axisLabelFormatter") return jest.fn(function (v) { return "".concat(v); }); }); var ticks = (0, _numeric["default"])(0, 100, pixels, mockOpts, mockDygraph, null, { units: [""] }); // Should not exceed maximum ticks based on pixel spacing var maxTicks = Math.ceil(pixels / pixelsPerLabel); var dataTicks = ticks.filter(function (tick) { return tick.v !== undefined && !tick.label_v; }); expect(dataTicks.length).toBeLessThanOrEqual(maxTicks + 2); // Allow some margin for boundaries }); it("formats labels using axisLabelFormatter", function () { var mockFormatter = jest.fn(function (value) { return "formatted_".concat(value); }); mockOpts.mockImplementation(function (key) { if (key === "axisLabelFormatter") return mockFormatter; if (key === "pixelsPerLabel") return 50; }); var vals = [0, 50, 100]; (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, vals, { units: [""] }); expect(mockFormatter).toHaveBeenCalled(); expect(mockFormatter).toHaveBeenCalledWith(expect.any(Number), 0, mockOpts, mockDygraph); }); it("includes anomaly SVG in first tick", function () { var ticks = (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, null, { units: [""] }); expect(ticks[0]).toHaveProperty("label_v"); expect(ticks[0]).toHaveProperty("label"); expect(ticks[0].label).toContain("svg"); expect(ticks[0].label).toContain("Anomaly detection"); }); it("includes empty label in last tick", function () { var ticks = (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, null, { units: [""] }); expect(ticks[ticks.length - 1]).toHaveProperty("label_v"); expect(ticks[ticks.length - 1]).toHaveProperty("label"); expect(ticks[ticks.length - 1].label).toBe(""); }); it("handles negative ranges correctly", function () { var ticks = (0, _numeric["default"])(-50, 50, 400, mockOpts, mockDygraph, null, { units: [""] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); // Should include ticks in negative range var dataTicks = ticks.filter(function (tick) { return tick.v !== undefined && !tick.label_v; }); expect(dataTicks.some(function (tick) { return tick.v < 0; })).toBe(true); }); it("handles reverse axis correctly", function () { // Test with b < a to simulate reverse axis var ticks = (0, _numeric["default"])(100, 0, 400, mockOpts, mockDygraph, null, { units: [""] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); }); it("calculates point height for boundary ticks", function () { mockDygraph.yAxisRange.mockReturnValue([10, 90]); mockDygraph.getArea.mockReturnValue({ h: 150 }); var ticks = (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, null, { units: [""] }); // Point height should be calculated as (max - min) / 15 / area.h var expectedPointHeight = (90 - 10) / 15 / 150; expect(ticks[0].label_v).toBeCloseTo(90 - expectedPointHeight); expect(ticks[ticks.length - 1].label_v).toBeCloseTo(10 + expectedPointHeight); }); it("formats all generated ticks with labels", function () { var vals = [0, 25, 50, 75, 100]; var ticks = (0, _numeric["default"])(0, 100, 200, mockOpts, mockDygraph, vals, { units: [""] }); // All ticks should have labels (including boundary ticks) ticks.forEach(function (tick) { expect(tick).toHaveProperty("label"); }); // Data ticks should have formatted labels var dataTicks = ticks.filter(function (tick) { return tick.v !== undefined && !tick.label_v; }); dataTicks.forEach(function (tick) { expect(_typeof(tick.label)).toBe("string"); }); }); it("handles edge case with very small range", function () { var ticks = (0, _numeric["default"])(0, 0.001, 200, mockOpts, mockDygraph, null, { units: [""] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); }); it("handles edge case with very large range", function () { var ticks = (0, _numeric["default"])(0, 1000000, 200, mockOpts, mockDygraph, null, { units: [""] }); expect(Array.isArray(ticks)).toBe(true); expect(ticks.length).toBeGreaterThan(2); }); });