mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-08 00:40:52 +08:00
Add widget component tests (medusa..netalertx)
This commit is contained in:
81
src/widgets/medusa/component.test.jsx
Normal file
81
src/widgets/medusa/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";
|
||||||
|
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/medusa/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "medusa" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||||
|
expect(screen.getByText("medusa.wanted")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("medusa.queued")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("medusa.series")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when either endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "future") return { data: undefined, error: { message: "nope" } };
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "medusa" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("computes wanted total from future lists and renders stats", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "future") {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
data: {
|
||||||
|
later: [{ id: 1 }],
|
||||||
|
missed: [{ id: 2 }, { id: 3 }],
|
||||||
|
soon: [],
|
||||||
|
today: [{ id: 4 }, { id: 5 }, { id: 6 }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint === "stats") {
|
||||||
|
return { data: { data: { ep_snatched: 7, shows_active: 8 } }, error: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "medusa" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBlockValue(container, "medusa.wanted", 6);
|
||||||
|
expectBlockValue(container, "medusa.queued", 7);
|
||||||
|
expectBlockValue(container, "medusa.series", 8);
|
||||||
|
});
|
||||||
|
});
|
||||||
82
src/widgets/mikrotik/component.test.jsx
Normal file
82
src/widgets/mikrotik/component.test.jsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// @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/mikrotik/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "mikrotik" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||||
|
expect(screen.getByText("mikrotik.uptime")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("mikrotik.cpuLoad")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("mikrotik.memoryUsed")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("mikrotik.numberOfLeases")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when either endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "leases") return { data: undefined, error: { message: "nope" } };
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "mikrotik" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders uptime, cpu load, memory used, and lease count", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "system") {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
uptime: "1d",
|
||||||
|
"cpu-load": 10,
|
||||||
|
"free-memory": 25,
|
||||||
|
"total-memory": 100,
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint === "leases") {
|
||||||
|
return { data: [{ id: 1 }, { id: 2 }, { id: 3 }], error: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "mikrotik" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
// memoryUsed = 100 - (25/100)*100 = 75
|
||||||
|
expectBlockValue(container, "mikrotik.uptime", "1d");
|
||||||
|
expectBlockValue(container, "mikrotik.cpuLoad", 10);
|
||||||
|
expectBlockValue(container, "mikrotik.memoryUsed", 75);
|
||||||
|
expectBlockValue(container, "mikrotik.numberOfLeases", 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
65
src/widgets/minecraft/component.test.jsx
Normal file
65
src/widgets/minecraft/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";
|
||||||
|
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/minecraft/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "minecraft" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||||
|
expect(screen.getByText("minecraft.status")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("minecraft.players")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("minecraft.version")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when status endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "minecraft" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders status, players, and version when loaded", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: {
|
||||||
|
online: true,
|
||||||
|
players: { online: 2, max: 10 },
|
||||||
|
version: "1.20.1",
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "minecraft" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBlockValue(container, "minecraft.status", "minecraft.up");
|
||||||
|
expectBlockValue(container, "minecraft.players", "2 / 10");
|
||||||
|
expectBlockValue(container, "minecraft.version", "1.20.1");
|
||||||
|
});
|
||||||
|
});
|
||||||
56
src/widgets/miniflux/component.test.jsx
Normal file
56
src/widgets/miniflux/component.test.jsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// @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/miniflux/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "miniflux" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(2);
|
||||||
|
expect(screen.getByText("miniflux.unread")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("miniflux.read")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when counters endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "miniflux" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders unread and read counters when loaded", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: { unread: 3, read: 7 }, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "miniflux" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBlockValue(container, "miniflux.unread", 3);
|
||||||
|
expectBlockValue(container, "miniflux.read", 7);
|
||||||
|
});
|
||||||
|
});
|
||||||
29
src/widgets/mjpeg/component.test.jsx
Normal file
29
src/widgets/mjpeg/component.test.jsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
// next/image requires Next runtime features; stub it for component tests.
|
||||||
|
vi.mock("next/image", () => ({
|
||||||
|
default: (props) => {
|
||||||
|
const { src, alt, objectFit, className, onError } = props;
|
||||||
|
return <img alt={alt} src={src} data-object-fit={objectFit} className={className} onError={onError} />;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
import Component from "./component";
|
||||||
|
|
||||||
|
describe("widgets/mjpeg/component", () => {
|
||||||
|
it("renders the stream images", () => {
|
||||||
|
render(<Component service={{ widget: { type: "mjpeg", stream: "http://example/stream.jpg", fit: "cover" } }} />);
|
||||||
|
|
||||||
|
const imgs = screen.getAllByAltText("stream");
|
||||||
|
expect(imgs).toHaveLength(2);
|
||||||
|
expect(imgs[0].getAttribute("src")).toBe("http://example/stream.jpg");
|
||||||
|
expect(imgs[1].getAttribute("src")).toBe("http://example/stream.jpg");
|
||||||
|
|
||||||
|
// Both renders pass through objectFit; the first is "fill", the second uses widget.fit.
|
||||||
|
expect(imgs[0].getAttribute("data-object-fit")).toBe("fill");
|
||||||
|
expect(imgs[1].getAttribute("data-object-fit")).toBe("cover");
|
||||||
|
});
|
||||||
|
});
|
||||||
90
src/widgets/moonraker/component.test.jsx
Normal file
90
src/widgets/moonraker/component.test.jsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// @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/moonraker/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "moonraker" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(1);
|
||||||
|
expect(screen.getByText("moonraker.printer_state")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders printer state as shutdown when webhook reports shutdown", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "print_stats") {
|
||||||
|
return { data: { result: { status: { print_stats: { state: "standby", info: {} } } } }, error: undefined };
|
||||||
|
}
|
||||||
|
if (endpoint === "display_status") {
|
||||||
|
return { data: { result: { status: { display_status: { progress: 0 } } } }, error: undefined };
|
||||||
|
}
|
||||||
|
if (endpoint === "webhooks") {
|
||||||
|
return { data: { result: { status: { webhooks: { state: "shutdown" } } } }, error: undefined };
|
||||||
|
}
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "moonraker" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(1);
|
||||||
|
expectBlockValue(container, "moonraker.printer_state", "shutdown");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders layers, progress and print status when active", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "print_stats") {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
result: {
|
||||||
|
status: {
|
||||||
|
print_stats: { state: "printing", info: { current_layer: 1, total_layer: 2 } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (endpoint === "display_status") {
|
||||||
|
return { data: { result: { status: { display_status: { progress: 0.25 } } } }, error: undefined };
|
||||||
|
}
|
||||||
|
if (endpoint === "webhooks") {
|
||||||
|
return { data: { result: { status: { webhooks: { state: "ready" } } } }, error: undefined };
|
||||||
|
}
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "moonraker" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||||
|
expectBlockValue(container, "moonraker.layers", "1 / 2");
|
||||||
|
expectBlockValue(container, "moonraker.print_progress", 25);
|
||||||
|
expectBlockValue(container, "moonraker.print_status", "printing");
|
||||||
|
});
|
||||||
|
});
|
||||||
68
src/widgets/mylar/component.test.jsx
Normal file
68
src/widgets/mylar/component.test.jsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// @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/mylar/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "mylar" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||||
|
expect(screen.getByText("mylar.series")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("mylar.issues")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("mylar.wanted")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when any endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "issues") return { data: undefined, error: { message: "nope" } };
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "mylar" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders series count, total issues, and wanted issues", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "series") return { data: { data: [{ id: 1 }, { id: 2 }] }, error: undefined };
|
||||||
|
if (endpoint === "issues") {
|
||||||
|
return { data: { data: [{ totalIssues: 3 }, { totalIssues: 4 }] }, error: undefined };
|
||||||
|
}
|
||||||
|
if (endpoint === "wanted") return { data: { issues: [{ id: 1 }] }, error: undefined };
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "mylar" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBlockValue(container, "mylar.series", 2);
|
||||||
|
expectBlockValue(container, "mylar.issues", 7);
|
||||||
|
expectBlockValue(container, "mylar.wanted", 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
59
src/widgets/myspeed/component.test.jsx
Normal file
59
src/widgets/myspeed/component.test.jsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// @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/myspeed/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "myspeed" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||||
|
expect(screen.getByText("myspeed.download")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("myspeed.upload")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("myspeed.ping")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error UI when endpoint errors", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "myspeed" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders download, upload and ping when loaded", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: [{ download: 1, upload: 2, ping: 3 }], error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "myspeed" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
// t("common.bitrate") returns the raw value from setup; widget multiplies by 1e6.
|
||||||
|
expectBlockValue(container, "myspeed.download", 1000 * 1000);
|
||||||
|
expectBlockValue(container, "myspeed.upload", 2 * 1000 * 1000);
|
||||||
|
expectBlockValue(container, "myspeed.ping", 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
53
src/widgets/navidrome/component.test.jsx
Normal file
53
src/widgets/navidrome/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/navidrome/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders a waiting row while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "navidrome" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getByText("navidrome.please_wait")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders an error container when the API errors", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "navidrome" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders now playing entries when present", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: {
|
||||||
|
"subsonic-response": {
|
||||||
|
nowPlaying: {
|
||||||
|
entry: {
|
||||||
|
0: { id: "a", title: "Song", artist: "Artist", album: "Album", username: "user" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "navidrome" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getByText("Artist - Song — Album (user)")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
55
src/widgets/netalertx/component.test.jsx
Normal file
55
src/widgets/netalertx/component.test.jsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// @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/netalertx/component", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders placeholders while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "netalertx" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||||
|
expect(screen.getByText("netalertx.total")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("netalertx.connected")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("netalertx.new_devices")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("netalertx.down_alerts")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses datav2 endpoint for version > 1 and renders parsed totals", () => {
|
||||||
|
useWidgetAPI.mockImplementation((_widget, endpoint) => {
|
||||||
|
if (endpoint === "datav2") return { data: ["10", "5", "0", "2", "1"], error: undefined };
|
||||||
|
return { data: undefined, error: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "netalertx", version: 2 } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(useWidgetAPI).toHaveBeenCalled();
|
||||||
|
expectBlockValue(container, "netalertx.total", 10);
|
||||||
|
expectBlockValue(container, "netalertx.connected", 5);
|
||||||
|
expectBlockValue(container, "netalertx.new_devices", 2);
|
||||||
|
expectBlockValue(container, "netalertx.down_alerts", 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user