Add admin vision lab and LLM vision verification

这个提交包含在:
cryptocommuniums-afk
2026-03-15 00:41:09 +08:00
父节点 20e183d2da
当前提交 ad83ce9c68
修改 18 个文件,包含 915 行新增16 行删除

查看文件

@@ -816,3 +816,80 @@ describe("notification.markAllRead", () => {
await expect(caller.notification.markAllRead()).rejects.toThrow();
});
});
// ===== VISION LIBRARY TESTS =====
describe("vision.library", () => {
it("requires authentication", async () => {
const { ctx } = createMockContext(null);
const caller = appRouter.createCaller(ctx);
await expect(caller.vision.library()).rejects.toThrow();
});
it("returns seeded references for authenticated users", async () => {
const user = createTestUser();
const { ctx } = createMockContext(user);
const caller = appRouter.createCaller(ctx);
const seedSpy = vi.spyOn(db, "seedVisionReferenceImages").mockResolvedValueOnce();
const listSpy = vi.spyOn(db, "listVisionReferenceImages").mockResolvedValueOnce([
{
id: 1,
slug: "ref-1",
title: "标准图:正手挥拍",
exerciseType: "forehand",
imageUrl: "https://example.com/forehand.jpg",
sourcePageUrl: "https://example.com/source",
sourceLabel: "Example",
author: null,
license: null,
expectedFocus: ["肩髋转动"],
tags: ["forehand"],
notes: null,
sortOrder: 1,
isPublished: 1,
createdAt: new Date(),
updatedAt: new Date(),
},
] as any);
const result = await caller.vision.library();
expect(seedSpy).toHaveBeenCalledTimes(1);
expect(listSpy).toHaveBeenCalledTimes(1);
expect(result).toHaveLength(1);
});
});
describe("vision.runs", () => {
it("limits regular users to their own vision test runs", async () => {
const user = createTestUser({ id: 7, role: "user" });
const { ctx } = createMockContext(user);
const caller = appRouter.createCaller(ctx);
const listSpy = vi.spyOn(db, "listVisionTestRuns").mockResolvedValueOnce([]);
await caller.vision.runs({ limit: 20 });
expect(listSpy).toHaveBeenCalledWith(7, 20);
});
it("allows admin users to view all vision test runs", async () => {
const admin = createTestUser({ id: 9, role: "admin", name: "H1" });
const { ctx } = createMockContext(admin);
const caller = appRouter.createCaller(ctx);
const listSpy = vi.spyOn(db, "listVisionTestRuns").mockResolvedValueOnce([]);
await caller.vision.runs({ limit: 30 });
expect(listSpy).toHaveBeenCalledWith(undefined, 30);
});
});
describe("vision.seedLibrary", () => {
it("rejects non-admin users", async () => {
const user = createTestUser({ role: "user" });
const { ctx } = createMockContext(user);
const caller = appRouter.createCaller(ctx);
await expect(caller.vision.seedLibrary()).rejects.toThrow();
});
});