From da7296e05a6d91dea24a8bfe2ca7a8016c7e8a74 Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Tue, 3 Feb 2026 12:38:12 -0800
Subject: [PATCH] Add widget component tests (prometheusmetric, zabbix)
---
.../prometheusmetric/component.test.jsx | 115 ++++++++++++++++++
src/widgets/zabbix/component.test.jsx | 65 ++++++++++
2 files changed, 180 insertions(+)
create mode 100644 src/widgets/prometheusmetric/component.test.jsx
create mode 100644 src/widgets/zabbix/component.test.jsx
diff --git a/src/widgets/prometheusmetric/component.test.jsx b/src/widgets/prometheusmetric/component.test.jsx
new file mode 100644
index 000000000..8df915874
--- /dev/null
+++ b/src/widgets/prometheusmetric/component.test.jsx
@@ -0,0 +1,115 @@
+// @vitest-environment jsdom
+
+import { screen } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+import { renderWithProviders } from "test-utils/render-with-providers";
+import { findServiceBlockByLabel } from "test-utils/widget-assertions";
+
+const { useWidgetAPI } = vi.hoisted(() => ({ useWidgetAPI: vi.fn() }));
+vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
+
+import Component from "./component";
+
+function expectBlockValue(container, label, value) {
+ const block = findServiceBlockByLabel(container, label);
+ expect(block, `missing block for ${label}`).toBeTruthy();
+ expect(block.textContent).toContain(String(value));
+}
+
+describe("widgets/prometheusmetric/component", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders blocks for configured metrics even when data is not yet available", () => {
+ useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
+
+ const service = {
+ widget: {
+ type: "prometheusmetric",
+ metrics: [
+ { label: "prometheusmetric.metricA", query: "metric_a" },
+ { label: "prometheusmetric.metricB", query: "metric_b" },
+ ],
+ },
+ };
+
+ const { container } = renderWithProviders(, { settings: { hideErrors: false } });
+
+ // Component renders one Block per metric; with no widget.fields, Container does not filter.
+ expect(container.querySelectorAll(".service-block")).toHaveLength(2);
+ expect(screen.getByText("prometheusmetric.metricA")).toBeInTheDocument();
+ expect(screen.getByText("prometheusmetric.metricB")).toBeInTheDocument();
+ });
+
+ it("formats scalar and vector query results (scale + prefix + suffix)", () => {
+ useWidgetAPI.mockImplementation((_widget, _endpoint, params) => {
+ if (params?.query === "scalar_q") {
+ return {
+ data: { data: { resultType: "scalar", result: [0, "5"] } },
+ error: undefined,
+ };
+ }
+
+ if (params?.query === "vector_q") {
+ return {
+ data: { data: { resultType: "vector", result: [{ value: [0, "3"] }] } },
+ error: undefined,
+ };
+ }
+
+ return { data: undefined, error: undefined };
+ });
+
+ const service = {
+ widget: {
+ type: "prometheusmetric",
+ metrics: [
+ {
+ label: "prometheusmetric.scalar",
+ query: "scalar_q",
+ format: { type: "number", scale: 2, prefix: "~", suffix: "x" },
+ },
+ {
+ label: "prometheusmetric.vector",
+ query: "vector_q",
+ format: { type: "number", scale: "1/2" },
+ },
+ ],
+ },
+ };
+
+ const { container } = renderWithProviders(, { settings: { hideErrors: false } });
+
+ // scalar "5" * 2 => 10 => "~10x"
+ expectBlockValue(container, "prometheusmetric.scalar", "~10x");
+ // vector "3" * (1/2) => 1.5
+ expectBlockValue(container, "prometheusmetric.vector", 1.5);
+ });
+
+ it("renders error UI when any query errors", () => {
+ useWidgetAPI.mockImplementation((_widget, _endpoint, params) => {
+ if (params?.query === "bad") return { data: undefined, error: { message: "nope" } };
+ return { data: { data: { resultType: "scalar", result: [0, "1"] } }, error: undefined };
+ });
+
+ renderWithProviders(
+ ,
+ { settings: { hideErrors: false } },
+ );
+
+ expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
+ expect(screen.getByText("nope")).toBeInTheDocument();
+ });
+});
diff --git a/src/widgets/zabbix/component.test.jsx b/src/widgets/zabbix/component.test.jsx
new file mode 100644
index 000000000..0795eb0bc
--- /dev/null
+++ b/src/widgets/zabbix/component.test.jsx
@@ -0,0 +1,65 @@
+// @vitest-environment jsdom
+
+import { screen } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+import { renderWithProviders } from "test-utils/render-with-providers";
+import { findServiceBlockByLabel } from "test-utils/widget-assertions";
+
+const { useWidgetAPI } = vi.hoisted(() => ({ useWidgetAPI: vi.fn() }));
+vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
+
+import Component from "./component";
+
+function expectBlockValue(container, label, value) {
+ const block = findServiceBlockByLabel(container, label);
+ expect(block, `missing block for ${label}`).toBeTruthy();
+ expect(block.textContent).toContain(String(value));
+}
+
+describe("widgets/zabbix/component", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("defaults fields to 4 and filters placeholders accordingly", () => {
+ useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
+
+ const service = { widget: { type: "zabbix" } };
+ const { container } = renderWithProviders(, { settings: { hideErrors: false } });
+
+ expect(service.widget.fields).toEqual(["warning", "average", "high", "disaster"]);
+ expect(container.querySelectorAll(".service-block")).toHaveLength(4);
+ expect(screen.getByText("zabbix.warning")).toBeInTheDocument();
+ expect(screen.getByText("zabbix.average")).toBeInTheDocument();
+ expect(screen.getByText("zabbix.high")).toBeInTheDocument();
+ expect(screen.getByText("zabbix.disaster")).toBeInTheDocument();
+ expect(screen.queryByText("zabbix.unclassified")).toBeNull();
+ expect(screen.queryByText("zabbix.information")).toBeNull();
+ });
+
+ it("renders error UI when endpoint errors", () => {
+ useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
+
+ renderWithProviders(, { settings: { hideErrors: false } });
+
+ expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
+ expect(screen.getByText("nope")).toBeInTheDocument();
+ });
+
+ it("computes and renders priority counts for selected fields", () => {
+ useWidgetAPI.mockReturnValue({
+ data: [{ priority: "2" }, { priority: "3" }, { priority: "3" }, { priority: "5" }],
+ error: undefined,
+ });
+
+ const service = { widget: { type: "zabbix" } };
+ const { container } = renderWithProviders(, { settings: { hideErrors: false } });
+
+ // Default fields: warning/average/high/disaster
+ expectBlockValue(container, "zabbix.warning", 1);
+ expectBlockValue(container, "zabbix.average", 2);
+ expectBlockValue(container, "zabbix.high", 0);
+ expectBlockValue(container, "zabbix.disaster", 1);
+ });
+});