UNPKG

@netdata/charts

Version:

Netdata frontend SDK and chart utilities

277 lines (276 loc) 11.1 kB
"use strict"; var _makeNode = _interopRequireDefault(require("./makeNode")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } describe("makeNode", function () { var mockSdk; var mockParent; var node; beforeEach(function () { mockSdk = { trigger: jest.fn() }; mockParent = { getAttributes: jest.fn(function () { return { timezone: "UTC" }; }), removeChild: jest.fn() }; var initialAttributes = { id: "test-chart", chartLibrary: "dygraph", pristine: {}, drawer: { action: "values", tab: "window", showAdvancedStats: false } }; node = (0, _makeNode["default"])({ sdk: mockSdk, parent: mockParent, attributes: initialAttributes }); }); describe("basic attribute operations", function () { it("gets simple attributes", function () { expect(node.getAttribute("id")).toBe("test-chart"); expect(node.getAttribute("chartLibrary")).toBe("dygraph"); }); it("sets simple attributes", function () { node.setAttribute("newAttr", "newValue"); expect(node.getAttribute("newAttr")).toBe("newValue"); }); it("returns default value for non-existent attributes", function () { expect(node.getAttribute("nonExistent", "default")).toBe("default"); }); }); describe("nested attribute operations", function () { it("gets nested attributes with dot notation", function () { expect(node.getAttribute("drawer.action")).toBe("values"); expect(node.getAttribute("drawer.tab")).toBe("window"); expect(node.getAttribute("drawer.showAdvancedStats")).toBe(false); }); it("sets nested attributes with dot notation", function () { node.setAttribute("drawer.newProp", "newValue"); expect(node.getAttribute("drawer.newProp")).toBe("newValue"); expect(node.getAttribute("drawer.action")).toBe("values"); }); it("returns default for non-existent nested attributes", function () { expect(node.getAttribute("drawer.nonExistent", "default")).toBe("default"); expect(node.getAttribute("nonExistent.prop", "default")).toBe("default"); }); it("creates nested structure when setting deep paths", function () { node.setAttribute("deep.nested.path", "value"); expect(node.getAttribute("deep.nested.path")).toBe("value"); }); }); describe("updateAttribute", function () { it("updates simple attributes and triggers listeners", function () { var listener = jest.fn(); node.onAttributeChange("testAttr", listener); node.updateAttribute("testAttr", "newValue"); expect(node.getAttribute("testAttr")).toBe("newValue"); expect(listener).toHaveBeenCalledWith("newValue", undefined, "testAttr"); }); it("updates nested attributes and triggers listeners", function () { var listener = jest.fn(); node.onAttributeChange("drawer.showAdvancedStats", listener); node.updateAttribute("drawer.showAdvancedStats", true); expect(node.getAttribute("drawer.showAdvancedStats")).toBe(true); expect(listener).toHaveBeenCalledWith(true, false, "drawer.showAdvancedStats"); }); it("does not trigger listeners if value unchanged", function () { var listener = jest.fn(); node.onAttributeChange("drawer.action", listener); node.updateAttribute("drawer.action", "values"); expect(listener).not.toHaveBeenCalled(); }); it("handles undefined to defined transitions", function () { var listener = jest.fn(); node.onAttributeChange("newAttr", listener); node.updateAttribute("newAttr", "value"); expect(listener).toHaveBeenCalledWith("value", undefined, "newAttr"); }); }); describe("updateAttributes", function () { it("updates multiple simple attributes", function () { var listener1 = jest.fn(); var listener2 = jest.fn(); node.onAttributeChange("attr1", listener1); node.onAttributeChange("attr2", listener2); node.updateAttributes({ attr1: "value1", attr2: "value2" }); expect(node.getAttribute("attr1")).toBe("value1"); expect(node.getAttribute("attr2")).toBe("value2"); expect(listener1).toHaveBeenCalledWith("value1", undefined, "attr1"); expect(listener2).toHaveBeenCalledWith("value2", undefined, "attr2"); }); it("handles nested objects in updateAttributes", function () { var listener = jest.fn(); node.onAttributeChange("drawer", listener); node.updateAttributes({ drawer: { showAdvancedStats: true, action: "compare" } }); expect(node.getAttribute("drawer.showAdvancedStats")).toBe(true); expect(node.getAttribute("drawer.action")).toBe("compare"); expect(listener).toHaveBeenCalledWith({ action: "compare", showAdvancedStats: true }, { action: "values", showAdvancedStats: false, tab: "window" }, "drawer"); }); it("handles mixed flat and nested updates", function () { node.updateAttributes({ simpleAttr: "value", nested: { prop: "nested value" }, dot: { notation: "dot value" } }); expect(node.getAttribute("simpleAttr")).toBe("value"); expect(node.getAttribute("nested.prop")).toBe("nested value"); expect(node.getAttribute("dot.notation")).toBe("dot value"); }); }); describe("attribute listeners", function () { it("supports multiple listeners on same attribute", function () { var listener1 = jest.fn(); var listener2 = jest.fn(); node.onAttributeChange("testAttr", listener1); node.onAttributeChange("testAttr", listener2); node.updateAttribute("testAttr", "value"); expect(listener1).toHaveBeenCalledWith("value", undefined, "testAttr"); expect(listener2).toHaveBeenCalledWith("value", undefined, "testAttr"); }); it("supports listening to multiple attributes", function () { var listener = jest.fn(); node.onAttributesChange(["attr1", "attr2"], listener); node.updateAttribute("attr1", "value1"); node.updateAttribute("attr2", "value2"); expect(listener).toHaveBeenCalledTimes(2); }); it("supports once listeners", function () { var listener = jest.fn(); node.onceAttributeChange("testAttr", listener); node.updateAttribute("testAttr", "value1"); node.updateAttribute("testAttr", "value2"); expect(listener).toHaveBeenCalledTimes(1); expect(listener).toHaveBeenCalledWith("value1", undefined, "testAttr"); }); }); describe("pristine functionality", function () { it("tracks pristine state changes", function () { node.updateAttribute("chartType", "table"); expect(mockSdk.trigger).toHaveBeenCalledWith("pristineChanged", "pristine", node, "table", undefined); }); }); describe("edge cases", function () { it("handles null/undefined values in nested attributes", function () { node.setAttribute("test.null", null); node.setAttribute("test.undefined", undefined); expect(node.getAttribute("test.null")).toBe(null); expect(node.getAttribute("test.undefined", "default")).toBe("default"); }); it("handles empty string paths", function () { node.setAttribute("", "value"); expect(node.getAttribute("", "default")).toBe("default"); }); it("handles null parent gracefully", function () { var nodeWithoutParent = (0, _makeNode["default"])({ sdk: mockSdk, parent: null, attributes: { id: "test" } }); expect(nodeWithoutParent.getAttribute("id")).toBe("test"); }); }); describe("pause reasons", function () { it("starts with no reasons and paused=false (assuming blur is off)", function () { expect(node.getAttribute("paused")).toBeUndefined(); }); it("addPauseReason flips paused to true", function () { node.addPauseReason("hover"); expect(node.getAttribute("paused")).toBe(true); }); it("removePauseReason after the only reason flips paused back to false", function () { node.addPauseReason("hover"); node.removePauseReason("hover"); expect(node.getAttribute("paused")).toBe(false); }); it("composes multiple reasons — removing one keeps paused true while others remain", function () { node.addPauseReason("hover"); node.addPauseReason("modal"); expect(node.getAttribute("paused")).toBe(true); node.removePauseReason("hover"); expect(node.getAttribute("paused")).toBe(true); node.removePauseReason("modal"); expect(node.getAttribute("paused")).toBe(false); }); it("is idempotent — same reason id added twice acts as one", function () { node.addPauseReason("hover"); node.addPauseReason("hover"); node.removePauseReason("hover"); expect(node.getAttribute("paused")).toBe(false); }); it("ignores empty/missing reason ids", function () { node.addPauseReason(""); node.addPauseReason(null); node.addPauseReason(undefined); expect(node.getAttribute("paused")).toBeUndefined(); }); it("recomputes when the blur attributes flip — window blur fires pause without an explicit reason", function () { node.updateAttribute("autofetchOnWindowBlur", false); node.updateAttribute("blurred", true); expect(node.getAttribute("paused")).toBe(true); node.updateAttribute("blurred", false); expect(node.getAttribute("paused")).toBe(false); }); it("blur and explicit reasons combine — un-blurring keeps paused true if a reason is still registered", function () { node.updateAttribute("autofetchOnWindowBlur", false); node.updateAttribute("blurred", true); node.addPauseReason("modal"); expect(node.getAttribute("paused")).toBe(true); node.updateAttribute("blurred", false); expect(node.getAttribute("paused")).toBe(true); node.removePauseReason("modal"); expect(node.getAttribute("paused")).toBe(false); }); it("autofetchOnWindowBlur=true disables the blur reason — paused stays false while blurred", function () { node.updateAttribute("autofetchOnWindowBlur", true); node.updateAttribute("blurred", true); expect(node.getAttribute("paused")).toBe(false); }); }); describe("inheritance", function () { it("inherits parent attributes", function () { mockParent.getAttributes.mockReturnValue({ timezone: "America/New_York", inherited: "value" }); var childNode = (0, _makeNode["default"])({ sdk: mockSdk, parent: mockParent, attributes: { id: "child" } }); expect(childNode.getAttribute("timezone")).toBe("America/New_York"); expect(childNode.getAttribute("inherited")).toBe("value"); expect(childNode.getAttribute("id")).toBe("child"); }); }); });