mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-07 16:30:52 +08:00
Add some more tests
This commit is contained in:
67
src/widgets/komga/component.test.jsx
Normal file
67
src/widgets/komga/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";
|
||||
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/komga/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "komga", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("komga.libraries")).toBeInTheDocument();
|
||||
expect(screen.getByText("komga.series")).toBeInTheDocument();
|
||||
expect(screen.getByText("komga.books")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "komga", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders library/series/book totals when loaded", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: {
|
||||
libraries: [{ id: 1 }, { id: 2 }],
|
||||
series: { totalElements: 10 },
|
||||
books: { totalElements: 20 },
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "komga", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expectBlockValue(container, "komga.libraries", 2);
|
||||
expectBlockValue(container, "komga.series", 10);
|
||||
expectBlockValue(container, "komga.books", 20);
|
||||
});
|
||||
});
|
||||
80
src/widgets/komodo/component.test.jsx
Normal file
80
src/widgets/komodo/component.test.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
// @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";
|
||||
|
||||
describe("widgets/komodo/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("defaults fields for stacks view and skips containers endpoint when showStacks=true and showSummary=false", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // containers (disabled)
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // stacks
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // servers (disabled)
|
||||
|
||||
const service = { widget: { type: "komodo", showStacks: true, showSummary: false } };
|
||||
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(service.widget.fields).toEqual(["total", "running", "down", "unhealthy"]);
|
||||
expect(useWidgetAPI.mock.calls[0][1]).toBe(""); // containersEndpoint
|
||||
expect(useWidgetAPI.mock.calls[1][1]).toBe("stacks");
|
||||
expect(useWidgetAPI.mock.calls[2][1]).toBe(""); // serversEndpoint
|
||||
|
||||
// Default fields filter out "unknown" which is rendered but not in widget.fields.
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("komodo.total")).toBeInTheDocument();
|
||||
expect(screen.getByText("komodo.running")).toBeInTheDocument();
|
||||
expect(screen.getByText("komodo.down")).toBeInTheDocument();
|
||||
expect(screen.getByText("komodo.unhealthy")).toBeInTheDocument();
|
||||
expect(screen.queryByText("komodo.unknown")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders computed down=stopped+down for stacks view", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // containers (disabled)
|
||||
.mockReturnValueOnce({
|
||||
data: { total: 10, running: 7, stopped: 1, down: 2, unhealthy: 3, unknown: 4 },
|
||||
error: undefined,
|
||||
})
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // servers (disabled)
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "komodo", showStacks: true, showSummary: false } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("10")).toBeInTheDocument();
|
||||
expect(screen.getByText("7")).toBeInTheDocument();
|
||||
const downBlock = findServiceBlockByLabel(container, "komodo.down");
|
||||
expect(downBlock).toBeTruthy();
|
||||
expect(downBlock.textContent).toContain("3"); // stopped(1) + down(2)
|
||||
});
|
||||
|
||||
it("renders summary view ratios when showSummary=true", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: { total: 5, running: 4 }, error: undefined }) // containers
|
||||
.mockReturnValueOnce({ data: { total: 2, running: 1 }, error: undefined }) // stacks
|
||||
.mockReturnValueOnce({ data: { total: 1, healthy: 1 }, error: undefined }); // servers
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "komodo", showSummary: true } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("1 / 1")).toBeInTheDocument();
|
||||
expect(screen.getByText("1 / 2")).toBeInTheDocument();
|
||||
expect(screen.getByText("4 / 5")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
83
src/widgets/kopia/component.test.jsx
Normal file
83
src/widgets/kopia/component.test.jsx
Normal file
@@ -0,0 +1,83 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { screen } from "@testing-library/react";
|
||||
import { afterEach, 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/kopia/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2020-01-01T00:00:00Z"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("renders placeholders when status data is missing or source filter finds nothing", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "kopia", snapshotHost: "nope" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("kopia.status")).toBeInTheDocument();
|
||||
expect(screen.getByText("kopia.size")).toBeInTheDocument();
|
||||
expect(screen.getByText("kopia.lastrun")).toBeInTheDocument();
|
||||
expect(screen.getByText("kopia.nextrun")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "kopia" } }} />, { settings: { hideErrors: false } });
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders filtered snapshot status, size, and relative last/next run times", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: {
|
||||
sources: [
|
||||
{
|
||||
source: { host: "hostA", path: "/data" },
|
||||
status: "OK",
|
||||
lastSnapshot: {
|
||||
startTime: "2019-12-31T22:00:00Z", // 2 hours ago
|
||||
stats: { errorCount: 0, totalSize: 1024 },
|
||||
},
|
||||
nextSnapshotTime: "2020-01-01T00:30:00Z", // 30 minutes ahead
|
||||
},
|
||||
],
|
||||
},
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "kopia", snapshotHost: "hostA", snapshotPath: "/data" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expectBlockValue(container, "kopia.status", "OK");
|
||||
expectBlockValue(container, "kopia.size", 1024);
|
||||
expectBlockValue(container, "kopia.lastrun", "2 h");
|
||||
expectBlockValue(container, "kopia.nextrun", "30 m");
|
||||
});
|
||||
});
|
||||
68
src/widgets/kubernetes/component.test.jsx
Normal file
68
src/widgets/kubernetes/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";
|
||||
|
||||
const { useSWR } = vi.hoisted(() => ({ useSWR: vi.fn() }));
|
||||
vi.mock("swr", () => ({ default: useSWR }));
|
||||
|
||||
import Component from "./component";
|
||||
|
||||
describe("widgets/kubernetes/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useSWR.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "kubernetes", namespace: "ns", app: "app" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(useSWR.mock.calls[0][0]).toContain("/api/kubernetes/status/ns/app?");
|
||||
expect(useSWR.mock.calls[1][0]).toContain("/api/kubernetes/stats/ns/app?");
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(2);
|
||||
expect(screen.getByText("docker.cpu")).toBeInTheDocument();
|
||||
expect(screen.getByText("docker.mem")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders offline status when status endpoint reports non-running state", () => {
|
||||
useSWR.mockImplementation((key) => {
|
||||
if (String(key).includes("/status/")) return { data: { status: "stopped" }, error: undefined };
|
||||
if (String(key).includes("/stats/")) return { data: { stats: { cpu: 0.1, mem: 10 } }, error: undefined };
|
||||
return { data: undefined, error: undefined };
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "kubernetes", namespace: "ns", app: "app" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getByText("docker.offline")).toBeInTheDocument();
|
||||
expect(screen.getByText("widget.status")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders cpu percent when cpuLimit is present, otherwise raw cpu number", () => {
|
||||
useSWR.mockImplementation((key) => {
|
||||
if (String(key).includes("/status/")) return { data: { status: "running" }, error: undefined };
|
||||
if (String(key).includes("/stats/"))
|
||||
return {
|
||||
data: { stats: { cpuLimit: true, cpuUsage: 12.3, cpu: 0.0001, mem: 1024 } },
|
||||
error: undefined,
|
||||
};
|
||||
return { data: undefined, error: undefined };
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "kubernetes", namespace: "ns", app: "app" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
// With cpuLimit=true, cpuUsage is formatted via common.percent mock -> string value.
|
||||
expect(screen.getByText("12.3")).toBeInTheDocument();
|
||||
expect(screen.getByText("1024")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
69
src/widgets/lidarr/component.test.jsx
Normal file
69
src/widgets/lidarr/component.test.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
// @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/lidarr/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // artist
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // wanted/missing
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // queue/status
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "lidarr", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("lidarr.wanted")).toBeInTheDocument();
|
||||
expect(screen.getByText("lidarr.queued")).toBeInTheDocument();
|
||||
expect(screen.getByText("lidarr.artists")).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: "lidarr", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders wanted/queued/artist counts when loaded", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: [{ id: 1 }, { id: 2 }], error: undefined })
|
||||
.mockReturnValueOnce({ data: { totalRecords: 10 }, error: undefined })
|
||||
.mockReturnValueOnce({ data: { totalCount: 3 }, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "lidarr", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expectBlockValue(container, "lidarr.wanted", 10);
|
||||
expectBlockValue(container, "lidarr.queued", 3);
|
||||
expectBlockValue(container, "lidarr.artists", 2);
|
||||
});
|
||||
});
|
||||
88
src/widgets/linkwarden/component.test.jsx
Normal file
88
src/widgets/linkwarden/component.test.jsx
Normal file
@@ -0,0 +1,88 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { screen, waitFor } 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/linkwarden/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }) // collections
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined }); // tags
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "linkwarden", url: "http://x" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("linkwarden.links")).toBeInTheDocument();
|
||||
expect(screen.getByText("linkwarden.collections")).toBeInTheDocument();
|
||||
expect(screen.getByText("linkwarden.tags")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when either endpoint errors", () => {
|
||||
useWidgetAPI
|
||||
.mockReturnValueOnce({ data: undefined, error: { message: "nope" } })
|
||||
.mockReturnValueOnce({ data: undefined, error: undefined });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "linkwarden", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("computes totalLinks from collection _count.links once both endpoints are loaded", async () => {
|
||||
useWidgetAPI.mockImplementation((widget, endpoint) => {
|
||||
if (endpoint === "collections") {
|
||||
return {
|
||||
data: {
|
||||
response: [
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
{ _count: { links: 2 } },
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
{ _count: { links: 4 } },
|
||||
],
|
||||
},
|
||||
error: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (endpoint === "tags") {
|
||||
return { data: { response: [{ id: 1 }, { id: 2 }, { id: 3 }] }, error: undefined };
|
||||
}
|
||||
|
||||
return { data: undefined, error: undefined };
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "linkwarden", url: "http://x" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expectBlockValue(container, "linkwarden.links", 6);
|
||||
});
|
||||
expectBlockValue(container, "linkwarden.collections", 2);
|
||||
expectBlockValue(container, "linkwarden.tags", 3);
|
||||
});
|
||||
});
|
||||
106
src/widgets/lubelogger/component.test.jsx
Normal file
106
src/widgets/lubelogger/component.test.jsx
Normal file
@@ -0,0 +1,106 @@
|
||||
// @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/lubelogger/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "lubelogger", url: "http://x" } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("lubelogger.vehicles")).toBeInTheDocument();
|
||||
expect(screen.getByText("lubelogger.serviceRecords")).toBeInTheDocument();
|
||||
expect(screen.getByText("lubelogger.reminders")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "lubelogger", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("filters to vehicleID and renders next reminder details when found", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: [
|
||||
{
|
||||
vehicleData: { id: 1, year: 2020, model: "Model A" },
|
||||
veryUrgentReminderCount: 1,
|
||||
urgentReminderCount: 2,
|
||||
notUrgentReminderCount: 3,
|
||||
serviceRecordCount: 5,
|
||||
nextReminder: { dueDate: 123 },
|
||||
},
|
||||
{
|
||||
vehicleData: { id: 2, year: 2021, model: "Model B" },
|
||||
veryUrgentReminderCount: 0,
|
||||
urgentReminderCount: 0,
|
||||
notUrgentReminderCount: 0,
|
||||
serviceRecordCount: 1,
|
||||
nextReminder: null,
|
||||
},
|
||||
],
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "lubelogger", url: "http://x", vehicleID: 1 } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expectBlockValue(container, "lubelogger.vehicle", "2020 Model A");
|
||||
expectBlockValue(container, "lubelogger.serviceRecords", 5);
|
||||
expectBlockValue(container, "lubelogger.reminders", 6);
|
||||
expectBlockValue(container, "lubelogger.nextReminder", 123);
|
||||
});
|
||||
|
||||
it("shows an error when vehicleID is set but not found", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: [
|
||||
{
|
||||
vehicleData: { id: 2, year: 2021, model: "Model B" },
|
||||
veryUrgentReminderCount: 0,
|
||||
urgentReminderCount: 0,
|
||||
notUrgentReminderCount: 0,
|
||||
serviceRecordCount: 0,
|
||||
},
|
||||
],
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "lubelogger", url: "http://x", vehicleID: 1 } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("Vehicle not found")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
73
src/widgets/mailcow/component.test.jsx
Normal file
73
src/widgets/mailcow/component.test.jsx
Normal file
@@ -0,0 +1,73 @@
|
||||
// @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/mailcow/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "mailcow", url: "http://x" } }} />,
|
||||
{
|
||||
settings: { hideErrors: false },
|
||||
},
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("mailcow.mailboxes")).toBeInTheDocument();
|
||||
expect(screen.getByText("mailcow.aliases")).toBeInTheDocument();
|
||||
expect(screen.getByText("mailcow.quarantined")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows a helpful error when the API returns no domains", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: [], error: undefined });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "mailcow", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("No domains found")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders computed totals when loaded", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: [
|
||||
{ mboxes_in_domain: "2", msgs_total: "10", bytes_total: "100" },
|
||||
{ mboxes_in_domain: "1", msgs_total: "5", bytes_total: "50" },
|
||||
],
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "mailcow", url: "http://x" } }} />,
|
||||
{
|
||||
settings: { hideErrors: false },
|
||||
},
|
||||
);
|
||||
|
||||
expectBlockValue(container, "mailcow.domains", 2);
|
||||
expectBlockValue(container, "mailcow.mailboxes", 3);
|
||||
expectBlockValue(container, "mailcow.mails", 15);
|
||||
expectBlockValue(container, "mailcow.storage", 150);
|
||||
});
|
||||
});
|
||||
69
src/widgets/mastodon/component.test.jsx
Normal file
69
src/widgets/mastodon/component.test.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
// @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/mastodon/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "mastodon", url: "http://x" } }} />,
|
||||
{
|
||||
settings: { hideErrors: false },
|
||||
},
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
|
||||
expect(screen.getByText("mastodon.user_count")).toBeInTheDocument();
|
||||
expect(screen.getByText("mastodon.status_count")).toBeInTheDocument();
|
||||
expect(screen.getByText("mastodon.domain_count")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders error UI when widget API errors", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: { message: "nope" } });
|
||||
|
||||
renderWithProviders(<Component service={{ widget: { type: "mastodon", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(screen.getAllByText(/widget\.api_error/i).length).toBeGreaterThan(0);
|
||||
expect(screen.getByText("nope")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders instance stats when loaded", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: { stats: { user_count: 1, status_count: 2, domain_count: 3 } },
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "mastodon", url: "http://x" } }} />,
|
||||
{
|
||||
settings: { hideErrors: false },
|
||||
},
|
||||
);
|
||||
|
||||
expectBlockValue(container, "mastodon.user_count", 1);
|
||||
expectBlockValue(container, "mastodon.status_count", 2);
|
||||
expectBlockValue(container, "mastodon.domain_count", 3);
|
||||
});
|
||||
});
|
||||
57
src/widgets/mealie/component.test.jsx
Normal file
57
src/widgets/mealie/component.test.jsx
Normal file
@@ -0,0 +1,57 @@
|
||||
// @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/mealie/component", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("uses v1 endpoint by default and renders placeholders while loading", () => {
|
||||
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||
|
||||
const { container } = renderWithProviders(<Component service={{ widget: { type: "mealie", url: "http://x" } }} />, {
|
||||
settings: { hideErrors: false },
|
||||
});
|
||||
|
||||
expect(useWidgetAPI.mock.calls[0][1]).toBe("statisticsv1");
|
||||
expect(container.querySelectorAll(".service-block")).toHaveLength(4);
|
||||
expect(screen.getByText("mealie.recipes")).toBeInTheDocument();
|
||||
expect(screen.getByText("mealie.users")).toBeInTheDocument();
|
||||
expect(screen.getByText("mealie.categories")).toBeInTheDocument();
|
||||
expect(screen.getByText("mealie.tags")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("uses v2 endpoint when widget.version === 2 and renders counts", () => {
|
||||
useWidgetAPI.mockReturnValue({
|
||||
data: { totalRecipes: 1, totalUsers: 2, totalCategories: 3, totalTags: 4 },
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<Component service={{ widget: { type: "mealie", url: "http://x", version: 2 } }} />,
|
||||
{ settings: { hideErrors: false } },
|
||||
);
|
||||
|
||||
expect(useWidgetAPI.mock.calls[0][1]).toBe("statisticsv2");
|
||||
expectBlockValue(container, "mealie.recipes", 1);
|
||||
expectBlockValue(container, "mealie.users", 2);
|
||||
expectBlockValue(container, "mealie.categories", 3);
|
||||
expectBlockValue(container, "mealie.tags", 4);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user