mirror of
https://github.com/gethomepage/homepage.git
synced 2026-02-08 00:40:52 +08:00
test: add widget proxy tests (batch 4)
This commit is contained in:
92
src/widgets/crowdsec/proxy.test.js
Normal file
92
src/widgets/crowdsec/proxy.test.js
Normal file
@@ -0,0 +1,92 @@
|
||||
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("memory-cache", () => ({
|
||||
default: cache,
|
||||
...cache,
|
||||
}));
|
||||
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: {
|
||||
crowdsec: {
|
||||
api: "{url}/{endpoint}",
|
||||
loginURL: "{url}/login",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import crowdsecProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/crowdsec/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cache._reset();
|
||||
});
|
||||
|
||||
it("logs in, caches a token, and uses it for requests", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "crowdsec",
|
||||
url: "http://cs",
|
||||
username: "machine",
|
||||
password: "pw",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
JSON.stringify({ token: "tok", expire: new Date(Date.now() + 60_000).toISOString() }),
|
||||
])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("data")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "alerts", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await crowdsecProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(2);
|
||||
expect(httpProxy.mock.calls[1][1].headers.Authorization).toBe("Bearer tok");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from("data"));
|
||||
});
|
||||
|
||||
it("returns 500 if token cannot be obtained", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "crowdsec", url: "http://cs", username: "machine", password: "pw" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", JSON.stringify({ expire: "2099-01-01T00:00:00Z" })]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "alerts", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await crowdsecProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body).toEqual({ error: "Failed to authenticate with Crowdsec" });
|
||||
});
|
||||
});
|
||||
@@ -69,7 +69,7 @@ export default async function frigateProxyHandler(req, res, map) {
|
||||
data = asJson(data);
|
||||
|
||||
if (endpoint == "stats") {
|
||||
res.status(status).send({
|
||||
return res.status(status).send({
|
||||
num_cameras: data?.cameras !== undefined ? Object.keys(data?.cameras).length : 0,
|
||||
uptime: data?.service?.uptime,
|
||||
version: data?.service.version,
|
||||
|
||||
71
src/widgets/frigate/proxy.test.js
Normal file
71
src/widgets/frigate/proxy.test.js
Normal file
@@ -0,0 +1,71 @@
|
||||
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(),
|
||||
},
|
||||
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: {
|
||||
frigate: {
|
||||
api: "{url}/api/{endpoint}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import frigateProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/frigate/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("logs in after a 401 and returns derived stats", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
type: "frigate",
|
||||
url: "http://frigate",
|
||||
username: "u",
|
||||
password: "p",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
// initial request
|
||||
.mockResolvedValueOnce([401, "application/json", Buffer.from("nope")])
|
||||
// login
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("{}"), { "set-cookie": ["sid=1"] }])
|
||||
// retry stats
|
||||
.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ cameras: { a: {}, b: {} }, service: { uptime: 123, version: "1.0" } })),
|
||||
]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "stats", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await frigateProxyHandler(req, res);
|
||||
|
||||
expect(cookieJar.addCookieToJar).toHaveBeenCalled();
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual({ num_cameras: 2, uptime: 123, version: "1.0" });
|
||||
});
|
||||
});
|
||||
76
src/widgets/fritzbox/proxy.test.js
Normal file
76
src/widgets/fritzbox/proxy.test.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, xml2json, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
xml2json: vi.fn((xml) => {
|
||||
const xmlString = Buffer.isBuffer(xml) ? xml.toString() : xml;
|
||||
if (xmlString === "GetStatusInfo") {
|
||||
return JSON.stringify({
|
||||
elements: [
|
||||
{
|
||||
elements: [
|
||||
{
|
||||
elements: [
|
||||
{
|
||||
elements: [
|
||||
{ name: "NewConnectionStatus", elements: [{ text: "Connected" }] },
|
||||
{ name: "NewUptime", elements: [{ text: "42" }] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
return JSON.stringify({ elements: [] });
|
||||
}),
|
||||
logger: { debug: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("xml-js", () => ({
|
||||
xml2json,
|
||||
}));
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import fritzboxProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/fritzbox/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("queries the configured fields and returns derived data", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
url: "http://fritz.box",
|
||||
fields: ["connectionStatus", "uptime"],
|
||||
});
|
||||
|
||||
httpProxy.mockResolvedValueOnce([200, "text/xml", Buffer.from("GetStatusInfo")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await fritzboxProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(
|
||||
expect.objectContaining({
|
||||
connectionStatus: "Connected",
|
||||
uptime: "42",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
67
src/widgets/gamedig/proxy.test.js
Normal file
67
src/widgets/gamedig/proxy.test.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { GameDig, getServiceWidget, logger } = vi.hoisted(() => ({
|
||||
GameDig: { query: vi.fn() },
|
||||
getServiceWidget: vi.fn(),
|
||||
logger: { error: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("gamedig", () => ({
|
||||
GameDig,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
|
||||
import gamedigProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/gamedig/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns online=true with server details when query succeeds", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://example.com:1234", serverType: "csgo" });
|
||||
GameDig.query.mockResolvedValue({
|
||||
name: "Server",
|
||||
map: "de_dust2",
|
||||
numplayers: 3,
|
||||
maxplayers: 10,
|
||||
bots: [],
|
||||
ping: 42,
|
||||
});
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await gamedigProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(
|
||||
expect.objectContaining({
|
||||
online: true,
|
||||
name: "Server",
|
||||
players: 3,
|
||||
maxplayers: 10,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("returns online=false when query fails", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://example.com:1234", serverType: "csgo" });
|
||||
GameDig.query.mockRejectedValue(new Error("nope"));
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await gamedigProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual({ online: false });
|
||||
});
|
||||
});
|
||||
60
src/widgets/homeassistant/proxy.test.js
Normal file
60
src/widgets/homeassistant/proxy.test.js
Normal file
@@ -0,0 +1,60 @@
|
||||
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() },
|
||||
}));
|
||||
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import homeassistantProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/homeassistant/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns 400 when custom JSON cannot be parsed", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://hass", key: "k", custom: "{not-json" });
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await homeassistantProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toEqual({ error: "Error parsing widget custom label" });
|
||||
});
|
||||
|
||||
it("runs default template queries and returns label/value pairs", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://hass", key: "k" });
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([200, "text/plain", Buffer.from("1 / 2")])
|
||||
.mockResolvedValueOnce([200, "text/plain", Buffer.from("3 / 4")])
|
||||
.mockResolvedValueOnce([200, "text/plain", Buffer.from("5 / 6")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await homeassistantProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(3);
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual([
|
||||
{ label: "homeassistant.people_home", value: "1 / 2" },
|
||||
{ label: "homeassistant.lights_on", value: "3 / 4" },
|
||||
{ label: "homeassistant.switches_on", value: "5 / 6" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
79
src/widgets/jdownloader/proxy.test.js
Normal file
79
src/widgets/jdownloader/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, tools, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
tools: {
|
||||
uniqueRid: vi.fn(() => 123),
|
||||
sha256: vi.fn(() => "secret"),
|
||||
validateRid: vi.fn(() => true),
|
||||
createEncryptionToken: vi.fn(() => "enc-token"),
|
||||
decrypt: vi.fn((cipherText) => {
|
||||
if (cipherText === "connect") {
|
||||
return JSON.stringify({ rid: 123, sessiontoken: "sess" });
|
||||
}
|
||||
if (cipherText === "devices") {
|
||||
return JSON.stringify({ list: [{ name: "myclient", id: "dev1" }] });
|
||||
}
|
||||
if (cipherText === "packages") {
|
||||
return JSON.stringify({
|
||||
data: [
|
||||
{ bytesLoaded: 40, bytesTotal: 100, finished: false, speed: 10 },
|
||||
{ bytesLoaded: 100, bytesTotal: 100, finished: true, speed: 0 },
|
||||
],
|
||||
});
|
||||
}
|
||||
return JSON.stringify({});
|
||||
}),
|
||||
encrypt: vi.fn(() => "encrypted-body"),
|
||||
},
|
||||
logger: { debug: vi.fn(), error: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("./tools", () => tools);
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import jdownloaderProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/jdownloader/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("aggregates package stats from the JDownloader API", async () => {
|
||||
getServiceWidget.mockResolvedValue({
|
||||
url: "http://ignored",
|
||||
username: "user@example.com",
|
||||
password: "pw",
|
||||
client: "myclient",
|
||||
});
|
||||
|
||||
httpProxy
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("connect")])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("devices")])
|
||||
.mockResolvedValueOnce([200, "application/json", Buffer.from("packages")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await jdownloaderProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(3);
|
||||
expect(res.body).toEqual({
|
||||
downloadCount: 2,
|
||||
bytesRemaining: 60,
|
||||
totalBytes: 200,
|
||||
totalSpeed: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
72
src/widgets/komodo/proxy.test.js
Normal file
72
src/widgets/komodo/proxy.test.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import createMockRes from "test-utils/create-mock-res";
|
||||
|
||||
const { httpProxy, getServiceWidget, validateWidgetData, logger } = vi.hoisted(() => ({
|
||||
httpProxy: vi.fn(),
|
||||
getServiceWidget: vi.fn(),
|
||||
validateWidgetData: vi.fn(() => true),
|
||||
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/validate-widget-data", () => ({
|
||||
default: validateWidgetData,
|
||||
}));
|
||||
vi.mock("widgets/widgets", () => ({
|
||||
default: {
|
||||
komodo: {
|
||||
api: "{url}/{endpoint}",
|
||||
mappings: {
|
||||
stats: { body: { hello: "world" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import komodoProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/komodo/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
validateWidgetData.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("POSTs to the unified read endpoint with API key/secret", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "komodo", url: "http://komodo", key: "k", secret: "s" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from("ok")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "stats", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await komodoProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy.mock.calls[0][0]).toBe("http://komodo/read");
|
||||
expect(httpProxy.mock.calls[0][1].headers["X-API-Key"]).toBe("k");
|
||||
expect(httpProxy.mock.calls[0][1].headers["X-API-Secret"]).toBe("s");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from("ok"));
|
||||
});
|
||||
|
||||
it("returns 500 when data validation fails", async () => {
|
||||
validateWidgetData.mockReturnValue(false);
|
||||
getServiceWidget.mockResolvedValue({ type: "komodo", url: "http://komodo", key: "k", secret: "s" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from("bad")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "stats", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await komodoProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.message).toBe("Invalid data");
|
||||
});
|
||||
});
|
||||
82
src/widgets/qnap/proxy.test.js
Normal file
82
src/widgets/qnap/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, cache, xml2json, 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(),
|
||||
},
|
||||
xml2json: vi.fn((xml) => {
|
||||
if (xml === "login") {
|
||||
return JSON.stringify({ QDocRoot: { authSid: { _cdata: "sid1" } } });
|
||||
}
|
||||
if (xml === "system") {
|
||||
return JSON.stringify({
|
||||
QDocRoot: {
|
||||
authPassed: { _cdata: "1" },
|
||||
func: { ownContent: { root: { cpu: 1 } } },
|
||||
},
|
||||
});
|
||||
}
|
||||
if (xml === "volume") {
|
||||
return JSON.stringify({ QDocRoot: { authPassed: { _cdata: "1" }, volume: { ok: true } } });
|
||||
}
|
||||
return JSON.stringify({ QDocRoot: { authPassed: { _cdata: "1" } } });
|
||||
}),
|
||||
logger: { debug: vi.fn(), error: vi.fn() },
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("memory-cache", () => ({
|
||||
default: cache,
|
||||
...cache,
|
||||
}));
|
||||
vi.mock("xml-js", () => ({
|
||||
xml2json,
|
||||
}));
|
||||
vi.mock("utils/logger", () => ({
|
||||
default: () => logger,
|
||||
}));
|
||||
vi.mock("utils/config/service-helpers", () => ({
|
||||
default: getServiceWidget,
|
||||
}));
|
||||
vi.mock("utils/proxy/http", () => ({
|
||||
httpProxy,
|
||||
}));
|
||||
|
||||
import qnapProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/qnap/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cache._reset();
|
||||
});
|
||||
|
||||
it("logs in and returns system + volume data", async () => {
|
||||
getServiceWidget.mockResolvedValue({ url: "http://qnap", username: "u", password: "p" });
|
||||
|
||||
httpProxy
|
||||
// login
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("login")])
|
||||
// system
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("system")])
|
||||
// volume
|
||||
.mockResolvedValueOnce([200, "application/xml", Buffer.from("volume")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await qnapProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body.system).toEqual({ cpu: 1 });
|
||||
expect(res.body.volume).toEqual(expect.objectContaining({ authPassed: { _cdata: "1" } }));
|
||||
});
|
||||
});
|
||||
68
src/widgets/suwayomi/proxy.test.js
Normal file
68
src/widgets/suwayomi/proxy.test.js
Normal file
@@ -0,0 +1,68 @@
|
||||
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: {
|
||||
suwayomi: {
|
||||
api: "{url}/graphql",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import suwayomiProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/suwayomi/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns extracted counts from GraphQL response (no category)", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "suwayomi", url: "http://su", fields: ["download", "unread"] });
|
||||
|
||||
httpProxy.mockResolvedValueOnce([
|
||||
200,
|
||||
"application/json",
|
||||
Buffer.from(JSON.stringify({ data: { download: { totalCount: 2 }, unread: { totalCount: 5 } } })),
|
||||
]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "graphql", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await suwayomiProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual([
|
||||
{ count: 2, label: "suwayomi.download" },
|
||||
{ count: 5, label: "suwayomi.unread" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns 401 when credentials are invalid", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "suwayomi", url: "http://su", username: "u", password: "p" });
|
||||
httpProxy.mockResolvedValueOnce([401, "application/json", Buffer.from("{}")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", endpoint: "graphql", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await suwayomiProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(401);
|
||||
expect(res.body.error.message).toContain("unauthorized");
|
||||
});
|
||||
});
|
||||
50
src/widgets/tdarr/proxy.test.js
Normal file
50
src/widgets/tdarr/proxy.test.js
Normal file
@@ -0,0 +1,50 @@
|
||||
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: {
|
||||
tdarr: {
|
||||
api: "{url}/api",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import tdarrProxyHandler from "./proxy";
|
||||
|
||||
describe("widgets/tdarr/proxy", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("POSTs the stats request and includes the API key header", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "tdarr", url: "http://td", key: "k" });
|
||||
httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from("ok")]);
|
||||
|
||||
const req = { query: { group: "g", service: "svc", index: "0" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await tdarrProxyHandler(req, res);
|
||||
|
||||
expect(httpProxy).toHaveBeenCalledTimes(1);
|
||||
expect(httpProxy.mock.calls[0][0].toString()).toBe("http://td/api");
|
||||
expect(httpProxy.mock.calls[0][1].headers["x-api-key"]).toBe("k");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toEqual(Buffer.from("ok"));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user