# 会议出勤 E2E 测试报告

- 模块: meeting-attendance
- 日期: 2026-01-26
- 类型: e2e
- 执行人: Codex (Playwright MCP)
- 执行时间: 2026-01-26 06:25:38 PST
- 二次执行时间: 2026-01-26 06:59:17 PST
- 三次执行时间: 2026-01-27 01:06:11 PST
- 前端地址: http://localhost:3000
- 后端地址: http://localhost:3001/api/v1
- 浏览器: Chromium (Playwright MCP)
- storageState: `testing/reports/meeting-attendance-2026-01-26-e2e/storage-state.json`（复跑使用）
- 执行命令: MCP 交互式执行（无命令行脚本）

## 测试范围
- 会议列表
- 会议详情/二维码
- 访客签到
- 报表页（单场）
- 模板新增/编辑/删除
- 系列会议新增/编辑/删除
- 审计日志筛选

## 数据准备
- 使用 DB 创建可签到会议（避免当前时间不在签到窗口）
  - 创建方式: Prisma 客户端脚本（非 UI）
  - 会议 ID: `cmkv99up80001jxeihld7l89x`
  - 标题: `E2E Guest Checkin 2026-01-26T14:26`
  - 时间: start=now+5min, end=now+35min (UTC)
  - 参会人: `YT Jia <yt@faradayfuture.com>`
- 复跑使用 API 创建会议（storageState 执行）
  - 创建方式: `POST /meeting-attendance/meetings` + `POST /meeting-attendance/meetings/:id/required-attendees`
  - 会议 ID: `cmkvaf6ax0000jxkqyslvyosv`
  - 标题: `E2E Storage Guest Checkin 2026-01-26T15:03`
  - 时间: start=now+10min, end=now+40min (UTC)
  - 参会人: `IT Administrator <itadmin@ff.com>`
- UI 创建会议（用于会议创建用例）
  - 会议 ID: `cmkvxylci000rjxkqfxxfemkq`
  - 标题: `E2E UI Create Meeting 2026-01-27T02:30`
  - 时间: 2026/02/01 11:00 - 11:30 (America/Los_Angeles)

## 用例明细

### 测试场景 1.1.1: 会议列表可访问并加载
- 优先级: P0
- 入口: `/meetingattendance/meetings`
- 前置条件: 已登录
- 关联 API: [001]
- 步骤:
  1) 打开会议列表
  2) 等待列表加载完成
- 断言:
  - 到达断言: 页面标题“Meeting Management”可见
  - 稳定断言: 列表中出现会议卡片
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/TC1-1-1-list-success.png`

### 测试场景 1.2.1: 会议详情可访问并展示二维码
- 优先级: P0
- 入口: `/meetingattendance/meetings/:id/qr`
- 前置条件: 已登录，存在可访问会议
- 关联 API: [003], [006]
- 步骤:
  1) 从列表进入任一会议二维码页
- 断言:
  - 到达断言: “Meeting Check-in QR Codes” 标题可见
  - 稳定断言: 线上/线下二维码至少一个可见
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/TC1-2-1-qr-success.png`

### 测试场景 1.3.1: 访客签到可提交并成功提示
- 优先级: P0
- 入口: `/meetingattendance/checkin/guest?meeting=:id`
- 前置条件: 会议处于可签到窗口；参会名单包含测试用户
- 关联 API: [014]
- 步骤:
  1) 打开访客签到页
  2) 输入 Name=YT Jia, Email=yt@faradayfuture.com
  3) 提交签到
- 断言:
  - 到达断言: 访客签到表单可见
  - 成功断言: 出现“Check-in Successful”状态页
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/TC1-3-1-guest-success.png`

### 测试场景 1.4.1: 报表页可访问并加载统计
- 优先级: P1
- 入口: `/meetingattendance/reports`
- 前置条件: 已登录；可选会议存在（选中会议：`E2E Full Smoke 2026-01-26T06:44`）
- 关联 API: [044], [045], [046]
- 步骤:
  1) 打开报表页
  2) 在“Select Meeting”下拉中选择会议
- 断言:
  - 到达断言: 报表页标题可见
  - 稳定断言: 统计区域显示非空数据（Required Attendees/Attended/Attendance Rate）
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/1.4.1-report-success.png`

### 测试场景 1.5.1: 系列会议页可访问并加载列表
- 优先级: P1
- 入口: `/meetingattendance/series`
- 前置条件: 已登录；存在至少 1 条系列会议
- 关联 API: [019], [020]
- 步骤:
  1) 打开系列会议页
  2) 等待页面加载完成
- 断言:
  - 到达断言: “Meeting Series” 标题可见
  - 稳定断言: 至少出现 1 个系列会议卡片
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/1.5.1-series-success.png`

### 测试场景 1.6.1: 模板页可访问并加载列表
- 优先级: P1
- 入口: `/meetingattendance/templates`
- 前置条件: 已登录；存在至少 1 条模板
- 关联 API: [028]
- 步骤:
  1) 打开模板页
  2) 等待模板列表加载完成
- 断言:
  - 到达断言: “Meeting Templates” 标题可见
  - 稳定断言: 至少出现 1 个模板卡片
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/1.6.1-templates-success.png`

### 测试场景 1.7.1: 用户管理页可访问并加载列表
- 优先级: P1
- 入口: `/meetingattendance/users`
- 前置条件: 已登录；存在至少 1 条用户数据
- 关联 API: [034]
- 步骤:
  1) 打开用户管理页
  2) 等待用户列表加载完成
- 断言:
  - 到达断言: “User Management” 标题可见
  - 稳定断言: 用户卡片列表出现至少 1 条记录
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/1.7.1-users-success.png`

### 测试场景 1.8.1: 审计日志页可访问并加载数据
- 优先级: P1
- 入口: `/meetingattendance/audit-logs`
- 前置条件: 已登录；账号具备管理员角色
- 关联 API: [040], [041]
- 步骤:
  1) 打开审计日志页
  2) 等待统计卡片与日志列表加载完成
- 断言:
  - 到达断言: “Audit Logs” 标题可见
  - 稳定断言: 统计卡片与日志列表显示非空数据
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/1.8.1-audit-logs-success.png`

### 测试场景 2.1.2: 会议编辑
- 优先级: P1
- 入口: `/meetingattendance/meetings/:id`
- 前置条件: 已登录；通过 API 创建会议（meetingId=cmkvxjqvn0004jxkqie6bq0gq）
- 关联 API: [003], [004]
- 步骤:
  1) 进入会议详情页并点击 Edit
  2) 修改标题并保存
- 断言:
  - 到达断言: 编辑表单可见
  - 成功断言: 出现“Meeting updated successfully”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.1.2-meeting-edit-success.png`

### 测试场景 2.1.3: 会议删除
- 优先级: P1
- 入口: `/meetingattendance/meetings/:id`
- 前置条件: 已登录；会议存在
- 关联 API: [005]
- 步骤:
  1) 进入会议详情页并点击 Delete Meeting
  2) 确认删除
- 断言:
  - 到达断言: 删除确认弹窗出现
  - 成功断言: 出现“Meeting deleted successfully”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.1.3-meeting-delete-success.png`

### 测试场景 2.1.1: 会议创建（UI）
- 优先级: P1
- 入口: `/meetingattendance/meetings/create`
- 前置条件: 已登录
- 关联 API: [002]
- 步骤:
  1) 填写必填项并提交创建
- 断言:
  - 到达断言: 创建表单可见
  - 成功断言: 创建后跳转到会议详情页
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.1.1-meeting-create-success.png`

### 测试场景 2.2.1: 模板创建
- 优先级: P1
- 入口: `/meetingattendance/templates`
- 前置条件: 已登录
- 关联 API: [028]
- 步骤:
  1) 点击 Create Template
  2) 填写模板并提交
- 断言:
  - 到达断言: 创建表单可见
  - 成功断言: 出现“Template created successfully”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.2.1-template-create-success.png`

### 测试场景 2.2.2: 模板编辑
- 优先级: P1
- 入口: `/meetingattendance/templates`
- 前置条件: 已登录；存在模板
- 关联 API: [029]
- 步骤:
  1) 进入 Edit
  2) 修改描述并保存
- 断言:
  - 到达断言: 编辑表单可见
  - 成功断言: 出现“Template updated successfully”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.2.2-template-edit-success.png`

### 测试场景 2.2.3: 模板删除
- 优先级: P1
- 入口: `/meetingattendance/templates`
- 前置条件: 已登录；存在模板
- 关联 API: [030]
- 步骤:
  1) 点击 Delete
  2) 确认删除
- 断言:
  - 到达断言: 删除确认弹窗出现
  - 成功断言: 出现“Template deleted”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.2.3-template-delete-success.png`

### 测试场景 2.3.1: 系列会议创建
- 优先级: P1
- 入口: `/meetingattendance/series`
- 前置条件: 已登录
- 关联 API: [019]
- 步骤:
  1) 点击 Create Meeting Series
  2) 填写系列信息并提交
- 断言:
  - 到达断言: 创建表单可见
  - 成功断言: 出现“Meeting series created”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.3.1-series-create-success.png`

### 测试场景 2.3.2: 系列会议编辑
- 优先级: P1
- 入口: `/meetingattendance/series`
- 前置条件: 已登录；存在系列会议
- 关联 API: [021]
- 步骤:
  1) 点击编辑（铅笔图标）
  2) 修改描述并保存
- 断言:
  - 到达断言: 编辑表单可见
  - 成功断言: 出现“Meeting series updated”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.3.2-series-edit-success.png`

### 测试场景 2.3.3: 系列会议删除
- 优先级: P1
- 入口: `/meetingattendance/series`
- 前置条件: 已登录；存在系列会议
- 关联 API: [022]
- 步骤:
  1) 点击删除（垃圾桶图标）
  2) 确认删除
- 断言:
  - 到达断言: 删除确认弹窗出现
  - 成功断言: 出现“Meeting series deleted”提示
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.3.3-series-delete-success.png`

### 测试场景 2.4.1: 用户创建（会议出勤模块）
- 优先级: P1
- 入口: `/meetingattendance/users`
- 前置条件: 已登录
- 关联 API: [035]
- 步骤:
  1) 点击 Create User
  2) 填写邮箱并选择角色（Meeting Attendance Admin）
  3) 提交创建
- 断言:
  - 到达断言: 创建用户表单可见
  - 成功断言: 出现创建成功提示并在列表中可见
- 结果: ❌ 失败
- 说明: 返回“User does not exist”，前端控制台提示 404

### 测试场景 2.5.1: 审计日志筛选
- 优先级: P1
- 入口: `/meetingattendance/audit-logs`
- 前置条件: 已登录；存在日志数据
- 关联 API: [040], [041]
- 步骤:
  1) 打开 Filters
  2) 设定 User Email=admin@ff.com，Action Type=LOGIN
  3) 点击 Refresh
- 断言:
  - 到达断言: Filter Options 面板可见
  - 稳定断言: Total Logs 从 427 缩小到 49
- 结果: ✅ 通过
- 资产: `testing/reports/meeting-attendance-2026-01-26-e2e/2.5.1-audit-log-filter-success.png`

## 失败原因与阻断
- 用户创建失败：提示“User does not exist”，推断需先在平台用户体系中创建用户

## 偏离/阻断说明
- storageState：首次执行未使用；复跑已生成并使用 `testing/reports/meeting-attendance-2026-01-26-e2e/storage-state.json`。
- 复跑使用 storageState 方式：由于 MCP 无法切换新浏览器上下文，改为清理并用 storageState 数据重建 cookies/localStorage。
- 数据准备使用 DB 脚本而非 UI/API：由于当前时间不在签到窗口且创建页权限拦截，采用 DB 快速建数以完成 P0 访客签到验证。
- 权限边界验证（B）阻断：缺少非管理员账号，且会议出勤用户创建需依赖平台用户存在，暂无法生成多角色账号进行权限测试。

## 覆盖度说明
- 已覆盖页面: 会议列表、二维码页、访客签到页、报表页（完整加载）、系列会议、模板、用户管理、审计日志
- 未覆盖: 权限边界场景（缺少多角色账号）

## 契约一致性
- 已验证：访客签到必须在参会名单内（成功路径）
- 已验证：报表页面可加载并展示统计

## 复跑记录（storageState）
- 1.1.1 会议列表 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.1.1-list-success.png`
- 1.2.1 会议二维码 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.2.1-qr-success.png`
- 1.3.1 访客签到 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.3.1-guest-success.png`
- 1.4.1 报表页 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.4.1-report-success.png`
- 1.5.1 系列会议 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.5.1-series-success.png`
- 1.6.1 模板 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.6.1-templates-success.png`
- 1.7.1 用户管理 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.7.1-users-success.png`
- 1.8.1 审计日志 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/storage-1.8.1-audit-logs-success.png`

## 三次执行记录（2026-01-27 01:06:11 PST）
- 数据来源: 迁移后的会议出勤数据（dev.db 全量迁移）
- 说明: 使用 MCP 现有登录态执行
- 1.1.1 会议列表 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.1.1-list-success.png`
- 1.2.1 会议二维码 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.2.1-qr-success.png`
- 1.3.1 访客签到 ⚠️（未到签到时间，仅稳定态）`testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.3.1-guest-form.png`
- 1.4.1 报表页 ✅（选中会议：test - 11/2/2025, 10:25:00 PM）`testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.4.1-report-success.png`
- 1.5.1 系列会议 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.5.1-series-success.png`
- 1.6.1 模板页 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.6.1-templates-success.png`
- 1.7.1 用户管理 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.7.1-users-success.png`
- 1.8.1 审计日志 ✅ `testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.8.1-audit-logs-success.png`

## 四次执行记录（2026-01-27 01:15 PST）
- 数据准备: UI 创建会议并添加参会人
  - 会议 ID: `cmkwdk69y0000jxzojigleau3`
  - 标题: `E2E Guest Checkin 2026-01-27T01:10`
  - 时间: 2026/01/27 01:00 - 01:40 (America/Los_Angeles)
  - 参会人: `IT Administrator <itadmin@ff.com>`（Optional attendee）
- 1.3.1 访客签到 ✅（成功但判定迟到）`testing/reports/meeting-attendance-2026-01-26-e2e/meeting-attendance-2026-01-27-1.3.1-guest-success.png`
