Files
NextEdu/webtest/lesson-preparation_v1.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

294 lines
17 KiB
JSON

{
"test_date": "2026-06-22 19:57:34",
"module": "备课 (lesson-preparation)",
"version": "v1",
"base_url": "http://localhost:3000",
"summary": {
"total": 4,
"passed": 2,
"failed": 0,
"warnings": 2
},
"roles": {
"admin": {
"role": "admin",
"login_success": true,
"list_page": {
"status": "passed",
"http_status": 200,
"final_url": "http://localhost:3000/teacher/lesson-plans",
"errors": [],
"warnings": []
},
"new_page": {
"status": "passed",
"http_status": 200,
"final_url": "http://localhost:3000/teacher/lesson-plans/new",
"errors": [],
"warnings": []
},
"checks": [
{
"name": "有权访问备课列表页",
"passed": true,
"detail": "HTTP 200"
}
],
"screenshots": [
"access_admin_list.png",
"access_admin_new.png"
]
},
"teacher": {
"role": "teacher",
"login_success": true,
"list_page": {
"status": "warning",
"http_status": 200,
"final_url": "http://localhost:3000/teacher/lesson-plans",
"errors": [],
"warnings": [
"控制台错误 1 条"
]
},
"new_page": {
"status": "passed",
"http_status": 200,
"final_url": "http://localhost:3000/teacher/lesson-plans/new",
"errors": [],
"warnings": []
},
"checks": [
{
"name": "有权访问备课列表页",
"passed": true,
"detail": "HTTP 200"
}
],
"screenshots": [
"access_teacher_list.png",
"access_teacher_new.png"
]
},
"student": {
"role": "student",
"login_success": true,
"list_page": {
"status": "passed",
"http_status": 200,
"final_url": "http://localhost:3000/student/dashboard?from=%2Fteacher%2Flesson-plans&reason=forbidden",
"errors": [],
"warnings": []
},
"new_page": {
"status": "unknown",
"http_status": null,
"final_url": null,
"errors": [],
"warnings": []
},
"checks": [
{
"name": "无权限访问被正确拦截",
"passed": true,
"detail": "重定向到 http://localhost:3000/student/dashboard?from=%2Fteacher%2Flesson-plans&reason=forbidden"
}
],
"screenshots": [
"access_student_list.png"
]
},
"parent": {
"role": "parent",
"login_success": true,
"list_page": {
"status": "warning",
"http_status": 200,
"final_url": "http://localhost:3000/parent/dashboard?from=%2Fteacher%2Flesson-plans&reason=forbidden",
"errors": [],
"warnings": [
"控制台错误 1 条"
]
},
"new_page": {
"status": "unknown",
"http_status": null,
"final_url": null,
"errors": [],
"warnings": []
},
"checks": [
{
"name": "无权限访问被正确拦截",
"passed": true,
"detail": "重定向到 http://localhost:3000/parent/dashboard?from=%2Fteacher%2Flesson-plans&reason=forbidden"
}
],
"screenshots": [
"access_parent_list.png"
]
}
},
"console_errors_global": [
{
"role": "current",
"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"
},
{
"role": "current",
"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"
}
],
"teacher_features": {
"role": "teacher",
"features": {
"list": {
"name": "列表页",
"status": "passed",
"checks": [
{
"name": "页面标题包含'备课'/'Lesson Plan'",
"passed": true,
"detail": "body 长度 380020"
},
{
"name": "存在'新建课案'按钮",
"passed": true,
"detail": "找到 1 个"
},
{
"name": "存在筛选器",
"passed": true,
"detail": "找到 4 个 input/select"
},
{
"name": "课案卡片或空状态",
"passed": true,
"detail": "找到 12 个课案链接"
}
],
"errors": []
},
"create": {
"name": "新建课案",
"status": "passed",
"checks": [
{
"name": "存在模板选择按钮",
"passed": true,
"detail": "找到 11 个按钮"
},
{
"name": "模板选中状态可视化",
"passed": true,
"detail": "选中 5 个"
},
{
"name": "创建后跳转到编辑页",
"passed": true,
"detail": "planId=gpqmy3bpyts1lpnhomibnzr2"
}
],
"errors": []
},
"editor": {
"name": "编辑器",
"status": "passed",
"checks": [
{
"name": "标题输入框存在且有值",
"passed": false,
"detail": "标题=''"
},
{
"name": "React Flow 节点渲染",
"passed": true,
"detail": "渲染 8 个节点"
},
{
"name": "React Flow 边渲染",
"passed": true,
"detail": "渲染 7 条边"
},
{
"name": "存在保存版本按钮",
"passed": true,
"detail": "找到 1 个"
},
{
"name": "存在版本历史按钮",
"passed": true,
"detail": "找到 2 个"
},
{
"name": "存在添加节点按钮",
"passed": true,
"detail": "找到 1 个"
}
],
"errors": []
},
"panel": {
"name": "节点选中与侧边面板",
"status": "passed",
"checks": [
{
"name": "点击节点后出现侧边面板",
"passed": true,
"detail": "找到编辑元素: True"
}
],
"errors": []
},
"version": {
"name": "版本历史",
"status": "passed",
"checks": [
{
"name": "版本历史抽屉打开",
"passed": false,
"detail": "找到 0 个 dialog/drawer"
}
],
"errors": []
},
"duplicate_archive": {
"name": "复制与归档",
"status": "passed",
"checks": [
{
"name": "列表页存在课案卡片",
"passed": true,
"detail": "找到 13 个"
},
{
"name": "存在复制按钮",
"passed": true,
"detail": "找到 12 个"
},
{
"name": "存在归档按钮",
"passed": true,
"detail": "找到 12 个"
},
{
"name": "复制后课案数量增加",
"passed": false,
"detail": "复制前 13 → 复制后 13"
}
],
"errors": []
}
},
"screenshots": [
"teacher_feature_list.png",
"teacher_feature_create.png",
"teacher_feature_editor.png",
"teacher_feature_panel.png",
"teacher_feature_versions.png",
"teacher_feature_duplicate.png"
],
"errors": [],
"warnings": []
}
}