mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-08 00:40:52 +08:00
test: add widget proxy tests (batch 3)
This commit is contained in:
82
src/widgets/dockhand/proxy.test.js
Normal file
82
src/widgets/dockhand/proxy.test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: {
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
dockhand: {
|
||||
api: "{url}/{endpoint}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import dockhandProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/dockhand/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("retries after a 401 by logging in once", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "dockhand",
|
||||
url: "http://dockhand/",
|
||||
username: "u",
|
||||
password: "p",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([401, "application/json", Buffer.from("nope")])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("ok")]) // login
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("data")]); // retry
|
||||
|
||||
const req = { method: "GET", query: { group: "g", service: "svc", endpoint: "api/v1/status", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await dockhandProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(3);
|
||||
expect(httpProxy.mock.calls[1][0]).toBe("http://dockhand/api/auth/login");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from("data"));
|
||||
});
|
||||
|
||||
it("returns a sanitized error response for HTTP errors", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "dockhand",
|
||||
url: "http://dockhand",
|
||||
});
|
||||
|
||||
httpProxy.mockResolvedValueOnce([500, "application/json", Buffer.from("boom")]);
|
||||
|
||||
const req = {
|
||||
method: "GET",
|
||||
query: { group: "g", service: "svc", endpoint: "api/v1/status?token=abc", index: "0" },
|
||||
};
|
||||
const res = createMockRes();
|
||||
|
||||
await dockhandProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.message).toBe("HTTP Error");
|
||||
expect(res.body.error.url).toContain("token=***");
|
||||
});
|
||||
});
|
||||
73
src/widgets/homebox/proxy.test.js
Normal file
73
src/widgets/homebox/proxy.test.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, cache, logger } = vi.hoisted(() => {
|
||||
const store = new Map();
|
||||
|
||||
return {
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
cache: {
|
||||
get: vi.fn((k) => store.get(k)),
|
||||
put: vi.fn((k, v) => store.set(k, v)),
|
||||
del: vi.fn((k) => store.delete(k)),
|
||||
_reset: () => store.clear(),
|
||||
},
|
||||
logger: {
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("memory-cache", () => ({
|
||||
default: cache,
|
||||
...cache,
|
||||
}));
|
||||
|
||||
import homeboxProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/homebox/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cache._reset();
|
||||
});
|
||||
|
||||
it("logs in and returns group statistics + currency", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
url: "http://homebox",
|
||||
username: "u",
|
||||
password: "p",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ token: "tok", expiresAt: new Date(Date.now() + 60_000).toISOString() })),
|
||||
])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ totalItems: 1, totalUsers: 2 }))])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ currency: "USD" }))]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await homeboxProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(3);
|
||||
expect(httpProxy.mock.calls[0][0]).toBe("http://homebox/api/v1/users/login");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body.currencyCode).toBe("USD");
|
||||
expect(res.body.users).toBe(2);
|
||||
});
|
||||
});
|
||||
96
src/widgets/homebridge/proxy.test.js
Normal file
96
src/widgets/homebridge/proxy.test.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, cache, logger } = vi.hoisted(() => {
|
||||
const store = new Map();
|
||||
|
||||
return {
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
cache: {
|
||||
get: vi.fn((k) => store.get(k)),
|
||||
put: vi.fn((k, v) => store.set(k, v)),
|
||||
del: vi.fn((k) => store.delete(k)),
|
||||
_reset: () => store.clear(),
|
||||
},
|
||||
logger: {
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("memory-cache", () => ({
|
||||
default: cache,
|
||||
...cache,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
homebridge: {
|
||||
api: "{url}/{endpoint}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import homebridgeProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/homebridge/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cache._reset();
|
||||
});
|
||||
|
||||
it("logs in and aggregates status, versions, plugin updates, and child bridge counts", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "homebridge", url: "http://hb", username: "u", password: "p" });
|
||||
|
||||
httpProxy
|
||||
// login
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ access_token: "tok", expires_in: 3600 })),
|
||||
{},
|
||||
])
|
||||
// status
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ status: "ok" })), {}])
|
||||
// version
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ updateAvailable: true })), {}])
|
||||
// child bridges
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify([{ status: "ok" }, { status: "down" }])),
|
||||
{},
|
||||
])
|
||||
// plugins
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify([{ updateAvailable: true }, { updateAvailable: false }])),
|
||||
{},
|
||||
]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await homebridgeProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual({
|
||||
status: "ok",
|
||||
updateAvailable: true,
|
||||
plugins: { updatesAvailable: 1 },
|
||||
childBridges: { running: 1, total: 2 },
|
||||
});
|
||||
});
|
||||
});
|
||||
79
src/widgets/jackett/proxy.test.js
Normal file
79
src/widgets/jackett/proxy.test.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: {
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
jackett: {
|
||||
api: "{url}/{endpoint}",
|
||||
loginURL: "{url}/UI/Dashboard",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import jackettProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/jackett/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("fetches an auth cookie when password is set and passes it on requests", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "jackett",
|
||||
url: "http://jackett",
|
||||
password: "pw",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
// login cookie fetch
|
||||
.mockResolvedValueOnce([200, "text/plain", null, null, { headers: { Cookie: "c=1" } }])
|
||||
// api call
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("ok")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "api/v2.0/indexers/all/results", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await jackettProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(2);
|
||||
expect(httpProxy.mock.calls[1][1].headers.Cookie).toBe("c=1");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from("ok"));
|
||||
});
|
||||
|
||||
it("returns 500 when cookie authentication fails", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "jackett",
|
||||
url: "http://jackett",
|
||||
password: "pw",
|
||||
});
|
||||
|
||||
httpProxy.mockResolvedValueOnce([200, "text/plain", null, null, { headers: {} }]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "api", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await jackettProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body).toEqual({ error: "Failed to authenticate with Jackett" });
|
||||
});
|
||||
});
|
||||
121
src/widgets/omada/proxy.test.js
Normal file
121
src/widgets/omada/proxy.test.js
Normal file
@@ -0,0 +1,121 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: {
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import omadaProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/omada/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("fetches controller info, logs in, selects site, and returns overview stats (v4)", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
url: "http://omada",
|
||||
username: "u",
|
||||
password: "p",
|
||||
site: "Default",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
// controller info
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }),
|
||||
])
|
||||
// login
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||
])
|
||||
// sites list
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }),
|
||||
])
|
||||
// overview diagram
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({
|
||||
errorCode: 0,
|
||||
result: {
|
||||
totalClientNum: 10,
|
||||
connectedApNum: 2,
|
||||
connectedGatewayNum: 1,
|
||||
connectedSwitchNum: 3,
|
||||
},
|
||||
}),
|
||||
])
|
||||
// alert count
|
||||
.mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 4 } })]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await omadaProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(5);
|
||||
expect(res.statusCode).toBe(null); // uses res.send directly without setting status
|
||||
expect(res.body).toBe(
|
||||
JSON.stringify({
|
||||
connectedAp: 2,
|
||||
activeUser: 10,
|
||||
alerts: 4,
|
||||
connectedGateways: 1,
|
||||
connectedSwitches: 3,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("returns an error when the site is not found", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://omada", username: "u", password: "p", site: "Missing" });
|
||||
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({ result: { omadacId: "cid", controllerVer: "4.5.6" } }),
|
||||
])
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t" } })),
|
||||
])
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", key: "sitekey" }] } }),
|
||||
]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await omadaProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body.error.message).toContain("Site Missing is not found");
|
||||
});
|
||||
});
|
||||
74
src/widgets/openmediavault/proxy.test.js
Normal file
74
src/widgets/openmediavault/proxy.test.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, cookieJar, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
cookieJar: {
|
||||
addCookieToJar: vi.fn(),
|
||||
setCookieHeader: vi.fn(),
|
||||
},
|
||||
logger: {
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("utils/proxy/cookie-jar", () => cookieJar);
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
openmediavault: {
|
||||
api: "{url}/rpc.php",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import openmediavaultProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/openmediavault/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("logs in after a 401 and retries the RPC call", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "openmediavault",
|
||||
url: "http://omv",
|
||||
username: "u",
|
||||
password: "p",
|
||||
method: "foo.bar",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
// initial rpc unauthorized
|
||||
.mockResolvedValueOnce([401, "application/json", Buffer.from(JSON.stringify({ response: {} })), {}])
|
||||
// login rpc
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ response: { authenticated: true } })),
|
||||
{ "set-cookie": ["sid=1"] },
|
||||
])
|
||||
// retry rpc
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ response: { ok: true } })), {}]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await openmediavaultProxyHandler(req, res);
|
||||
|
||||
expect(cookieJar.addCookieToJar).toHaveBeenCalled();
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from(JSON.stringify({ response: { ok: true } })));
|
||||
});
|
||||
});
|
||||
59
src/widgets/openwrt/proxy.test.js
Normal file
59
src/widgets/openwrt/proxy.test.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { sendJsonRpcRequest, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
sendJsonRpcRequest: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: { debug: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/handlers/jsonrpc", () => ({
|
||||
sendJsonRpcRequest,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
openwrt: {
|
||||
api: "{url}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import openwrtProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/openwrt/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("logs in and retries after an unauthorized response", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "openwrt", url: "http://openwrt", username: "u", password: "p" });
|
||||
|
||||
sendJsonRpcRequest
|
||||
// initial call -> unauthorized
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ error: { code: -32002 } }))])
|
||||
// login -> sets ubus token
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify([0, { ubus_rpc_session: "sess" }]))])
|
||||
// retry system info -> ok
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify([0, { uptime: 1, load: [0, 131072, 0] }])),
|
||||
]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await openwrtProxyHandler(req, res);
|
||||
|
||||
expect(sendJsonRpcRequest).toHaveBeenCalledTimes(3);
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(JSON.parse(res.body).cpuLoad).toBe("2.00");
|
||||
});
|
||||
});
|
||||
41
src/widgets/photoprism/proxy.test.js
Normal file
41
src/widgets/photoprism/proxy.test.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: { debug: vi.fn(), error: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import photoprismProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/photoprism/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("supports bearer-token auth and returns config count", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://pp", key: "k" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ config: { count: 123 } }))]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await photoprismProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy.mock.calls[0][1].headers.Authorization).toBe("Bearer k");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toBe(123);
|
||||
});
|
||||
});
|
||||
93
src/widgets/plex/proxy.test.js
Normal file
93
src/widgets/plex/proxy.test.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, cache, xml2json, logger } = vi.hoisted(() => {
|
||||
const store = new Map();
|
||||
return {
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
cache: {
|
||||
get: vi.fn((k) => (store.has(k) ? store.get(k) : null)),
|
||||
put: vi.fn((k, v) => store.set(k, v)),
|
||||
del: vi.fn((k) => store.delete(k)),
|
||||
_reset: () => store.clear(),
|
||||
},
|
||||
xml2json: vi.fn((xml) => {
|
||||
if (xml === "sessions") return JSON.stringify({ MediaContainer: { _attributes: { size: "2" } } });
|
||||
if (xml === "libraries")
|
||||
return JSON.stringify({
|
||||
MediaContainer: {
|
||||
Directory: [
|
||||
{ _attributes: { type: "movie", key: "1" } },
|
||||
{ _attributes: { type: "show", key: "2" } },
|
||||
{ _attributes: { type: "artist", key: "3" } },
|
||||
],
|
||||
},
|
||||
});
|
||||
if (xml === "movies") return JSON.stringify({ MediaContainer: { _attributes: { size: "10" } } });
|
||||
if (xml === "tv") return JSON.stringify({ MediaContainer: { _attributes: { totalSize: "20" } } });
|
||||
if (xml === "albums") return JSON.stringify({ MediaContainer: { _attributes: { size: "30" } } });
|
||||
return JSON.stringify({ MediaContainer: { _attributes: { size: "0" } } });
|
||||
}),
|
||||
logger: { debug: vi.fn(), error: vi.fn() },
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("memory-cache", () => ({
|
||||
default: cache,
|
||||
...cache,
|
||||
}));
|
||||
vi.mock("xml-js", () => ({
|
||||
xml2json,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
plex: {
|
||||
api: "{url}{endpoint}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import plexProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/plex/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cache._reset();
|
||||
});
|
||||
|
||||
it("fetches sessions and library counts, caching intermediate results", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "plex", url: "http://plex" });
|
||||
|
||||
httpProxy
|
||||
// sessions
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("sessions")])
|
||||
// libraries
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("libraries")])
|
||||
// movies
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("movies")])
|
||||
// tv
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("tv")])
|
||||
// albums
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("albums")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await plexProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual({ streams: "2", albums: 30, movies: 10, tv: 20 });
|
||||
expect(cache.put).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
48
src/widgets/rutorrent/proxy.test.js
Normal file
48
src/widgets/rutorrent/proxy.test.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: { error: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
rutorrent: {
|
||||
api: "{url}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import rutorrentProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/rutorrent/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("parses torrent list data into an array", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "rutorrent", url: "http://ru", username: "u", password: "p" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", JSON.stringify({ t: { hash1: Array(34).fill(0) } })]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await rutorrentProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(Array.isArray(res.body)).toBe(true);
|
||||
expect(res.body[0]["d.get_name"]).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user