Files
NextEdu/webtest/attendance_0.1.0.json
SpecialX d884c6d513
Some checks failed
CI / scheduled-backup (push) Failing after 36s
CI / backup-verify (push) Has been skipped
CI / weekly-dr-drill (push) Failing after 0s
CI / build-deploy (push) Has been cancelled
CI / security-scan (push) Has been cancelled
test: update and add E2E, integration, visual, and webapp tests
- 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
2026-06-23 17:39:40 +08:00

305 lines
14 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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"
}
]
}