{ "test_date": "2026-06-22 19:22:17", "module": "考勤 (Attendance)", "version": "0.1.0", "base_url": "http://localhost:3000", "summary": { "total": 28, "passed": 28, "failed": 0, "warnings": 0 }, "roles": { "admin": { "role": "admin", "login_success": true, "pages": [ { "url": "http://localhost:3000/admin/attendance", "route": "/admin/attendance", "category": "考勤总览", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/admin/attendance", "checks": [ { "name": "标题关键词匹配 (考勤总览)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\admin_admin_attendance.png" } ], "interactions": [ { "name": "管理员考勤总览 - 统计卡片显示", "passed": true, "detail": "" }, { "name": "管理员考勤总览 - 筛选器存在", "passed": true, "detail": "" }, { "name": "管理员考勤总览 - 统计分析快捷链接", "passed": true, "detail": "" } ], "errors": [], "warnings": [] }, "teacher": { "role": "teacher", "login_success": true, "pages": [ { "url": "http://localhost:3000/teacher/attendance", "route": "/teacher/attendance", "category": "考勤记录", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/teacher/attendance", "checks": [ { "name": "标题关键词匹配 (考勤记录)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\teacher_teacher_attendance.png" }, { "url": "http://localhost:3000/teacher/attendance/sheet", "route": "/teacher/attendance/sheet", "category": "录入考勤", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/teacher/attendance/sheet", "checks": [ { "name": "标题关键词匹配 (录入考勤)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\teacher_teacher_attendance_sheet.png" }, { "url": "http://localhost:3000/teacher/attendance/stats", "route": "/teacher/attendance/stats", "category": "考勤统计", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/teacher/attendance/stats", "checks": [ { "name": "标题关键词匹配 (考勤统计)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\teacher_teacher_attendance_stats.png" } ], "interactions": [ { "name": "录入考勤 - 班级选择器存在", "passed": true, "detail": "" }, { "name": "录入考勤 - 日期选择器存在", "passed": true, "detail": "" }, { "name": "录入考勤 - 全部标记到场按钮", "passed": true, "detail": "" }, { "name": "考勤统计 - 统计卡片显示", "passed": true, "detail": "" }, { "name": "考勤统计 - 班级切换器存在", "passed": true, "detail": "找到 1 个班级切换链接" } ], "errors": [], "warnings": [] }, "student": { "role": "student", "login_success": true, "pages": [ { "url": "http://localhost:3000/student/attendance", "route": "/student/attendance", "category": "我的考勤", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/student/attendance", "checks": [ { "name": "标题关键词匹配 (我的考勤)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\student_student_attendance.png" } ], "interactions": [ { "name": "学生考勤 - 统计信息显示", "passed": true, "detail": "" }, { "name": "学生考勤 - 最近记录显示", "passed": true, "detail": "" } ], "errors": [], "warnings": [] }, "parent": { "role": "parent", "login_success": true, "pages": [ { "url": "http://localhost:3000/parent/attendance", "route": "/parent/attendance", "category": "子女考勤", "status": "passed", "http_status": 200, "final_url": "http://localhost:3000/parent/attendance", "checks": [ { "name": "标题关键词匹配 (子女考勤)", "passed": true, "detail": "实际匹配: True" } ], "errors": [], "warnings": [], "console_errors": [], "screenshot": "webtest\\screenshots\\attendance\\parent_parent_attendance.png" } ], "interactions": [ { "name": "家长考勤 - 子女信息显示", "passed": true, "detail": "" }, { "name": "家长考勤 - 出勤率卡片", "passed": true, "detail": "" }, { "name": "家长考勤 - 月历视图", "passed": true, "detail": "" } ], "errors": [], "warnings": [] } }, "cross_role_tests": [ { "role": "teacher", "forbidden_route": "/admin/attendance", "final_url": "http://localhost:3000/teacher/dashboard?from=%2Fadmin%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /teacher/dashboard(拒绝访问)" }, { "role": "teacher", "forbidden_route": "/student/attendance", "final_url": "http://localhost:3000/teacher/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /teacher/dashboard(拒绝访问)" }, { "role": "teacher", "forbidden_route": "/parent/attendance", "final_url": "http://localhost:3000/teacher/dashboard?from=%2Fparent%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /teacher/dashboard(拒绝访问)" }, { "role": "student", "forbidden_route": "/admin/attendance", "final_url": "http://localhost:3000/student/dashboard?from=%2Fadmin%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /student/dashboard(拒绝访问)" }, { "role": "student", "forbidden_route": "/teacher/attendance", "final_url": "http://localhost:3000/student/dashboard?from=%2Fteacher%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /student/dashboard(拒绝访问)" }, { "role": "student", "forbidden_route": "/parent/attendance", "final_url": "http://localhost:3000/student/dashboard?from=%2Fparent%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /student/dashboard(拒绝访问)" }, { "role": "parent", "forbidden_route": "/admin/attendance", "final_url": "http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /parent/dashboard(拒绝访问)" }, { "role": "parent", "forbidden_route": "/teacher/attendance", "final_url": "http://localhost:3000/parent/dashboard?from=%2Fteacher%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /parent/dashboard(拒绝访问)" }, { "role": "parent", "forbidden_route": "/student/attendance", "final_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden", "passed": true, "error": "重定向回 /parent/dashboard(拒绝访问)" } ], "interactions": [], "console_errors_global": [ { "role": "student", "error": "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:\n\n- A server/client branch `if (typeof window !== 'undefined')`.\n- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n- Date formatting in a user's locale which doesn't match the server.\n- External changing data without sending a snapshot of it along with the HTML.\n- Invalid HTML tag nesting.\n\nIt can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n\n%s%s https://react.dev/link/hydration-mismatch \n\n ...\n