feat(*): 画布助手 - 新增 Live2D 配置导入与模型渲染支持
This commit is contained in:
47
web/test/live2d-loader.test.ts
Normal file
47
web/test/live2d-loader.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { afterEach, expect, test } from "bun:test";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { installLive2DLoader } from "../src/services/live2d-loader";
|
||||
import type { Live2DLoader, Live2DLoaderContext } from "pixi-live2d-display/cubism4";
|
||||
|
||||
const originalFetch = globalThis.fetch;
|
||||
const originalWindow = Object.getOwnPropertyDescriptor(globalThis, "window");
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch;
|
||||
if (originalWindow) Object.defineProperty(globalThis, "window", originalWindow);
|
||||
else Reflect.deleteProperty(globalThis, "window");
|
||||
});
|
||||
|
||||
test("Live2D loader restricts credentialed URLs, propagates failures and aborts on destroy", async () => {
|
||||
Object.defineProperty(globalThis, "window", { configurable: true, value: { location: { href: "https://canvas.example/admin" } } });
|
||||
const loader = { middlewares: [] } as unknown as typeof Live2DLoader;
|
||||
installLive2DLoader(loader);
|
||||
installLive2DLoader(loader);
|
||||
expect(loader.middlewares).toHaveLength(1);
|
||||
const run = (context: Live2DLoaderContext) => loader.middlewares[0](context, async () => {});
|
||||
const url = "/api/admin/settings/appearance/live2d/id/model.model3.json";
|
||||
let requests = 0;
|
||||
globalThis.fetch = (async (_url: unknown, options: RequestInit) => {
|
||||
requests++;
|
||||
expect(options.credentials).toBe("include");
|
||||
return new Response('{"Version":3}', { status: 200 });
|
||||
}) as typeof fetch;
|
||||
const context = { url, type: "json" } as Live2DLoaderContext;
|
||||
await run(context);
|
||||
expect(context.result).toEqual({ Version: 3 });
|
||||
for (const unsafe of ["https://evil.example" + url, "/api/admin/users", "//evil.example/model.json"]) {
|
||||
await expect(run({ url: unsafe, type: "json" })).rejects.toThrow("本站模型接口");
|
||||
}
|
||||
expect(requests).toBe(1);
|
||||
globalThis.fetch = (async () => new Response("denied", { status: 403 })) as typeof fetch;
|
||||
await expect(run({ url, type: "json" })).rejects.toThrow("403");
|
||||
|
||||
const target = new EventEmitter();
|
||||
globalThis.fetch = ((_url: unknown, options: RequestInit) =>
|
||||
new Promise((_resolve, reject) => {
|
||||
options.signal?.addEventListener("abort", () => reject(new Error("aborted")));
|
||||
})) as typeof fetch;
|
||||
const pending = run({ url, type: "json", target: target as unknown as Live2DLoaderContext["target"] });
|
||||
target.emit("destroy");
|
||||
await expect(pending).rejects.toThrow("aborted");
|
||||
expect(target.listenerCount("destroy")).toBe(0);
|
||||
});
|
||||
Reference in New Issue
Block a user