import { describe, expect, it } from "vitest"; import type { AiCitation, ElderAiAnalysisOutput, ElderAiFinding, ElderAiRecommendation, KnowledgeEntryInput } from "@/modules/ai/types"; import { parseDataScopes, validateElderAiAnalysisOutput, validateKnowledgeEntryInput, } from "@/modules/ai/types"; const validKnowledgeInput: KnowledgeEntryInput = { scope: "organization", organizationId: "org-1", title: "Fall prevention guidance", category: "Safety", tags: "fall,night", body: "Residents with night wandering need bed exit checks and clear walkways.", status: "enabled", }; const validFinding: ElderAiFinding = { category: "fall-risk", severity: "warning", evidence: "Night wandering and prior fall history are present.", citationIds: ["resident-1"], }; const validRecommendation: ElderAiRecommendation = { title: "Increase night checks", priority: "high", rationale: "Additional observation reduces missed night wandering events.", suggestedNextStep: "Add a night-shift round note for the next care review.", citationIds: ["resident-1"], }; const validCitation: AiCitation = { id: "resident-1", sourceType: "resident_context", sourceId: "elder-1", title: "Resident profile", excerpt: "Night wandering and prior fall history.", }; const validAnalysisOutput: ElderAiAnalysisOutput = { overallRiskLevel: "medium", summary: "Resident has elevated fall risk at night.", keyFindings: [validFinding], recommendations: [validRecommendation], dataGaps: ["Recent gait assessment is unavailable."], citations: [validCitation], confidence: 0.72, modelSummary: { provider: "openai-compatible", chatModel: "gpt-test", knowledgeRetrieval: "keyword", }, }; describe("AI validators", () => { describe("validateKnowledgeEntryInput", () => { it("accepts a scoped entry and trims user-authored text fields", () => { const result = validateKnowledgeEntryInput({ ...validKnowledgeInput, title: " Fall prevention guidance ", category: " Safety ", tags: " fall,night ", body: " Residents need clear walkways. ", }); expect(result).toEqual({ success: true, input: { ...validKnowledgeInput, title: "Fall prevention guidance", category: "Safety", tags: "fall,night", body: "Residents need clear walkways.", }, }); }); it.each([ { name: "non-object payload", value: null, reason: "请求数据格式无效" }, { name: "unknown scope", value: { ...validKnowledgeInput, scope: "facility" }, reason: "知识库范围无效" }, { name: "unknown status", value: { ...validKnowledgeInput, status: "archived" }, reason: "知识库状态无效" }, { name: "blank title", value: { ...validKnowledgeInput, title: " " }, reason: "知识标题不能为空" }, { name: "blank body", value: { ...validKnowledgeInput, body: "\n\t" }, reason: "知识内容不能为空" }, ])("rejects $name", ({ value, reason }) => { expect(validateKnowledgeEntryInput(value)).toEqual({ success: false, reason }); }); }); describe("validateElderAiAnalysisOutput", () => { it("accepts valid model output, coerces numeric confidence strings, and clamps the public score", () => { const result = validateElderAiAnalysisOutput({ ...validAnalysisOutput, confidence: "1.25", }); expect(result).toEqual({ ...validAnalysisOutput, confidence: 1, }); }); it.each([ { name: "unknown risk level", value: { ...validAnalysisOutput, overallRiskLevel: "urgent" }, }, { name: "finding with invalid severity", value: { ...validAnalysisOutput, keyFindings: [{ ...validFinding, severity: "debug" }], }, }, { name: "recommendation with invalid priority", value: { ...validAnalysisOutput, recommendations: [{ ...validRecommendation, priority: "soon" }], }, }, { name: "mixed citation id array", value: { ...validAnalysisOutput, keyFindings: [{ ...validFinding, citationIds: ["resident-1", 42] }], }, }, { name: "invalid citation source", value: { ...validAnalysisOutput, citations: [{ ...validCitation, sourceType: "web" }], }, }, { name: "unexpected model provider", value: { ...validAnalysisOutput, modelSummary: { ...validAnalysisOutput.modelSummary, provider: "anthropic" }, }, }, { name: "unexpected knowledge retrieval mode", value: { ...validAnalysisOutput, modelSummary: { ...validAnalysisOutput.modelSummary, knowledgeRetrieval: "embedding" }, }, }, { name: "non-finite confidence", value: { ...validAnalysisOutput, confidence: "not-a-number" }, }, ])("rejects $name", ({ value }) => { expect(validateElderAiAnalysisOutput(value)).toBeNull(); }); }); describe("parseDataScopes", () => { it("keeps only recognized scope strings in caller order", () => { expect(parseDataScopes(["elder", "health", "unknown", 7, "knowledge", "elder"])).toEqual([ "elder", "health", "knowledge", "elder", ]); }); it.each([undefined, null, "elder", { scopes: ["elder"] }])("returns an empty list for non-array input %#", (value) => { expect(parseDataScopes(value)).toEqual([]); }); }); });