mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-08 00:40:52 +08:00
test: cover widget internal modules (calendar, openwrt, omv, truenas, jdownloader)
This commit is contained in:
64
src/widgets/calendar/agenda.test.jsx
Normal file
64
src/widgets/calendar/agenda.test.jsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { EventStub, compareDateTimezoneStub } = vi.hoisted(() => ({
|
||||||
|
EventStub: vi.fn(({ event, showDate, showTime }) => (
|
||||||
|
<div data-testid="event" data-showdate={showDate ? "1" : "0"} data-showtime={showTime ? "1" : "0"}>
|
||||||
|
{event.title}
|
||||||
|
</div>
|
||||||
|
)),
|
||||||
|
compareDateTimezoneStub: vi.fn(
|
||||||
|
(date, event) => date.startOf("day").toISODate() === event.date.startOf("day").toISODate(),
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./event", () => ({
|
||||||
|
default: EventStub,
|
||||||
|
compareDateTimezone: compareDateTimezoneStub,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import Agenda from "./agenda";
|
||||||
|
|
||||||
|
describe("widgets/calendar/agenda", () => {
|
||||||
|
it("renders an empty placeholder when showDate is not set", () => {
|
||||||
|
const { container } = render(<Agenda service={{ widget: {} }} colorVariants={{}} events={{}} showDate={null} />);
|
||||||
|
expect(container.textContent).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders a no-events placeholder when there are no events in range", () => {
|
||||||
|
render(<Agenda service={{ widget: {} }} colorVariants={{}} events={{}} showDate={DateTime.now()} />);
|
||||||
|
expect(screen.getByText("calendar.noEventsToday")).toBeInTheDocument();
|
||||||
|
expect(EventStub).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters by previousDays, sorts, and enforces maxEvents", () => {
|
||||||
|
const showDate = DateTime.local(2099, 1, 2).startOf("day");
|
||||||
|
const service = { widget: { previousDays: 0, maxEvents: 2, showTime: true } };
|
||||||
|
|
||||||
|
const events = {
|
||||||
|
old: { title: "Old", date: DateTime.local(2099, 1, 1, 0, 0), color: "gray" },
|
||||||
|
a: { title: "A", date: DateTime.local(2099, 1, 2, 10, 0), color: "gray" },
|
||||||
|
b: { title: "B", date: DateTime.local(2099, 1, 3, 10, 0), color: "gray" },
|
||||||
|
c: { title: "C", date: DateTime.local(2099, 1, 4, 10, 0), color: "gray" },
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<Agenda service={service} colorVariants={{}} events={events} showDate={showDate} />);
|
||||||
|
|
||||||
|
// Old is filtered out, C is sliced out by maxEvents.
|
||||||
|
expect(screen.queryByText("Old")).toBeNull();
|
||||||
|
expect(screen.getByText("A")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("B")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("C")).toBeNull();
|
||||||
|
|
||||||
|
const renderedEvents = screen.getAllByTestId("event");
|
||||||
|
expect(renderedEvents).toHaveLength(2);
|
||||||
|
|
||||||
|
// showTime is only true for the selected day.
|
||||||
|
const [first, second] = renderedEvents;
|
||||||
|
expect(first).toHaveAttribute("data-showtime", "1");
|
||||||
|
expect(second).toHaveAttribute("data-showtime", "0");
|
||||||
|
});
|
||||||
|
});
|
||||||
56
src/widgets/calendar/event.test.jsx
Normal file
56
src/widgets/calendar/event.test.jsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import Event, { compareDateTimezone } from "./event";
|
||||||
|
|
||||||
|
describe("widgets/calendar/event", () => {
|
||||||
|
it("renders an anchor when a url is provided and toggles additional text on hover", () => {
|
||||||
|
const date = DateTime.fromISO("2099-01-01T13:00:00.000Z").setZone("utc");
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Event
|
||||||
|
event={{
|
||||||
|
title: "Primary",
|
||||||
|
additional: "More info",
|
||||||
|
date,
|
||||||
|
color: "gray",
|
||||||
|
url: "https://example.com",
|
||||||
|
isCompleted: true,
|
||||||
|
}}
|
||||||
|
colorVariants={{ gray: "bg-gray-500" }}
|
||||||
|
showDate
|
||||||
|
showTime
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const link = screen.getByRole("link", { name: /primary/i });
|
||||||
|
expect(link).toHaveAttribute("href", "https://example.com");
|
||||||
|
expect(link).toHaveAttribute("target", "_blank");
|
||||||
|
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||||
|
|
||||||
|
// time is rendered when showTime=true
|
||||||
|
expect(link.textContent).toContain("13:00");
|
||||||
|
|
||||||
|
// default shows title, hover shows `additional`
|
||||||
|
expect(screen.getByText("Primary")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("More info")).toBeNull();
|
||||||
|
|
||||||
|
fireEvent.mouseEnter(link);
|
||||||
|
expect(screen.getByText("More info")).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.mouseLeave(link);
|
||||||
|
expect(screen.getByText("Primary")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// completed icon from react-icons renders an SVG
|
||||||
|
expect(link.querySelector("svg")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("compareDateTimezone matches dates by day", () => {
|
||||||
|
const day = DateTime.fromISO("2099-01-01T00:00:00.000Z").setZone("utc");
|
||||||
|
expect(compareDateTimezone(day, { date: DateTime.fromISO("2099-01-01T23:59:00.000Z").setZone("utc") })).toBe(true);
|
||||||
|
expect(compareDateTimezone(day, { date: DateTime.fromISO("2099-01-02T00:00:00.000Z").setZone("utc") })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
64
src/widgets/calendar/integrations/ical.test.jsx
Normal file
64
src/widgets/calendar/integrations/ical.test.jsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||||
|
useWidgetAPI: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
|
||||||
|
|
||||||
|
import Integration from "./ical";
|
||||||
|
|
||||||
|
describe("widgets/calendar/integrations/ical", () => {
|
||||||
|
it("adds parsed events within the date range", async () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: {
|
||||||
|
data: [
|
||||||
|
"BEGIN:VCALENDAR",
|
||||||
|
"VERSION:2.0",
|
||||||
|
"PRODID:-//Test//EN",
|
||||||
|
"BEGIN:VEVENT",
|
||||||
|
"UID:uid1",
|
||||||
|
"DTSTAMP:20990101T000000Z",
|
||||||
|
"DTSTART:20990101T130000Z",
|
||||||
|
"DTEND:20990101T140000Z",
|
||||||
|
"SUMMARY:Test Event",
|
||||||
|
"LOCATION:Office",
|
||||||
|
"URL:https://example.com",
|
||||||
|
"END:VEVENT",
|
||||||
|
"END:VCALENDAR",
|
||||||
|
"",
|
||||||
|
].join("\n"),
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEvents = vi.fn();
|
||||||
|
render(
|
||||||
|
<Integration
|
||||||
|
config={{ name: "Work", type: "ical", color: "blue", params: { showName: true } }}
|
||||||
|
params={{ start: "2099-01-01T00:00:00.000Z", end: "2099-01-02T00:00:00.000Z" }}
|
||||||
|
setEvents={setEvents}
|
||||||
|
hideErrors
|
||||||
|
timezone="utc"
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(setEvents).toHaveBeenCalled());
|
||||||
|
|
||||||
|
const updater = setEvents.mock.calls[0][0];
|
||||||
|
const next = updater({});
|
||||||
|
const entries = Object.values(next);
|
||||||
|
expect(entries).toHaveLength(1);
|
||||||
|
|
||||||
|
const [event] = entries;
|
||||||
|
expect(event.title).toBe("Work: Test Event");
|
||||||
|
expect(event.color).toBe("blue");
|
||||||
|
expect(event.type).toBe("ical");
|
||||||
|
expect(event.additional).toBe("Office");
|
||||||
|
expect(event.url).toBe("https://example.com");
|
||||||
|
expect(event.isCompleted).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
39
src/widgets/calendar/integrations/lidarr.test.jsx
Normal file
39
src/widgets/calendar/integrations/lidarr.test.jsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||||
|
useWidgetAPI: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
|
||||||
|
|
||||||
|
import Integration from "./lidarr";
|
||||||
|
|
||||||
|
describe("widgets/calendar/integrations/lidarr", () => {
|
||||||
|
it("adds release events", async () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: [
|
||||||
|
{ artist: { artistName: "Artist" }, title: "Album", releaseDate: "2099-01-01T00:00:00.000Z", grabbed: true },
|
||||||
|
],
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEvents = vi.fn();
|
||||||
|
render(
|
||||||
|
<Integration
|
||||||
|
config={{ type: "lidarr", color: "green" }}
|
||||||
|
params={{ start: "2099-01-01T00:00:00.000Z", end: "2099-01-02T00:00:00.000Z" }}
|
||||||
|
setEvents={setEvents}
|
||||||
|
hideErrors
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(setEvents).toHaveBeenCalled());
|
||||||
|
|
||||||
|
const next = setEvents.mock.calls[0][0]({});
|
||||||
|
expect(Object.keys(next)).toEqual(["Artist - Album"]);
|
||||||
|
expect(next["Artist - Album"].isCompleted).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
49
src/widgets/calendar/integrations/radarr.test.jsx
Normal file
49
src/widgets/calendar/integrations/radarr.test.jsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||||
|
useWidgetAPI: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
|
||||||
|
|
||||||
|
import Integration from "./radarr";
|
||||||
|
|
||||||
|
describe("widgets/calendar/integrations/radarr", () => {
|
||||||
|
it("adds cinema/physical/digital events", async () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: "Movie",
|
||||||
|
titleSlug: "movie",
|
||||||
|
hasFile: false,
|
||||||
|
inCinemas: "2099-01-01T00:00:00.000Z",
|
||||||
|
physicalRelease: "2099-01-02T00:00:00.000Z",
|
||||||
|
digitalRelease: "2099-01-03T00:00:00.000Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEvents = vi.fn();
|
||||||
|
render(
|
||||||
|
<Integration
|
||||||
|
config={{ type: "radarr", baseUrl: "https://radarr.example", color: "amber" }}
|
||||||
|
params={{ start: "2099-01-01T00:00:00.000Z", end: "2099-01-10T00:00:00.000Z" }}
|
||||||
|
setEvents={setEvents}
|
||||||
|
hideErrors
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(setEvents).toHaveBeenCalled());
|
||||||
|
|
||||||
|
const next = setEvents.mock.calls[0][0]({});
|
||||||
|
const keys = Object.keys(next);
|
||||||
|
expect(keys.some((k) => k.includes("calendar.inCinemas"))).toBe(true);
|
||||||
|
expect(keys.some((k) => k.includes("calendar.physicalRelease"))).toBe(true);
|
||||||
|
expect(keys.some((k) => k.includes("calendar.digitalRelease"))).toBe(true);
|
||||||
|
expect(Object.values(next)[0].url).toBe("https://radarr.example/movie/movie");
|
||||||
|
});
|
||||||
|
});
|
||||||
48
src/widgets/calendar/integrations/readarr.test.jsx
Normal file
48
src/widgets/calendar/integrations/readarr.test.jsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||||
|
useWidgetAPI: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
|
||||||
|
|
||||||
|
import Integration from "./readarr";
|
||||||
|
|
||||||
|
describe("widgets/calendar/integrations/readarr", () => {
|
||||||
|
it("adds release events with author name", async () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: "Book",
|
||||||
|
seriesTitle: "Series",
|
||||||
|
releaseDate: "2099-01-01T00:00:00.000Z",
|
||||||
|
grabbed: false,
|
||||||
|
author: { authorName: "Author" },
|
||||||
|
authorTitle: "Author Book",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEvents = vi.fn();
|
||||||
|
render(
|
||||||
|
<Integration
|
||||||
|
config={{ type: "readarr", color: "rose" }}
|
||||||
|
params={{ start: "2099-01-01T00:00:00.000Z", end: "2099-01-02T00:00:00.000Z" }}
|
||||||
|
setEvents={setEvents}
|
||||||
|
hideErrors
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(setEvents).toHaveBeenCalled());
|
||||||
|
|
||||||
|
const next = setEvents.mock.calls[0][0]({});
|
||||||
|
const [key] = Object.keys(next);
|
||||||
|
expect(key).toContain("Author");
|
||||||
|
expect(key).toContain("Book");
|
||||||
|
expect(key).toContain("(Series)");
|
||||||
|
});
|
||||||
|
});
|
||||||
48
src/widgets/calendar/integrations/sonarr.test.jsx
Normal file
48
src/widgets/calendar/integrations/sonarr.test.jsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { useWidgetAPI } = vi.hoisted(() => ({
|
||||||
|
useWidgetAPI: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/use-widget-api", () => ({ default: useWidgetAPI }));
|
||||||
|
|
||||||
|
import Integration from "./sonarr";
|
||||||
|
|
||||||
|
describe("widgets/calendar/integrations/sonarr", () => {
|
||||||
|
it("adds episode events", async () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
series: { title: "Show", titleSlug: "show" },
|
||||||
|
seasonNumber: 1,
|
||||||
|
episodeNumber: 2,
|
||||||
|
airDateUtc: "2099-01-01T00:00:00.000Z",
|
||||||
|
hasFile: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setEvents = vi.fn();
|
||||||
|
render(
|
||||||
|
<Integration
|
||||||
|
config={{ type: "sonarr", baseUrl: "https://sonarr.example", color: "teal" }}
|
||||||
|
params={{ start: "2099-01-01T00:00:00.000Z", end: "2099-01-02T00:00:00.000Z" }}
|
||||||
|
setEvents={setEvents}
|
||||||
|
hideErrors
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(setEvents).toHaveBeenCalled());
|
||||||
|
|
||||||
|
const next = setEvents.mock.calls[0][0]({});
|
||||||
|
const [entry] = Object.values(next);
|
||||||
|
expect(entry.title).toBe("Show");
|
||||||
|
expect(entry.additional).toBe("S1 E2");
|
||||||
|
expect(entry.url).toBe("https://sonarr.example/series/show");
|
||||||
|
expect(entry.isCompleted).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
71
src/widgets/calendar/monthly.test.jsx
Normal file
71
src/widgets/calendar/monthly.test.jsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { EventStub, compareDateTimezoneStub } = vi.hoisted(() => ({
|
||||||
|
EventStub: vi.fn(({ event }) => <div data-testid="event">{event.title}</div>),
|
||||||
|
compareDateTimezoneStub: vi.fn(
|
||||||
|
(date, event) => date.startOf("day").toISODate() === event.date.startOf("day").toISODate(),
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./event", () => ({
|
||||||
|
default: EventStub,
|
||||||
|
compareDateTimezone: compareDateTimezoneStub,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import Monthly from "./monthly";
|
||||||
|
|
||||||
|
describe("widgets/calendar/monthly", () => {
|
||||||
|
it("renders an empty placeholder when showDate is not set", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<Monthly
|
||||||
|
service={{ widget: {} }}
|
||||||
|
colorVariants={{}}
|
||||||
|
events={{}}
|
||||||
|
showDate={null}
|
||||||
|
setShowDate={() => {}}
|
||||||
|
currentDate={DateTime.now()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
expect(container.textContent).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates months and renders day events", () => {
|
||||||
|
const setShowDate = vi.fn();
|
||||||
|
const showDate = DateTime.local(2099, 2, 15).startOf("day");
|
||||||
|
const currentDate = DateTime.local(2099, 2, 4).startOf("day");
|
||||||
|
const service = { widget: { maxEvents: 10, showTime: false } };
|
||||||
|
|
||||||
|
const events = {
|
||||||
|
e1: { title: "Today Event", date: DateTime.local(2099, 2, 15, 10, 0), color: "zinc" },
|
||||||
|
e2: { title: "Other Event", date: DateTime.local(2099, 2, 16, 10, 0), color: "zinc" },
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Monthly
|
||||||
|
service={service}
|
||||||
|
colorVariants={{}}
|
||||||
|
events={events}
|
||||||
|
showDate={showDate}
|
||||||
|
setShowDate={setShowDate}
|
||||||
|
currentDate={currentDate}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("Today Event")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Other Event")).toBeNull();
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: ">" }));
|
||||||
|
expect(setShowDate).toHaveBeenCalled();
|
||||||
|
expect(setShowDate.mock.calls[0][0].toISODate()).toBe(showDate.plus({ months: 1 }).startOf("day").toISODate());
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "<" }));
|
||||||
|
expect(setShowDate.mock.calls[1][0].toISODate()).toBe(showDate.minus({ months: 1 }).startOf("day").toISODate());
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: showDate.toFormat("MMMM y") }));
|
||||||
|
expect(setShowDate.mock.calls[2][0].toISODate()).toBe(currentDate.startOf("day").toISODate());
|
||||||
|
});
|
||||||
|
});
|
||||||
39
src/widgets/jdownloader/tools.test.js
Normal file
39
src/widgets/jdownloader/tools.test.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import crypto from "crypto";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import { createEncryptionToken, decrypt, encrypt, sha256, uniqueRid, validateRid } from "./tools";
|
||||||
|
|
||||||
|
describe("widgets/jdownloader/tools", () => {
|
||||||
|
it("sha256 returns a 32-byte buffer", () => {
|
||||||
|
expect(sha256("hello")).toBeInstanceOf(Buffer);
|
||||||
|
expect(sha256("hello")).toHaveLength(32);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uniqueRid returns an integer", () => {
|
||||||
|
vi.spyOn(Math, "random").mockReturnValueOnce(0.123);
|
||||||
|
expect(uniqueRid()).toBeTypeOf("number");
|
||||||
|
expect(Number.isInteger(uniqueRid())).toBe(true);
|
||||||
|
Math.random.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validateRid throws when mismatched", () => {
|
||||||
|
expect(() => validateRid({ rid: 1 }, 2)).toThrow(/RequestID mismatch/i);
|
||||||
|
expect(validateRid({ rid: 5 }, 5)).toEqual({ rid: 5 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("encrypt/decrypt roundtrip with a 32-byte ivKey", () => {
|
||||||
|
const ivKey = crypto.randomBytes(32);
|
||||||
|
const plaintext = "secret";
|
||||||
|
const encrypted = encrypt(plaintext, ivKey);
|
||||||
|
const decrypted = decrypt(encrypted, ivKey);
|
||||||
|
expect(decrypted).toBe(plaintext);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("createEncryptionToken merges buffers and hashes", () => {
|
||||||
|
const oldToken = Buffer.from("aa", "hex");
|
||||||
|
const updateToken = "bb";
|
||||||
|
const token = createEncryptionToken(oldToken, updateToken);
|
||||||
|
expect(token).toBeInstanceOf(Buffer);
|
||||||
|
expect(token).toHaveLength(32);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { 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 "./downloader_get_downloadlist";
|
||||||
|
|
||||||
|
describe("widgets/openmediavault/methods/downloader_get_downloadlist", () => {
|
||||||
|
it("renders '-' values when data is missing", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openmediavault" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("openmediavault.downloading")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openmediavault.total")).toBeInTheDocument();
|
||||||
|
expect(screen.getAllByText("-").length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("counts downloading and total items", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: { response: { data: [{ downloading: true }, { downloading: false }, { downloading: true }] } },
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openmediavault" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("2")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("3")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { 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 "./services_get_status";
|
||||||
|
|
||||||
|
describe("widgets/openmediavault/methods/services_get_status", () => {
|
||||||
|
it("counts running/stopped/total services", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: { response: { data: [{ running: true }, { running: false }, { running: true }] } },
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openmediavault" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("openmediavault.running")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openmediavault.stopped")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openmediavault.total")).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByText("2")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("1")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("3")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
41
src/widgets/openmediavault/methods/smart_get_list.test.jsx
Normal file
41
src/widgets/openmediavault/methods/smart_get_list.test.jsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { 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 "./smart_get_list";
|
||||||
|
|
||||||
|
describe("widgets/openmediavault/methods/smart_get_list", () => {
|
||||||
|
it("counts passed/failed monitored disks", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({
|
||||||
|
data: {
|
||||||
|
response: {
|
||||||
|
output: JSON.stringify({
|
||||||
|
data: [
|
||||||
|
{ monitor: true, overallstatus: "GOOD" },
|
||||||
|
{ monitor: true, overallstatus: "BAD" },
|
||||||
|
{ monitor: false, overallstatus: "BAD" },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openmediavault" } }} />, {
|
||||||
|
settings: { hideErrors: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("openmediavault.passed")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openmediavault.failed")).toBeInTheDocument();
|
||||||
|
expect(screen.getAllByText("1")).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
37
src/widgets/openwrt/methods/interface.test.jsx
Normal file
37
src/widgets/openwrt/methods/interface.test.jsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { 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 "./interface";
|
||||||
|
|
||||||
|
describe("widgets/openwrt/methods/interface", () => {
|
||||||
|
it("returns null while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "openwrt" } }} />);
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders status and byte counters when loaded", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: { up: true, bytesTx: 100, bytesRx: 200 }, error: undefined });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openwrt" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getByText("widget.status")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openwrt.bytesTx")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openwrt.bytesRx")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// t("common.bytes") mock returns the numeric value as a string.
|
||||||
|
expect(screen.getByText("100")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("200")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openwrt.up")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
33
src/widgets/openwrt/methods/system.test.jsx
Normal file
33
src/widgets/openwrt/methods/system.test.jsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { 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 "./system";
|
||||||
|
|
||||||
|
describe("widgets/openwrt/methods/system", () => {
|
||||||
|
it("returns null while loading", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
const { container } = renderWithProviders(<Component service={{ widget: { type: "openwrt" } }} />);
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders uptime and cpu load when loaded", () => {
|
||||||
|
useWidgetAPI.mockReturnValue({ data: { uptime: 123, cpuLoad: "0.5" }, error: undefined });
|
||||||
|
|
||||||
|
renderWithProviders(<Component service={{ widget: { type: "openwrt" } }} />, { settings: { hideErrors: false } });
|
||||||
|
|
||||||
|
expect(screen.getByText("openwrt.uptime")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("openwrt.cpuLoad")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("123")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("0.5")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
19
src/widgets/truenas/pool.test.jsx
Normal file
19
src/widgets/truenas/pool.test.jsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import Pool from "./pool";
|
||||||
|
|
||||||
|
describe("widgets/truenas/pool", () => {
|
||||||
|
it("renders pool name, usage percent, and status color", () => {
|
||||||
|
const { container } = render(<Pool name="tank" free={50} allocated={50} healthy={false} />);
|
||||||
|
expect(screen.getByText("tank")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// 50 / 100 => 50%
|
||||||
|
expect(container.textContent).toContain("(50%)");
|
||||||
|
|
||||||
|
// status color reflects healthy=false
|
||||||
|
expect(container.querySelector(".bg-yellow-500")).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user