- Update E2E tests: announcements, auth, auth-business-flow, full-route-regression, grades, navigation, smoke-auth, teacher-web-test - Update integration tests: api-ai-chat, api-onboarding-complete, api-onboarding-status, proxy-guard, integration setup - Update visual regression tests: admin-dashboard, homepage, student-dashboard, teacher-dashboard, visual config, helpers - Update webapp tests: admin, parent, student full tests and debug scripts - Add new webapp tests: announcements_messages, settings_profile, debug scripts - Add webtest directory with test plans, screenshots, and diagnostic scripts
305 lines
14 KiB
JSON
305 lines
14 KiB
JSON
{
|
||
"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 <div className=\"flex items...\">\n <GlobalSearch>\n ...\n <MenuProvider scope={{Menu:[...], ...}} onClose={function Menu.useCallback} isUsingKeyboardRef={{current:false}} ...>\n <DropdownMenuTrigger asChild={true}>\n <DropdownMenuTrigger data-slot=\"dropdown-m...\" asChild={true}>\n <MenuAnchor asChild={true} __scopeMenu={{Menu:[...], ...}}>\n <PopperAnchor __scopePopper={{Menu:[...], ...}} asChild={true} ref={null}>\n <Primitive.div asChild={true} ref={function}>\n <Primitive.div.Slot ref={function}>\n <Primitive.div.SlotClone ref={function}>\n <Primitive.button type=\"button\" id=\"radix-_R_l...\" aria-haspopup=\"menu\" aria-expanded={false} ...>\n <Primitive.button.Slot type=\"button\" id=\"radix-_R_l...\" aria-haspopup=\"menu\" ...>\n <Primitive.button.SlotClone type=\"button\" id=\"radix-_R_l...\" aria-haspopup=\"menu\" ...>\n <Button variant=\"ghost\" size=\"icon\" className=\"relative t...\" aria-label=\"通知\" type=\"button\" ...>\n <button\n data-slot=\"dropdown-menu-trigger\"\n className={\"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded...\"}\n aria-label=\"通知\"\n type=\"button\"\n+ id=\"radix-_R_lebn6lb_\"\n- id=\"radix-_R_2lqbn6lb_\"\n aria-haspopup=\"menu\"\n aria-expanded={false}\n aria-controls={undefined}\n data-state=\"closed\"\n data-disabled={undefined}\n disabled={false}\n onPointerDown={function handleEvent}\n onKeyDown={function handleEvent}\n ref={function}\n >\n ...\n ...\n <MenuProvider scope={{Menu:[...], ...}} onClose={function Menu.useCallback} isUsingKeyboardRef={{current:false}} ...>\n <DropdownMenuTrigger asChild={true}>\n <DropdownMenuTrigger data-slot=\"dropdown-m...\" asChild={true}>\n <MenuAnchor asChild={true} __scopeMenu={{Menu:[...], ...}}>\n <PopperAnchor __scopePopper={{Menu:[...], ...}} asChild={true} ref={null}>\n <Primitive.div asChild={true} ref={function}>\n <Primitive.div.Slot ref={function}>\n <Primitive.div.SlotClone ref={function}>\n <Primitive.button type=\"button\" id=\"radix-_R_t...\" aria-haspopup=\"menu\" aria-expanded={false} ...>\n <Primitive.button.Slot type=\"button\" id=\"radix-_R_t...\" aria-haspopup=\"menu\" ...>\n <Primitive.button.SlotClone type=\"button\" id=\"radix-_R_t...\" aria-haspopup=\"menu\" ...>\n <Button variant=\"ghost\" className=\"relative s...\" type=\"button\" id=\"radix-_R_t...\" ...>\n <button\n data-slot=\"dropdown-menu-trigger\"\n className={\"inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm...\"}\n type=\"button\"\n+ id=\"radix-_R_tebn6lb_\"\n- id=\"radix-_R_3lqbn6lb_\"\n aria-haspopup=\"menu\"\n aria-expanded={false}\n aria-controls={undefined}\n data-state=\"closed\"\n data-disabled={undefined}\n disabled={false}\n onPointerDown={function handleEvent}\n onKeyDown={function handleEvent}\n ref={function}\n >\n ...\n"
|
||
}
|
||
]
|
||
} |