从用户旅程到 E2E 测试 | Celoria Platform
| App | Pages | CUJs | E2E Framework | Doc Location |
|---|---|---|---|---|
| Guest App | 25 | 7 | Flutter integration_test | product-design/guest-app-cuj.html |
| Employee App | 24 | 9 | Flutter integration_test | product-design/employee-app-cuj.html |
| Kiosk App | 8 | 3 | Flutter integration_test | product-design/kiosk-app-cuj.html |
| Web App | 134 pages + 37 modals | TBD (按模块拆分) | Playwright | notes/product-design/web-*.html |
| 优先级 | 定义 | 示例 | 测试覆盖要求 |
|---|---|---|---|
| P0 | 核心收入/安全路径,必须100%覆盖 | 登录、预约、支付、打卡 | 100% E2E 覆盖 |
| P1 | 高频使用路径,应该覆盖 | 查看排班、预约历史、账户设置 | 应该覆盖 (80%+) |
| P2 | 辅助功能,按资源覆盖 | 语言切换、主题设置、通知设置 | 按资源覆盖 (50%+) |
| P3 | 边缘场景,可选 | 错误恢复、离线提示、版本更新 | 可选 (best effort) |
关键用户旅程,定义用户完成核心任务的完整路径。
| 元素 | 说明 | 示例 |
|---|---|---|
| 触发点 | 用户为什么开始这个旅程 | 客人想预约下周二的美甲服务 |
| 阶段 | 旅程中的主要步骤 | 发现 → 选择服务 → 选技师 → 选时间 → 确认 → 完成 |
| 情感曲线 | 用户在每个阶段的满意度 | 选服务(焦虑)→ 看到可用时段(安心)→ 确认(满足) |
| 触点 | 用户与系统交互的界面 | App 主页、服务列表页、技师选择页、日历页 |
| 痛点 | 当前体验中的摩擦 | 技师头像加载慢、时间段选择不直观 |
| 机会点 | 优化方向 | 预加载技师图片、增加时间段推荐 |
将 CUJ 转化为页面级流程图,定义页面跳转和决策点。
用业务语言描述测试场景,连接产品需求和技术实现。
# Scenario: 客人成功预约服务
Given 用户已登录 Guest App
And 用户在服务选择页
And "Manicure" 服务可用
When 用户点击 "Manicure"
And 用户选择 "Any Technician"
And 用户选择明天下午 2:00 PM 的时段
And 用户填写联系信息(姓名、电话)
And 用户点击 "Confirm Booking"
Then 系统应显示 "Booking Successful" 消息
And 用户应看到预约确认页
And 预约应出现在 "My Appointments" 列表中
将 BDD 场景转化为可执行的自动化测试代码。
// Flutter Integration Test 示例
testWidgets('CUJ1: Guest books a manicure service', (tester) async {
// Given: 用户已登录
await _login(tester, 'guest@example.com', 'password123');
await tester.pumpAndSettle();
// When: 选择服务
await tester.tap(find.text('Manicure'));
await tester.pumpAndSettle();
// When: 选择技师和时间
await tester.tap(find.text('Any Technician'));
await tester.pumpAndSettle();
await tester.tap(find.byType(TimeSlotCard).first);
await tester.pumpAndSettle();
// When: 填写信息并确认
await tester.enterText(find.byType(TextField).first, 'John Doe');
await tester.enterText(find.byType(TextField).last, '555-0123');
await tester.tap(find.text('Confirm Booking'));
await tester.pumpAndSettle();
// Then: 验证成功
expect(find.text('Booking Successful'), findsOneWidget);
expect(find.byType(SuccessPage), findsOneWidget);
});
| Step | Output | Format | Location | 工时估算 |
|---|---|---|---|---|
| 1 | 梳理 CUJ | HTML 表格 | notes/product-design/*.html |
2-4 小时 |
| 2 | 画 User Flow | Mermaid 流程图 | 同上(内嵌在 HTML 中) | 1-2 小时 |
| 3 | 写 BDD Scenarios | Given-When-Then (Markdown) | 同上(每条 CUJ 2-3 个场景) | 2-3 小时 |
| 4 | 实现 E2E 测试 | Dart / TypeScript 代码 | integration_test/ 或 tests/e2e/ |
8-16 小时 |
| 概念 | 形式 | 关注点 | 是否需要 |
|---|---|---|---|
| Storyboard | 视觉插画 + 场景描述 | 情感体验、场景氛围、视觉风格 | ❌ 不需要 (时间成本高) |
| User Flow | 流程图 (Mermaid) | 页面跳转、决策分支、操作步骤 | ✅ 需要 (Layer 2 核心) |
| Journey Map | 横向时间轴 + 情感曲线 | 用户目标、痛点、触点、情感波动 | ✅ 需要 (Layer 1 核心) |
| BDD Scenario | Given-When-Then 文本 | 业务逻辑、验收标准、测试用例 | ✅ 需要 (Layer 3 核心) |
| CUJ 文档 | 覆盖模块 | Pages | Modals | 预估 CUJ 数 |
|---|---|---|---|---|
web-auth-cuj.html |
登录 + 会话管理 + 租户选择 | 2 | 0 | 2-3 |
web-appointments-cuj.html |
预约看板 + 新建/编辑/取消 + Walk-in + Checkout | 8 | 8 | 4-5 |
web-day-end-closeout-cuj.html |
日结关账 5 步 + 收银台 + 解锁 | 1 | 4 | 2-3 |
web-employees-cuj.html |
员工管理 + 排班 + 考勤 + Payroll | 10 | 7 | 4-5 |
web-guests-cuj.html |
客户管理 + 标签 + 档案 + 黑名单 | 6 | 4 | 2-3 |
web-payments-cuj.html |
支付 + 退款 + 拆单 + 终端 + 发票 | 4 | 5 | 3-4 |
web-booking-cuj.html |
公共预约(Web Booking)+ Check-in + Terminal | 14 | 2 | 3-4 |
web-reports-cuj.html |
报表 + 分析 + 导出 | 12 | 1 | 2-3 |
web-marketing-cuj.html |
营销 + 实验 + 策略 + 模板 + 礼品卡 | 22 | 1 | 3-4 |
web-settings-cuj.html |
系统设置 + 权限 + 门店 + 服务 + 同步 + Platform | 18 | 5 | 3-4 |
| 合计 | — | ~97 核心页 | 37 | ~28-38 |
脚本自动扫描所有 page.tsx 和 *Modal*.tsx / *Dialog*.tsx,生成注册表。
// page-registry.json 格式
{
"pages": [
{
"id": "admin-appointments",
"route": "/admin/appointments",
"file": "src/app/[locale]/[tenant]/admin/appointments/page.tsx",
"module": "appointments",
"cuj_refs": [], // ← 由 Step 3 填充
"e2e_refs": [], // ← 由 Step 3 填充
"status": "uncovered" // uncovered | covered | exempt
}
],
"modals": [
{
"id": "new-appointment-modal",
"file": "src/components/Appointment/NewAppointmentModal.tsx",
"module": "appointments",
"cuj_refs": [],
"e2e_refs": [],
"status": "uncovered"
}
]
}
每个 CUJ 文档的 User Flow 和 BDD Scenarios 中,用 <!-- TOUCHES: page-id, modal-id --> 注释标注触及的页面和弹窗。
<!-- ======= CUJ-1: 日结关账完整流程 ======= -->
<!-- TOUCHES: admin-day-end-closeout, day-end-closeout-modal,
currency-count-modal, close-register-modal,
unlock-closeout-modal -->
<h3>User Flow</h3>
<div class="mermaid">
flowchart TD
A[日结主页 admin-day-end-closeout] --> B[点击开始日结]
B --> C[DayEndCloseoutModal 5步流程]
...
</div>
<h3>BDD Scenarios</h3>
<!-- ... Given/When/Then ... -->
<p class="test-file">E2E: day-end-closeout.spec.ts</p>
校验脚本读取 Page Registry + 所有 CUJ 文档中的 TOUCHES 注释,输出追溯矩阵。
// 校验脚本: scripts/check-cuj-coverage.js
//
// 输入:
// 1. page-registry.json(自动生成)
// 2. notes/product-design/web-*.html(人工标注 TOUCHES)
// 3. frontend/web_app/tests/e2e/*.spec.ts(E2E 测试文件)
//
// 输出:
// ✅ admin-appointments → W-APT-CUJ-1, W-APT-CUJ-2 → appointments-board.spec.ts
// ✅ new-appointment-modal → W-APT-CUJ-1 → appointments-board.spec.ts
// ❌ admin-gift-cards → (NOT COVERED) → (NO E2E)
// ⚠️ admin-storybook → EXEMPT (internal tool)
// ❌ refund-modal → (NOT COVERED) → (NO E2E)
Gap Report 将未覆盖的页面/弹窗分为三类:
| 分类 | 含义 | 处理方式 |
|---|---|---|
| ❌ NOT COVERED | 面向用户的页面/弹窗,但没有任何 CUJ 引用 | 必须创建或扩展 CUJ 来覆盖 |
| ⚠️ NO E2E | CUJ 引用了,但没有对应的 E2E 测试文件 | 需要编写 E2E 测试 |
| ✅ EXEMPT | 内部工具、开发页面、法律页面等 | 标注为 exempt,不计入覆盖率 |
| 阶段 | 交付物 | 工时 |
|---|---|---|
| Phase 1 | Page Registry 生成脚本 + 首个 CUJ 文档(Day-End Closeout) | 4-6 小时 |
| Phase 2 | 剩余 9 个模块的 CUJ 文档(每个 3-4 小时) | 27-36 小时 |
| Phase 3 | 追溯矩阵校验脚本 + 首次 Gap Report | 4-6 小时 |
| 持续 | 每次新增页面/弹窗时更新 CUJ + 运行校验脚本 | ~30 分钟/次 |
check-cuj-coverage.js 集成到 CI/CD 管道中。当 PR 新增了 page.tsx 或 *Modal*.tsx 但没有更新任何 CUJ 文档时,CI 发出 warning(不阻塞,但可见)。
核心价值: 将用户体验设计与自动化测试连接起来,确保产品"做对的事"(CUJ)和"把事做对"(E2E)。
实施建议: 从 P0 CUJ 开始,每周迭代 1-2 条,3-6 个月内覆盖核心路径。保持文档简洁实用,避免过度设计。
覆盖保障: 通过 Page↔CUJ 追溯矩阵(Section 8)确保每个面向用户的页面和弹窗都被至少一个 CUJ 覆盖,防止"孤儿页面"遗漏测试。
相关文档:
web-day-end-closeout-cuj.html — 日结关账(优先)web-appointments-cuj.html — 预约管理web-employees-cuj.html — 员工管理web-payments-cuj.html — 支付与收银web-auth-cuj.html — 认证与会话