feat(student-portal): 完成Docker构建验证+全量测试通过+nextstep下游依赖文档
This commit is contained in:
229
apps/student-portal/src/mocks/fixtures.test.ts
Normal file
229
apps/student-portal/src/mocks/fixtures.test.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Mock Fixture JSON 文件测试
|
||||
*
|
||||
* 验证每个 fixture 文件存在且为有效 JSON。
|
||||
* Fixtures 存储原始业务数据(非 ActionState 信封),由 handlers.ts 包裹为 ActionState。
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import currentUser from "./fixtures/currentUser.json";
|
||||
import myClasses from "./fixtures/myClasses.json";
|
||||
import myExams from "./fixtures/myExams.json";
|
||||
import examDetail from "./fixtures/examDetail.json";
|
||||
import myHomework from "./fixtures/myHomework.json";
|
||||
import homeworkDetail from "./fixtures/homeworkDetail.json";
|
||||
import myGrades from "./fixtures/myGrades.json";
|
||||
import myAttendance from "./fixtures/myAttendance.json";
|
||||
import textbooks from "./fixtures/textbooks.json";
|
||||
import chapters from "./fixtures/chapters.json";
|
||||
import learningPath from "./fixtures/learningPath.json";
|
||||
import studentDashboard from "./fixtures/studentDashboard.json";
|
||||
import myWeakness from "./fixtures/myWeakness.json";
|
||||
import myTrend from "./fixtures/myTrend.json";
|
||||
import myNotifications from "./fixtures/myNotifications.json";
|
||||
import serverTime from "./fixtures/serverTime.json";
|
||||
import mySchedule from "./fixtures/mySchedule.json";
|
||||
import studentGrowth from "./fixtures/studentGrowth.json";
|
||||
import assignmentAnalysis from "./fixtures/assignmentAnalysis.json";
|
||||
import myProfile from "./fixtures/myProfile.json";
|
||||
import errorBook from "./fixtures/errorBook.json";
|
||||
import leaveRequests from "./fixtures/leaveRequests.json";
|
||||
import electiveCourses from "./fixtures/electiveCourses.json";
|
||||
import practiceSessions from "./fixtures/practiceSessions.json";
|
||||
import announcements from "./fixtures/announcements.json";
|
||||
import lessonPlans from "./fixtures/lessonPlans.json";
|
||||
import coursePlans from "./fixtures/coursePlans.json";
|
||||
import reportCard from "./fixtures/reportCard.json";
|
||||
import diagnosticReports from "./fixtures/diagnosticReports.json";
|
||||
import masterySummary from "./fixtures/masterySummary.json";
|
||||
|
||||
/** 检查值为对象(非数组、非 null) */
|
||||
function isObject(v: unknown): v is Record<string, unknown> {
|
||||
return typeof v === "object" && v !== null && !Array.isArray(v);
|
||||
}
|
||||
|
||||
/** 检查值为数组 */
|
||||
function isArray(v: unknown): v is unknown[] {
|
||||
return Array.isArray(v);
|
||||
}
|
||||
|
||||
describe("fixture 文件有效性", () => {
|
||||
const fixtures: Array<[string, unknown]> = [
|
||||
["currentUser", currentUser],
|
||||
["myClasses", myClasses],
|
||||
["myExams", myExams],
|
||||
["examDetail", examDetail],
|
||||
["myHomework", myHomework],
|
||||
["homeworkDetail", homeworkDetail],
|
||||
["myGrades", myGrades],
|
||||
["myAttendance", myAttendance],
|
||||
["textbooks", textbooks],
|
||||
["chapters", chapters],
|
||||
["learningPath", learningPath],
|
||||
["studentDashboard", studentDashboard],
|
||||
["myWeakness", myWeakness],
|
||||
["myTrend", myTrend],
|
||||
["myNotifications", myNotifications],
|
||||
["serverTime", serverTime],
|
||||
["mySchedule", mySchedule],
|
||||
["studentGrowth", studentGrowth],
|
||||
["assignmentAnalysis", assignmentAnalysis],
|
||||
["myProfile", myProfile],
|
||||
["errorBook", errorBook],
|
||||
["leaveRequests", leaveRequests],
|
||||
["electiveCourses", electiveCourses],
|
||||
["practiceSessions", practiceSessions],
|
||||
["announcements", announcements],
|
||||
["lessonPlans", lessonPlans],
|
||||
["coursePlans", coursePlans],
|
||||
["reportCard", reportCard],
|
||||
["diagnosticReports", diagnosticReports],
|
||||
["masterySummary", masterySummary],
|
||||
];
|
||||
|
||||
it("应加载 30 个 fixture 文件", () => {
|
||||
expect(fixtures).toHaveLength(30);
|
||||
});
|
||||
|
||||
it.each(fixtures)("fixture %s 应为有效的 JSON 对象或数组", (_name, data) => {
|
||||
expect(data).toBeDefined();
|
||||
expect(data).not.toBeNull();
|
||||
expect(typeof data === "object").toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("currentUser fixture", () => {
|
||||
it("应包含学生信息字段", () => {
|
||||
expect(isObject(currentUser)).toBe(true);
|
||||
expect(currentUser).toHaveProperty("id");
|
||||
expect(currentUser).toHaveProperty("name");
|
||||
expect(currentUser).toHaveProperty("studentNo");
|
||||
expect(currentUser).toHaveProperty("roles");
|
||||
expect(currentUser).toHaveProperty("permissions");
|
||||
expect(currentUser).toHaveProperty("dataScope");
|
||||
});
|
||||
|
||||
it("roles 应为数组", () => {
|
||||
expect(isObject(currentUser)).toBe(true);
|
||||
expect(isArray(currentUser.roles)).toBe(true);
|
||||
});
|
||||
|
||||
it("permissions 应为数组", () => {
|
||||
expect(isObject(currentUser)).toBe(true);
|
||||
expect(isArray(currentUser.permissions)).toBe(true);
|
||||
});
|
||||
|
||||
it("dataScope 应为字符串", () => {
|
||||
expect(isObject(currentUser)).toBe(true);
|
||||
expect(typeof currentUser.dataScope).toBe("string");
|
||||
});
|
||||
});
|
||||
|
||||
describe("serverTime fixture", () => {
|
||||
it("应包含 timestamp 和 offset 字段", () => {
|
||||
expect(isObject(serverTime)).toBe(true);
|
||||
expect(serverTime).toHaveProperty("timestamp");
|
||||
expect(serverTime).toHaveProperty("offset");
|
||||
expect(typeof serverTime.timestamp).toBe("string");
|
||||
expect(typeof serverTime.offset).toBe("number");
|
||||
});
|
||||
});
|
||||
|
||||
describe("myClasses fixture", () => {
|
||||
it("应为数组", () => {
|
||||
expect(isArray(myClasses)).toBe(true);
|
||||
});
|
||||
|
||||
it("每个班级应包含 id 和 name", () => {
|
||||
expect(isArray(myClasses)).toBe(true);
|
||||
if (myClasses.length > 0) {
|
||||
const first = myClasses[0];
|
||||
expect(isObject(first)).toBe(true);
|
||||
expect(first).toHaveProperty("id");
|
||||
expect(first).toHaveProperty("name");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("examDetail fixture", () => {
|
||||
it("应包含考试详情字段", () => {
|
||||
expect(isObject(examDetail)).toBe(true);
|
||||
expect(examDetail).toHaveProperty("id");
|
||||
expect(examDetail).toHaveProperty("name");
|
||||
expect(examDetail).toHaveProperty("questions");
|
||||
expect(examDetail).toHaveProperty("durationSeconds");
|
||||
});
|
||||
|
||||
it("questions 应为数组", () => {
|
||||
expect(isObject(examDetail)).toBe(true);
|
||||
expect(isArray(examDetail.questions)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("studentDashboard fixture", () => {
|
||||
it("应包含仪表盘聚合字段", () => {
|
||||
expect(isObject(studentDashboard)).toBe(true);
|
||||
expect(studentDashboard).toHaveProperty("upcomingHomework");
|
||||
expect(studentDashboard).toHaveProperty("upcomingExams");
|
||||
expect(studentDashboard).toHaveProperty("recentGrades");
|
||||
expect(studentDashboard).toHaveProperty("attendanceRate");
|
||||
expect(studentDashboard).toHaveProperty("learningStreakDays");
|
||||
expect(studentDashboard).toHaveProperty("avgScore");
|
||||
expect(studentDashboard).toHaveProperty("classRank");
|
||||
});
|
||||
});
|
||||
|
||||
describe("myNotifications fixture", () => {
|
||||
it("应为通知数组", () => {
|
||||
expect(isArray(myNotifications)).toBe(true);
|
||||
expect(myNotifications.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("每个通知应包含 id / type / title / content / read / createdAt", () => {
|
||||
expect(isArray(myNotifications)).toBe(true);
|
||||
const first = (myNotifications as unknown[])[0];
|
||||
expect(isObject(first)).toBe(true);
|
||||
expect(first).toHaveProperty("id");
|
||||
expect(first).toHaveProperty("type");
|
||||
expect(first).toHaveProperty("title");
|
||||
expect(first).toHaveProperty("content");
|
||||
expect(first).toHaveProperty("read");
|
||||
expect(first).toHaveProperty("createdAt");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errorBook fixture", () => {
|
||||
it("应包含 items 和 stats", () => {
|
||||
expect(isObject(errorBook)).toBe(true);
|
||||
expect(errorBook).toHaveProperty("items");
|
||||
expect(errorBook).toHaveProperty("stats");
|
||||
});
|
||||
});
|
||||
|
||||
describe("practiceSessions fixture", () => {
|
||||
it("应包含 sessions 和 stats", () => {
|
||||
expect(isObject(practiceSessions)).toBe(true);
|
||||
expect(practiceSessions).toHaveProperty("sessions");
|
||||
expect(practiceSessions).toHaveProperty("stats");
|
||||
});
|
||||
});
|
||||
|
||||
describe("reportCard fixture", () => {
|
||||
it("应包含成绩报告卡字段", () => {
|
||||
expect(isObject(reportCard)).toBe(true);
|
||||
expect(reportCard).toHaveProperty("studentId");
|
||||
expect(reportCard).toHaveProperty("studentName");
|
||||
expect(reportCard).toHaveProperty("subjects");
|
||||
expect(reportCard).toHaveProperty("overallAverage");
|
||||
expect(reportCard).toHaveProperty("overallRank");
|
||||
});
|
||||
});
|
||||
|
||||
describe("masterySummary fixture", () => {
|
||||
it("应包含掌握度摘要字段", () => {
|
||||
expect(isObject(masterySummary)).toBe(true);
|
||||
expect(masterySummary).toHaveProperty("studentId");
|
||||
expect(masterySummary).toHaveProperty("averageMastery");
|
||||
expect(masterySummary).toHaveProperty("mastery");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user