# 医梦统一入口客户端 Web Demo — 测试报告

**日期**: 2026-06-02  
**版本**: 0.1.0  
**分支**: 统一入口客户端演示  
**测试环境**: Windows 11 / Node.js 20.19.4 / Chrome (本地)

---

## 概览

| 层级 | 测试文件 | 测试用例 | 通过 | 失败 | 通过率 |
|------|---------|---------|------|------|--------|
| 单元测试 | 5 | 25 | 25 | 0 | 100% |
| E2E 测试 | 2 | 4 | 4 | 0 | 100% |
| **合计** | **7** | **29** | **29** | **0** | **100%** |

---

## 一、单元测试（Vitest）

```
PASS  tests/unit/sse.spec.ts                        (6 tests / 8ms)
PASS  tests/unit/apiClient.spec.ts                   (3 tests / 17ms)
PASS  tests/unit/terminalStore.spec.ts               (7 tests / 15ms)
PASS  tests/unit/doctorAssistantFigure.spec.ts       (1 test  / 42ms)
PASS  tests/unit/cardRenderer.spec.ts               (8 tests / 53ms)
─────────────────────────────────────────────────────────
Test Files  5 passed (5)
     Tests  25 passed (25)
  Duration  2.47s
```

### 1.1 SSE 解析器 (`sse.spec.ts`) — 6 通过

| # | 测试用例 | 状态 | 说明 |
|---|---------|------|------|
| 1 | parses named SSE events with JSON data and preserves remainder | PASS | 正确解析 `event:`/`data:` 配对并保留未完成片段 |
| 2 | accumulates across multiple chunks | PASS | 跨 chunk 拼接，收到完整 `\n\n` 后再输出事件 |
| 3 | handles multiple events in one chunk | PASS | 单次收到多个 `\n\n` 分隔的事件时全部解析 |
| 4 | ignores malformed data events without throwing | PASS | data 非合法 JSON 时不抛异常，返回 error 类型事件 |
| 5 | skips events without both event and data lines | PASS | 缺失 event 或 data 行的事件静默跳过 |
| 6 | handles all six SSE event types | PASS | 全部 6 种类型 (task_updated / message_delta / message_completed / card_created / error / completed) 均正确解析 |

### 1.2 HMAC 辅助函数 (`apiClient.spec.ts`) — 3 通过

| # | 测试用例 | 状态 | 说明 |
|---|---------|------|------|
| 1 | hashes body as lowercase hex sha256 | PASS | `{"a":1}` 的 SHA-256 散列与预期一致 |
| 2 | produces consistent hash for same input | PASS | 相同输入产生相同哈希 |
| 3 | produces different hashes for different input | PASS | 不同输入产生不同哈希 |

### 1.3 全局状态 Store (`terminalStore.spec.ts`) — 7 通过

| # | 测试用例 | 状态 | 说明 |
|---|---------|------|------|
| 1 | starts in idle right-panel mode with no active card | PASS | 初始状态：idle，无 activeCard |
| 2 | switches to task mode when a card is active | PASS | setActiveCard → contextPanelMode = task |
| 3 | switches to completed mode for appointment-success card | PASS | 挂号成功卡片 → contextPanelMode = completed |
| 4 | switches to error mode when error message is set | PASS | setError → contextPanelMode = error |
| 5 | resets to idle clears task, card and error | PASS | resetToIdle 清空 task / activeCard / errorMessage |
| 6 | appends assistant delta correctly | PASS | appendAssistantDelta 流式拼接文本 |
| 7 | completes assistant message marks streaming false | PASS | completeAssistantMessage 标记流结束 |

### 1.4 医生形象组件 (`doctorAssistantFigure.spec.ts`) — 1 通过

| # | 测试用例 | 状态 | 说明 |
|---|---------|------|------|
| 1 | renders the static doctor assistant image and no voice controls | PASS | 渲染医生图片、文字说明，无语音/按钮交互，无"可听""可说" |

### 1.5 卡片渲染器 (`cardRenderer.spec.ts`) — 8 通过

| # | 测试用例 | 状态 | 说明 |
|---|---------|------|------|
| 1 | renders department card by cardKey | PASS | `department-selection` → 渲染"推荐科室""神经内科" |
| 2 | renders doctor selection card | PASS | `doctor-selection` → 渲染"选择医生""李明""主任医师" |
| 3 | renders time slot selection card | PASS | `time-slot-selection` → 渲染"选择时间""明天 09:30-09:45" |
| 4 | renders confirm appointment card | PASS | `confirm-appointment` → 渲染"确认挂号信息""神经内科""25 元" |
| 5 | renders payment QR card with mock label | PASS | `payment-qrcode` → 必须包含"联调演示 / Mock 支付" |
| 6 | renders appointment success card with mock label | PASS | `appointment-success` → 渲染"A023"，包含 mock 标签 |
| 7 | renders error card for unknown card key | PASS | 未知 cardKey → 显示"暂不支持的卡片类型" |
| 8 | emits action event when card button is clicked | PASS | 按钮点击正确向上 emit action 事件 |

---

## 二、E2E 测试（Playwright）

```
PASS  [desktop-1440]  visual-layout        (1.5s)
PASS  [desktop-1920]  visual-layout        (1.8s)
PASS  [desktop-1440]  registration-flow    (1.9s)
PASS  [desktop-1920]  registration-flow    (2.2s)
─────────────────────────────────────────────────────────
4 passed (6.4s)
```

### 2.1 视觉布局验收 (`visual-layout.spec.ts`) — 2 通过

| 视口 | 状态 | 验收点 |
|------|------|--------|
| 1440×900 | PASS | 标题"医梦门诊助手"可见；左侧"说出需求，我来判断下一步"可见；医生助手图片存在；"静态形象展示"文案存在；语音/发送按钮在中间区域；无"智能挂号"等大按钮；无横向滚动 |
| 1920×1080 | PASS | 同上 |

### 2.2 挂号全流程 (`registration-flow.spec.ts`) — 2 通过

| 视口 | 状态 | 验收点 |
|------|------|--------|
| 1440×900 | PASS | 输入症状 → 科室推荐 → 选择神经内科 → 选择李明医生 → 选择 09:30 → 确认挂号 → Mock 支付 → 挂号成功(A023) |
| 1920×1080 | PASS | 同上 |

---

## 三、构建验证

```
pnpm build   PASS   (vue-tsc --noEmit + vite build)
```

产物：
```
dist/index.html                 0.41 kB (gzip: 0.30 kB)
dist/assets/index-gsDAE_p7.css  10.44 kB (gzip: 2.28 kB)
dist/assets/index-9PUkZENd.js   84.33 kB (gzip: 32.96 kB)
```

---

## 四、覆盖范围分析

| 模块 | 单元测试 | E2E | 覆盖状态 |
|------|:---:|:---:|------|
| SSE 解析器 (`sse.ts`) | 6 | - | 完全覆盖 |
| HMAC 辅助 (`hmac.ts`) | 3 | - | 完全覆盖 |
| API 客户端 (`client.ts`) | - | - | Demo 模式已间接覆盖，真实模式待后端联调 |
| 状态 Store | 7 | - | 完全覆盖 |
| 医生形象组件 | 1 | 2 | 完全覆盖 |
| 卡片渲染器 | 8 | 2 | 完全覆盖 |
| 对话面板 | - | 2 | E2E 间接覆盖 |
| 三栏布局 Shell | - | 2 | E2E 间接覆盖 |
| 挂号进度组件 | - | 2 | E2E 间接覆盖 |

---

## 五、已知缺口

1. **API 客户端真实模式** — `client.ts` 的真实 HTTP 请求分支需要后端 SSE 接口就绪后才能验证
2. **医生 PNG 图片** — 当前使用 SVG 占位，设计稿指定了真实 PNG（macOS 路径未同步至 Windows 环境）
3. **语音功能** — 按设计在 `out of scope` 范围内，当前仅展示按钮并给出提示
4. **hmac.ts 真实签名** — Demo 签名仅用于本地演示，真实 HMAC 签名待联调时接入
5. **应用启动引导** — 设备注册、心跳、场景加载流程待后端就绪后覆盖
