Some checks failed
Security / deep-security-scan (push) Failing after 20m5s
DR Drill / dr-drill (push) Failing after 1m31s
CI / scheduled-backup (push) Failing after 1m31s
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
主要变更: - 新增 lesson-preparation 模块: 备课编辑器、节点编辑、AI 建议、知识点选择、版本历史、作业发布 - 新增 shared 通用组件: charts/question-bank-filters/schedule-list/ui (chip-nav/filter-bar/page-header/stat-card/stat-item) - 新增 student/admin 端 loading.tsx 与 error.tsx, 优化加载与错误态体验 - 新增 teacher/lesson-plans 页面 (列表/新建/编辑) - 新增 drizzle 迁移 0002_tiny_lionheart 及 snapshot - 新增 textbooks/schema.ts 与 exams/utils/normalize-structure.ts - 修复 Tiptap v3 SSR hydration 崩溃 (rich-text-block immediatelyRender: false) - 重构多模块 data-access/actions/组件, 修复权限校验与类型规范 - 同步架构文档 004/005 反映新增模块、导出、依赖关系 - 归档 bugs/* 测试报告与 e2e 测试脚本 (admin/parent/student/teacher web_test)
493 lines
17 KiB
JSON
493 lines
17 KiB
JSON
{
|
||
"test_date": "2026-06-20 12:28:43",
|
||
"test_target": "家长端 (Parent)",
|
||
"base_url": "http://localhost:3000",
|
||
"parent_email": "parent_g1c1_1@xiaoxue.edu.cn",
|
||
"summary": {
|
||
"total": 24,
|
||
"passed": 17,
|
||
"failed": 7,
|
||
"warnings": 0
|
||
},
|
||
"pages": {
|
||
"parent_dashboard": {
|
||
"url": "http://localhost:3000/parent/dashboard",
|
||
"route": "/parent/dashboard",
|
||
"category": "Dashboard",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"parent_grades": {
|
||
"url": "http://localhost:3000/parent/grades",
|
||
"route": "/parent/grades",
|
||
"category": "Grades",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/grades",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"parent_attendance": {
|
||
"url": "http://localhost:3000/parent/attendance",
|
||
"route": "/parent/attendance",
|
||
"category": "Attendance",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/attendance",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"announcements": {
|
||
"url": "http://localhost:3000/announcements",
|
||
"route": "/announcements",
|
||
"category": "Announcements",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/announcements",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"messages": {
|
||
"url": "http://localhost:3000/messages",
|
||
"route": "/messages",
|
||
"category": "Messages",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/messages",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"messages_compose": {
|
||
"url": "http://localhost:3000/messages/compose",
|
||
"route": "/messages/compose",
|
||
"category": "Messages",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/messages/compose",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"profile": {
|
||
"url": "http://localhost:3000/profile",
|
||
"route": "/profile",
|
||
"category": "Profile",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/profile",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"settings": {
|
||
"url": "http://localhost:3000/settings",
|
||
"route": "/settings",
|
||
"category": "Settings",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/settings",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"settings_security": {
|
||
"url": "http://localhost:3000/settings/security",
|
||
"route": "/settings/security",
|
||
"category": "Settings",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/settings/security",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"parent_children_user_s_g1c1_1": {
|
||
"url": "http://localhost:3000/parent/children/user_s_g1c1_1",
|
||
"route": "/parent/children/user_s_g1c1_1",
|
||
"category": "Child Detail",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/children/user_s_g1c1_1",
|
||
"redirect_url": null,
|
||
"errors": [],
|
||
"warnings": [
|
||
"Error text on page: Due 2026年6月18日"
|
||
],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_admin_dashboard": {
|
||
"url": "http://localhost:3000/admin/dashboard",
|
||
"route": "/admin/dashboard",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fdashboard&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fdashboard&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_admin_school": {
|
||
"url": "http://localhost:3000/admin/school",
|
||
"route": "/admin/school",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_teacher_dashboard": {
|
||
"url": "http://localhost:3000/teacher/dashboard",
|
||
"route": "/teacher/dashboard",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 500,
|
||
"final_url": "http://localhost:3000/teacher/dashboard",
|
||
"redirect_url": null,
|
||
"errors": [
|
||
"跨角色访问返回 HTTP 500(应被重定向拦截)",
|
||
"Failed to load resource: the server responded with a status of 500 (Internal Server Error)",
|
||
"%o\n\n%s Error: Teacher not found\n at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?61:9381:27)\n at TeacherDashboardPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__6e4018f8._.js?62:2019:23)\n at resolveErrorDev (http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_react-server-dom-turbopack_9212ccad._.js:...(已截断)"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_exams": {
|
||
"url": "http://localhost:3000/teacher/exams",
|
||
"route": "/teacher/exams",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/teacher/exams/all",
|
||
"redirect_url": "http://localhost:3000/teacher/exams/all",
|
||
"errors": [
|
||
"⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效",
|
||
"%o\n\n%s Error: Failed query: select `exams`.`id`, `exams`.`title`, `exams`.`description`, `exams`.`structure`, `exams`.`creator_id`, `exams`.`subject_id`, `exams`.`grade_id`, `exams`.`start_time`, `exams`.`end_time`, `exams`.`exam_mode`, `exams`.`duration_minutes`, `exams`.`shuffle_questions`, `exams`.`allow_late_start`, `exams`.`late_start_grace_minutes`, `exams`.`anti_cheat_enabled`, `exams`.`status`, `exams`.`created_at`, `exams`.`updated_at`, `exams_subject`.`data` as `subject`, `exams_gradeE...(已截断)"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_homework": {
|
||
"url": "http://localhost:3000/teacher/homework",
|
||
"route": "/teacher/homework",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 500,
|
||
"final_url": "http://localhost:3000/teacher/homework/assignments",
|
||
"redirect_url": "http://localhost:3000/teacher/homework/assignments",
|
||
"errors": [
|
||
"跨角色访问返回 HTTP 500(应被重定向拦截)",
|
||
"Failed to load resource: the server responded with a status of 500 (Internal Server Error)",
|
||
"%o\n\n%s Error: Teacher not found\n at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?47:9381:27)\n at AssignmentsPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__8e4de1e6._.js?48:253:23)\n at resolveErrorDev (http://localhost:3000/_next/static/chunks/node_modules_next_dist_compiled_react-server-dom-turbopack_9212ccad._.js:1882:1...(已截断)"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_grades": {
|
||
"url": "http://localhost:3000/teacher/grades",
|
||
"route": "/teacher/grades",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/teacher/grades",
|
||
"redirect_url": null,
|
||
"errors": [
|
||
"⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/grades),权限隔离失效"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_questions": {
|
||
"url": "http://localhost:3000/teacher/questions",
|
||
"route": "/teacher/questions",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/teacher/questions",
|
||
"redirect_url": null,
|
||
"errors": [
|
||
"⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/questions),权限隔离失效"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_classes": {
|
||
"url": "http://localhost:3000/teacher/classes",
|
||
"route": "/teacher/classes",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/teacher/classes/my",
|
||
"redirect_url": "http://localhost:3000/teacher/classes/my",
|
||
"errors": [
|
||
"⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/classes/my),权限隔离失效"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_teacher_attendance": {
|
||
"url": "http://localhost:3000/teacher/attendance",
|
||
"route": "/teacher/attendance",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "failed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/teacher/attendance",
|
||
"redirect_url": null,
|
||
"errors": [
|
||
"⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/attendance),权限隔离失效"
|
||
],
|
||
"warnings": [],
|
||
"content_checks": []
|
||
},
|
||
"forbidden_student_dashboard": {
|
||
"url": "http://localhost:3000/student/dashboard",
|
||
"route": "/student/dashboard",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fdashboard&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fdashboard&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_student_learning": {
|
||
"url": "http://localhost:3000/student/learning",
|
||
"route": "/student/learning",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_student_grades": {
|
||
"url": "http://localhost:3000/student/grades",
|
||
"route": "/student/grades",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_student_attendance": {
|
||
"url": "http://localhost:3000/student/attendance",
|
||
"route": "/student/attendance",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
},
|
||
"forbidden_management_grade_classes": {
|
||
"url": "http://localhost:3000/management/grade/classes",
|
||
"route": "/management/grade/classes",
|
||
"category": "Cross-Role Access Control",
|
||
"status": "passed",
|
||
"http_status": 200,
|
||
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden",
|
||
"redirect_url": "http://localhost:3000/parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden",
|
||
"errors": [],
|
||
"warnings": [],
|
||
"content_checks": [
|
||
"跨角色访问被权限系统拦截"
|
||
]
|
||
}
|
||
},
|
||
"functional_checks": [
|
||
{
|
||
"name": "返回仪表盘按钮",
|
||
"expected": "存在 Back to Dashboard 链接",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "子女姓名标题",
|
||
"expected": "显示子女姓名",
|
||
"actual": "小明",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "邮箱掩码处理",
|
||
"expected": "邮箱被掩码为 j***@domain.com",
|
||
"actual": "Masked",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "作业摘要卡片",
|
||
"expected": "显示 {childName}'s Homework",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "作业统计 - Pending",
|
||
"expected": "显示 Pending 计数",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "作业统计 - Submitted",
|
||
"expected": "显示 Submitted 计数",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "作业统计 - Graded",
|
||
"expected": "显示 Graded 计数",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "成绩趋势卡片",
|
||
"expected": "显示成绩信息",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "今日课表卡片",
|
||
"expected": "显示 {childName}'s Today Schedule",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "View all 链接",
|
||
"expected": "存在 View all 链接",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "仪表盘标题",
|
||
"expected": "Parent Dashboard",
|
||
"actual": "Parent Dashboard",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "问候语显示",
|
||
"expected": "Good morning/afternoon/evening 或 Welcome",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "Grades 快捷入口",
|
||
"expected": "存在",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "Attendance 快捷入口",
|
||
"expected": "存在",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "Announcements 快捷入口",
|
||
"expected": "存在",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "子女卡片显示",
|
||
"expected": "≥1 个子女卡片",
|
||
"actual": "1 个",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "子女卡片 - Pending 统计",
|
||
"expected": "显示 Pending 计数",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "子女卡片 - Overdue 统计",
|
||
"expected": "显示 Overdue 计数",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "子女数量提示",
|
||
"expected": "显示 'N child(ren) linked'",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "侧边栏 - Dashboard",
|
||
"expected": "显示 Dashboard 导航项",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "侧边栏 - Grades",
|
||
"expected": "显示 Grades 导航项",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "侧边栏 - Attendance",
|
||
"expected": "显示 Attendance 导航项",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "侧边栏 - Announcements",
|
||
"expected": "显示 Announcements 导航项",
|
||
"actual": "Found",
|
||
"passed": true
|
||
},
|
||
{
|
||
"name": "侧边栏 - Messages",
|
||
"expected": "显示 Messages 导航项",
|
||
"actual": "Found",
|
||
"passed": true
|
||
}
|
||
],
|
||
"security_checks": [
|
||
{
|
||
"name": "访问不存在/非关联子女应被拒绝",
|
||
"expected": "显示 Access denied 或 404",
|
||
"actual": "Access denied",
|
||
"passed": true
|
||
}
|
||
],
|
||
"console_errors": [],
|
||
"navigation_issues": []
|
||
} |