85 lines
2.3 KiB
TypeScript
85 lines
2.3 KiB
TypeScript
import { NextRequest } from "next/server";
|
|
import { beforeEach, expect, it, vi } from "vitest";
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
guard: vi.fn(),
|
|
source: vi.fn(),
|
|
official: vi.fn(),
|
|
inspect: vi.fn(),
|
|
}));
|
|
vi.mock("@/lib/api-handler", () => ({
|
|
withAdmin: (options: unknown, handler: unknown) => {
|
|
mocks.guard(options);
|
|
return handler;
|
|
},
|
|
}));
|
|
vi.mock("@/lib/services/clone-sources", () => ({ getSource: mocks.source }));
|
|
vi.mock("@/lib/services/habbo-furnidata-cache", () => ({
|
|
getOfficialHabboFurnidata: mocks.official,
|
|
}));
|
|
vi.mock("@/lib/services/furniture-source-assets", () => ({
|
|
inspectSourceAssets: mocks.inspect,
|
|
}));
|
|
|
|
import { POST } from "./route";
|
|
|
|
const item = {
|
|
id: 1,
|
|
classname: "chair",
|
|
name: "Chair",
|
|
description: "",
|
|
revision: 1,
|
|
type: "flooritem",
|
|
category: "other",
|
|
};
|
|
const request = (body: unknown) =>
|
|
new NextRequest("http://localhost/api/admin/studio/source-assets", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
});
|
|
beforeEach(() => {
|
|
mocks.source.mockReset().mockResolvedValue(null);
|
|
mocks.official.mockReset().mockResolvedValue(new Map());
|
|
mocks.inspect.mockReset().mockResolvedValue({
|
|
classname: "chair",
|
|
state: "missing",
|
|
revision: 1,
|
|
alternatives: [],
|
|
});
|
|
});
|
|
it("requires import permission", () =>
|
|
expect(mocks.guard).toHaveBeenCalledWith({
|
|
permission: PERMS.ASSETS_IMPORT,
|
|
}));
|
|
it.each([
|
|
[],
|
|
Array(21).fill(item),
|
|
[{ ...item, classname: "../secret" }],
|
|
[{ ...item, revision: -1 }],
|
|
[null],
|
|
])("rejects invalid items before network checks: %j", async (items) => {
|
|
expect((await POST(request({ items }))).status).toBe(400);
|
|
expect(mocks.inspect).not.toHaveBeenCalled();
|
|
});
|
|
it("rejects unknown configured sources", async () => {
|
|
expect(
|
|
(await POST(request({ items: [item], sourceId: "missing" }))).status,
|
|
).toBe(404);
|
|
expect(mocks.inspect).not.toHaveBeenCalled();
|
|
});
|
|
it("uses server source configuration instead of client URLs", async () => {
|
|
const source = { id: "custom", nitroBaseUrl: "https://configured.example" };
|
|
mocks.source.mockResolvedValue(source);
|
|
const response = await POST(
|
|
request({
|
|
items: [item],
|
|
sourceId: "custom",
|
|
nitroBaseUrl: "https://untrusted.example",
|
|
}),
|
|
);
|
|
expect(response.status).toBe(200);
|
|
expect(mocks.inspect).toHaveBeenCalledWith(item, [], source);
|
|
expect((await response.json()).items[0].state).toBe("missing");
|
|
});
|