mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-07 16:30:52 +08:00
Test: 10 more widget components
This commit is contained in:
50
src/widgets/booklore/component.test.jsx
Normal file
50
src/widgets/booklore/component.test.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/booklore/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "booklore" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("booklore.libraries")).toBeInTheDocument();
|
||||
expect(screen.getByText("booklore.books")).toBeInTheDocument();
|
||||
expect(screen.getByText("booklore.reading")).toBeInTheDocument();
|
||||
expect(screen.getByText("booklore.finished")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders values with nullish fallback defaults", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: { libraries: 1, books: 2, finished: 4 }, // reading missing -> 0
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "booklore" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(screen.getByText("1")).toBeInTheDocument();
|
||||
expect(screen.getByText("2")).toBeInTheDocument();
|
||||
expect(screen.getByText("0")).toBeInTheDocument();
|
||||
expect(screen.getByText("4")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
74
src/widgets/firefly/component.test.jsx
Normal file
74
src/widgets/firefly/component.test.jsx
Normal file
@@ -0,0 +1,74 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/firefly/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "firefly" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(2);
|
||||
expect(screen.getByText("firefly.networth")).toBeInTheDocument();
|
||||
expect(screen.getByText("firefly.budget")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when either request errors", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: { message: "nope" } }) // summary
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // budgets
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "firefly" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
// The widget uses a string error, which Error normalizes to { message }.
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("Failed to load Firefly account summary and budgets")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders net worth and budget summary", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({
|
||||
data: { "net-worth-in-EUR": { value_parsed: "100" } },
|
||||
error: undefined,
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
type: "available_budgets",
|
||||
attributes: {
|
||||
amount: "100",
|
||||
currency_symbol: "$",
|
||||
spent_in_budgets: [{ sum: "-10" }],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "firefly" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(screen.getByText("100")).toBeInTheDocument();
|
||||
expect(screen.getByText("$ 10 / $ 100")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
65
src/widgets/jellystat/component.test.jsx
Normal file
65
src/widgets/jellystat/component.test.jsx
Normal file
@@ -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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/jellystat/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("defaults invalid days to 30 and renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const service = { widget: { type: "jellystat", days: -1 } };
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(service.widget.days).toBe(30);
|
||||
expect(useWidgetAPI).toHaveBeenCalledWith(service.widget, "getViewsByLibraryType", { days: 30 });
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("jellystat.songs")).toBeInTheDocument();
|
||||
expect(screen.getByText("jellystat.movies")).toBeInTheDocument();
|
||||
expect(screen.getByText("jellystat.episodes")).toBeInTheDocument();
|
||||
expect(screen.getByText("jellystat.other")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "jellystat", days: 7 } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders values when loaded", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: { Audio: 1, Movie: 2, Series: 3, Other: 4 },
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "jellystat", days: 7 } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("1")).toBeInTheDocument();
|
||||
expect(screen.getByText("2")).toBeInTheDocument();
|
||||
expect(screen.getByText("3")).toBeInTheDocument();
|
||||
expect(screen.getByText("4")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
83
src/widgets/nextcloud/component.test.jsx
Normal file
83
src/widgets/nextcloud/component.test.jsx
Normal file
@@ -0,0 +1,83 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/nextcloud/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders default placeholders (no cpu/memory blocks when fields are unset)", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "nextcloud" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.queryByText("nextcloud.cpuload")).toBeNull();
|
||||
expect(screen.queryByText("nextcloud.memoryusage")).toBeNull();
|
||||
expect(screen.getByText("nextcloud.freespace")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.activeusers")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.numfiles")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.numshares")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("respects widget.fields and renders computed values", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: {
|
||||
ocs: {
|
||||
data: {
|
||||
nextcloud: {
|
||||
system: {
|
||||
cpuload: [0.5],
|
||||
mem_total: "100",
|
||||
mem_free: "50",
|
||||
freespace: 1024,
|
||||
},
|
||||
storage: { num_files: 1 },
|
||||
shares: { num_shares: 2 },
|
||||
},
|
||||
activeUsers: { last24hours: 3 },
|
||||
},
|
||||
},
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
// 4 fields triggers the legacy behavior where CPU + memory are shown;
|
||||
// Container then filters to exactly these fields.
|
||||
const service = {
|
||||
widget: { type: "nextcloud", fields: ["cpuload", "memoryusage", "freespace", "activeusers"] },
|
||||
};
|
||||
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("nextcloud.cpuload")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.memoryusage")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.freespace")).toBeInTheDocument();
|
||||
expect(screen.getByText("nextcloud.activeusers")).toBeInTheDocument();
|
||||
expect(screen.queryByText("nextcloud.numfiles")).toBeNull();
|
||||
expect(screen.queryByText("nextcloud.numshares")).toBeNull();
|
||||
|
||||
// Values: cpu load 0.5, memory usage 50, freespace 1024, active users 3.
|
||||
expect(screen.getByText("0.5")).toBeInTheDocument();
|
||||
expect(screen.getByText("50")).toBeInTheDocument();
|
||||
expect(screen.getByText("1024")).toBeInTheDocument();
|
||||
expect(screen.getByText("3")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
52
src/widgets/peanut/component.test.jsx
Normal file
52
src/widgets/peanut/component.test.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/peanut/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "peanut" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("peanut.battery_charge")).toBeInTheDocument();
|
||||
expect(screen.getByText("peanut.ups_load")).toBeInTheDocument();
|
||||
expect(screen.getByText("peanut.ups_status")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders legacy field mapping and status translation", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: {
|
||||
"battery.charge": 55,
|
||||
"ups.load": 12,
|
||||
"ups.status": "OL",
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "peanut" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(screen.getByText("55")).toBeInTheDocument();
|
||||
expect(screen.getByText("12")).toBeInTheDocument();
|
||||
expect(screen.getByText("peanut.online")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
77
src/widgets/proxmoxbackupserver/component.test.jsx
Normal file
77
src/widgets/proxmoxbackupserver/component.test.jsx
Normal file
@@ -0,0 +1,77 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/proxmoxbackupserver/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // datastore
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // tasks
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // host
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "proxmoxbackupserver" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("proxmoxbackupserver.datastore_usage")).toBeInTheDocument();
|
||||
expect(screen.getByText("proxmoxbackupserver.failed_tasks_24h")).toBeInTheDocument();
|
||||
expect(screen.getByText("proxmoxbackupserver.cpu_usage")).toBeInTheDocument();
|
||||
expect(screen.getByText("proxmoxbackupserver.memory_usage")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when any endpoint errors", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined })
|
||||
.mockReturnValueOnce({ data: undefined, error: { message: "nope" } })
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "proxmoxbackupserver" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders computed values and caps failed tasks at 99+", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({
|
||||
data: {
|
||||
data: [
|
||||
{ store: "ds1", used: 50, total: 100 },
|
||||
{ store: "ds2", used: 25, total: 50 },
|
||||
],
|
||||
},
|
||||
error: undefined,
|
||||
})
|
||||
.mockReturnValueOnce({ data: { total: 1000 }, error: undefined })
|
||||
.mockReturnValueOnce({ data: { data: { cpu: 0.2, memory: { used: 1, total: 4 } } }, error: undefined });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "proxmoxbackupserver", datastore: "ds2" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
// datastore usage for ds2: 25/50*100 = 50
|
||||
expect(screen.getByText("50")).toBeInTheDocument();
|
||||
expect(screen.getByText("20")).toBeInTheDocument(); // cpu usage
|
||||
expect(screen.getByText("25")).toBeInTheDocument(); // memory usage
|
||||
expect(screen.getByText("99+")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
63
src/widgets/rutorrent/component.test.jsx
Normal file
63
src/widgets/rutorrent/component.test.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/rutorrent/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "rutorrent" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("rutorrent.active")).toBeInTheDocument();
|
||||
expect(screen.getByText("rutorrent.upload")).toBeInTheDocument();
|
||||
expect(screen.getByText("rutorrent.download")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "rutorrent" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders computed active/upload/download values", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: [
|
||||
{ "d.get_state": "1", "d.get_up_rate": "10", "d.get_down_rate": "5" },
|
||||
{ "d.get_state": "0", "d.get_up_rate": "20", "d.get_down_rate": "15" },
|
||||
{ "d.get_state": "1", "d.get_up_rate": "0", "d.get_down_rate": "0" },
|
||||
],
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "rutorrent" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("2")).toBeInTheDocument(); // active torrents
|
||||
expect(screen.getByText("30")).toBeInTheDocument(); // upload sum (common.byterate mocked)
|
||||
expect(screen.getByText("20")).toBeInTheDocument(); // download sum (common.byterate mocked)
|
||||
});
|
||||
});
|
||||
53
src/widgets/swagdashboard/component.test.jsx
Normal file
53
src/widgets/swagdashboard/component.test.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/swagdashboard/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "swagdashboard" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("swagdashboard.proxied")).toBeInTheDocument();
|
||||
expect(screen.getByText("swagdashboard.auth")).toBeInTheDocument();
|
||||
expect(screen.getByText("swagdashboard.outdated")).toBeInTheDocument();
|
||||
expect(screen.getByText("swagdashboard.banned")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders values when loaded", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: { proxied: 1, auth: 2, outdated: 3, banned: 4 },
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "swagdashboard" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("1")).toBeInTheDocument();
|
||||
expect(screen.getByText("2")).toBeInTheDocument();
|
||||
expect(screen.getByText("3")).toBeInTheDocument();
|
||||
expect(screen.getByText("4")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
81
src/widgets/truenas/component.test.jsx
Normal file
81
src/widgets/truenas/component.test.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
// Pool is rendered outside of the main Container; stub it to a simple marker.
|
||||
vi.mock("widgets/truenas/pool", () => ({
|
||||
default: ({ name, healthy, allocated, free }) => (
|
||||
<div
|
||||
data-testid="truenas-pool"
|
||||
data-name={name}
|
||||
data-healthy={String(healthy)}
|
||||
data-allocated={allocated}
|
||||
data-free={free}
|
||||
/>
|
||||
),
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/truenas/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading (no pools)", () => {
|
||||
useWidgetAPI.mockImplementation(() => ({ data: undefined, error: undefined }));
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "truenas" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("truenas.load")).toBeInTheDocument();
|
||||
expect(screen.getByText("truenas.uptime")).toBeInTheDocument();
|
||||
expect(screen.getByText("truenas.alerts")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("truenas-pool")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders values and pool list when enablePools is on and data is present", () => {
|
||||
useWidgetAPI.mockImplementation((widget, endpoint) => {
|
||||
if (endpoint === "alerts") return { data: { pending: 7 }, error: undefined };
|
||||
if (endpoint === "status") return { data: { loadavg: [1.23], uptime_seconds: 3600 }, error: undefined };
|
||||
if (endpoint === "pools") return { data: [{ id: "1", name: "tank", healthy: true }], error: undefined };
|
||||
if (endpoint === "dataset")
|
||||
return {
|
||||
data: [{ pool: "tank", name: "tank", used: { parsed: 10 }, available: { parsed: 20 } }],
|
||||
error: undefined,
|
||||
};
|
||||
return { data: undefined, error: undefined };
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "truenas", enablePools: true } }} />,
|
||||
{
|
||||
settings: { hideErrors: false },
|
||||
},
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("1.23")).toBeInTheDocument();
|
||||
expect(screen.getByText("3600")).toBeInTheDocument(); // common.duration mocked
|
||||
expect(screen.getByText("7")).toBeInTheDocument();
|
||||
|
||||
const pool = screen.getByTestId("truenas-pool");
|
||||
expect(pool.getAttribute("data-name")).toBe("tank");
|
||||
expect(pool.getAttribute("data-healthy")).toBe("true");
|
||||
expect(pool.getAttribute("data-allocated")).toBe("10");
|
||||
expect(pool.getAttribute("data-free")).toBe("20");
|
||||
});
|
||||
});
|
||||
67
src/widgets/unraid/component.test.jsx
Normal file
67
src/widgets/unraid/component.test.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
// @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";
|
||||
|
||||
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||
useWidgetAPI: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("utils/proxy/use-widget-api", () => ({
|
||||
default: useWidgetAPI,
|
||||
}));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/unraid/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("defaults widget.fields and filters down to 4 visible blocks while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const service = { widget: { type: "unraid" } };
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
// Component sets default fields
|
||||
expect(service.widget.fields).toEqual(["status", "cpu", "memoryPercent", "notifications"]);
|
||||
|
||||
// Container filters the many placeholder Blocks down to the selected fields.
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("unraid.status")).toBeInTheDocument();
|
||||
expect(screen.getByText("unraid.cpu")).toBeInTheDocument();
|
||||
expect(screen.getByText("unraid.notifications")).toBeInTheDocument();
|
||||
expect(screen.getByText("unraid.memoryUsed")).toBeInTheDocument();
|
||||
expect(screen.queryByText("unraid.memoryAvailable")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders values for the default fields", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: {
|
||||
arrayState: "started",
|
||||
cpuPercent: 12,
|
||||
memoryAvailable: 100,
|
||||
memoryUsed: 50,
|
||||
memoryUsedPercent: 33,
|
||||
unreadNotifications: 7,
|
||||
arrayUsed: 1,
|
||||
arrayFree: 2,
|
||||
arrayUsedPercent: 3,
|
||||
caches: {},
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const service = { widget: { type: "unraid" } };
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("unraid.started")).toBeInTheDocument();
|
||||
expect(screen.getByText("12")).toBeInTheDocument();
|
||||
expect(screen.getByText("33")).toBeInTheDocument();
|
||||
expect(screen.getByText("7")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,8 @@ import { cleanup } from "@testing-library/react";
|
||||
import { afterEach, vi } from "vitest";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
// Node-environment tests shouldn't require jsdom; guard cleanup accordingly.
|
||||
if (typeof document !== "undefined") cleanup();
|
||||
});
|
||||
|
||||
// implement a couple of common formatters mocked in next-i18next
|
||||
@@ -13,6 +14,10 @@ vi.mock("next-i18next", () => ({
|
||||
t: (key, opts) => {
|
||||
if (key === "common.number") return String(opts?.value ?? "");
|
||||
if (key === "common.percent") return String(opts?.value ?? "");
|
||||
if (key === "common.bytes") return String(opts?.value ?? "");
|
||||
if (key === "common.bbytes") return String(opts?.value ?? "");
|
||||
if (key === "common.byterate") return String(opts?.value ?? "");
|
||||
if (key === "common.duration") return String(opts?.value ?? "");
|
||||
return key;
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user