From 9039b55b8a8ed47e09878222785dc5fe7375c472 Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:13:16 -0800
Subject: [PATCH] test: cover remaining resources widgets + version component
---
src/components/version.test.jsx | 67 +++++++++++++++++++
src/components/widgets/resources/cpu.test.jsx | 47 +++++++++++++
.../widgets/resources/cputemp.test.jsx | 45 +++++++++++++
.../widgets/resources/disk.test.jsx | 45 +++++++++++++
.../widgets/resources/memory.test.jsx | 45 +++++++++++++
.../widgets/resources/network.test.jsx | 49 ++++++++++++++
.../widgets/resources/uptime.test.jsx | 46 +++++++++++++
7 files changed, 344 insertions(+)
create mode 100644 src/components/version.test.jsx
create mode 100644 src/components/widgets/resources/cpu.test.jsx
create mode 100644 src/components/widgets/resources/cputemp.test.jsx
create mode 100644 src/components/widgets/resources/disk.test.jsx
create mode 100644 src/components/widgets/resources/memory.test.jsx
create mode 100644 src/components/widgets/resources/network.test.jsx
create mode 100644 src/components/widgets/resources/uptime.test.jsx
diff --git a/src/components/version.test.jsx b/src/components/version.test.jsx
new file mode 100644
index 000000000..d5576599f
--- /dev/null
+++ b/src/components/version.test.jsx
@@ -0,0 +1,67 @@
+// @vitest-environment jsdom
+
+import { render, screen } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { cache, cv, useSWR } = vi.hoisted(() => ({
+ cache: {
+ get: vi.fn(),
+ put: vi.fn(),
+ },
+ cv: {
+ validate: vi.fn(),
+ compareVersions: vi.fn(),
+ },
+ useSWR: vi.fn(),
+}));
+
+vi.mock("memory-cache", () => ({
+ default: cache,
+}));
+
+vi.mock("compare-versions", () => ({
+ validate: cv.validate,
+ compareVersions: cv.compareVersions,
+}));
+
+vi.mock("swr", () => ({
+ default: useSWR,
+}));
+
+import Version from "./version";
+
+describe("components/version", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ process.env.NEXT_PUBLIC_VERSION = "dev";
+ process.env.NEXT_PUBLIC_REVISION = "abcdef012345";
+ process.env.NEXT_PUBLIC_BUILDTIME = "2020-01-01T00:00:00.000Z";
+ });
+
+ it("renders non-link version text for dev/main/nightly", () => {
+ cv.validate.mockReturnValue(false);
+ cache.get.mockReturnValue(null);
+ useSWR.mockReturnValue({ data: undefined });
+
+ render();
+
+ expect(screen.getByText(/dev \(abcdef0/)).toBeInTheDocument();
+ expect(screen.queryAllByRole("link")).toHaveLength(0);
+ });
+
+ it("renders tag link and shows update available when a newer release exists", () => {
+ process.env.NEXT_PUBLIC_VERSION = "1.2.3";
+ cv.validate.mockReturnValue(true);
+ cache.get.mockReturnValue(null);
+ useSWR.mockReturnValue({
+ data: [{ tag_name: "1.2.4", html_url: "http://example.com/release" }],
+ });
+ cv.compareVersions.mockReturnValue(1);
+
+ render();
+
+ const links = screen.getAllByRole("link");
+ expect(links.find((a) => a.getAttribute("href")?.includes("/releases/tag/1.2.3"))).toBeTruthy();
+ expect(links.find((a) => a.getAttribute("href") === "http://example.com/release")).toBeTruthy();
+ });
+});
diff --git a/src/components/widgets/resources/cpu.test.jsx b/src/components/widgets/resources/cpu.test.jsx
new file mode 100644
index 000000000..0a2ef019a
--- /dev/null
+++ b/src/components/widgets/resources/cpu.test.jsx
@@ -0,0 +1,47 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() =>
),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import Cpu from "./cpu";
+
+describe("components/widgets/resources/cpu", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders a placeholder Resource while loading", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+
+ render();
+
+ expect(Resource).toHaveBeenCalled();
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("-");
+ expect(props.expanded).toBe(true);
+ });
+
+ it("renders usage/load values when data is present", () => {
+ useSWR.mockReturnValue({
+ data: { cpu: { usage: 12.3, load: 1.23 } },
+ error: undefined,
+ });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("12.3");
+ expect(props.expandedValue).toBe("1.23");
+ expect(props.percentage).toBe(12.3);
+ });
+});
diff --git a/src/components/widgets/resources/cputemp.test.jsx b/src/components/widgets/resources/cputemp.test.jsx
new file mode 100644
index 000000000..bbeeb7129
--- /dev/null
+++ b/src/components/widgets/resources/cputemp.test.jsx
@@ -0,0 +1,45 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() => ),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import CpuTemp from "./cputemp";
+
+describe("components/widgets/resources/cputemp", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders placeholder when temperature data is missing", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("-");
+ });
+
+ it("averages core temps, converts to fahrenheit and computes percentage", () => {
+ useSWR.mockReturnValue({
+ data: { cputemp: { main: 10, cores: [10, 10], max: 20 } },
+ error: undefined,
+ });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ // common.number mock returns string of value
+ expect(props.value).toBe("50");
+ expect(props.expandedValue).toBe("68");
+ expect(props.percentage).toBe(74);
+ });
+});
diff --git a/src/components/widgets/resources/disk.test.jsx b/src/components/widgets/resources/disk.test.jsx
new file mode 100644
index 000000000..8065fd870
--- /dev/null
+++ b/src/components/widgets/resources/disk.test.jsx
@@ -0,0 +1,45 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() => ),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import Disk from "./disk";
+
+describe("components/widgets/resources/disk", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders a placeholder Resource while loading", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("-");
+ });
+
+ it("computes percent used from size/available and renders bytes", () => {
+ useSWR.mockReturnValue({
+ data: { drive: { size: 100, available: 40 } },
+ error: undefined,
+ });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("40");
+ expect(props.expandedValue).toBe("100");
+ expect(props.percentage).toBe(60);
+ });
+});
diff --git a/src/components/widgets/resources/memory.test.jsx b/src/components/widgets/resources/memory.test.jsx
new file mode 100644
index 000000000..408b2678a
--- /dev/null
+++ b/src/components/widgets/resources/memory.test.jsx
@@ -0,0 +1,45 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() => ),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import Memory from "./memory";
+
+describe("components/widgets/resources/memory", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders a placeholder Resource while loading", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("-");
+ });
+
+ it("calculates percentage from active/total and renders available/total", () => {
+ useSWR.mockReturnValue({
+ data: { memory: { available: 10, total: 20, active: 5 } },
+ error: undefined,
+ });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("10");
+ expect(props.expandedValue).toBe("20");
+ expect(props.percentage).toBe(25);
+ });
+});
diff --git a/src/components/widgets/resources/network.test.jsx b/src/components/widgets/resources/network.test.jsx
new file mode 100644
index 000000000..83be9428a
--- /dev/null
+++ b/src/components/widgets/resources/network.test.jsx
@@ -0,0 +1,49 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() => ),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import Network from "./network";
+
+describe("components/widgets/resources/network", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("normalizes options.network=true to default interfaceName in the request", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+
+ render();
+
+ expect(useSWR).toHaveBeenCalledWith(expect.stringContaining("interfaceName=default"), expect.any(Object));
+ });
+
+ it("renders rates and usage percentage when data is present", () => {
+ useSWR.mockReturnValue({
+ data: {
+ network: { rx_sec: 3, tx_sec: 1, rx_bytes: 30, tx_bytes: 10 },
+ },
+ error: undefined,
+ });
+
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toContain("1");
+ expect(props.value).toContain("↑");
+ expect(props.label).toContain("3");
+ expect(props.label).toContain("↓");
+ expect(props.percentage).toBe(75);
+ expect(props.wide).toBe(true);
+ });
+});
diff --git a/src/components/widgets/resources/uptime.test.jsx b/src/components/widgets/resources/uptime.test.jsx
new file mode 100644
index 000000000..f99d83bcd
--- /dev/null
+++ b/src/components/widgets/resources/uptime.test.jsx
@@ -0,0 +1,46 @@
+// @vitest-environment jsdom
+
+import { render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const { useSWR, Resource, Error } = vi.hoisted(() => ({
+ useSWR: vi.fn(),
+ Resource: vi.fn(() => ),
+ Error: vi.fn(() => ),
+}));
+
+vi.mock("swr", () => ({ default: useSWR }));
+vi.mock("../widget/resource", () => ({ default: Resource }));
+vi.mock("../widget/error", () => ({ default: Error }));
+
+import Uptime from "./uptime";
+
+describe("components/widgets/resources/uptime", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("renders a placeholder while loading", () => {
+ useSWR.mockReturnValue({ data: undefined, error: undefined });
+
+ render();
+ expect(Resource).toHaveBeenCalled();
+ expect(Resource.mock.calls[0][0].value).toBe("-");
+ });
+
+ it("renders formatted duration and sets percentage based on current seconds", () => {
+ vi.useFakeTimers();
+ try {
+ vi.setSystemTime(new Date("2020-01-01T00:00:30.000Z"));
+
+ useSWR.mockReturnValue({ data: { uptime: 1234 }, error: undefined });
+ render();
+
+ const props = Resource.mock.calls[0][0];
+ expect(props.value).toBe("1234");
+ expect(props.percentage).toBe("50");
+ } finally {
+ vi.useRealTimers();
+ }
+ });
+});