---
title: "feat: 全项目 E2E 测试套件 + CI workflow"
date: 2026-06-28
plan_type: feat
origin: docs/solutions/integration-issues/jwt-secret-dev-mode-user-id-mismatch.md
depth: deep
---

# feat: 全项目 E2E 测试套件 + CI workflow

## Summary

建立覆盖全项目的 E2E 测试体系，包括前端所有关键视图的 Playwright spec、后端 API/WS 闭环测试、认证状态持久化测试、数据一致性测试，以及 GitHub Actions/Gitea CI workflow。目标：让本次出现的 reload 登录失效、日历数据不一致、对话无法删除等问题在 CI 阶段就被捕获，不再流入用户手中。

## Problem Frame

当前项目虽有测试基础设施（后端 `tests/e2e/` + 前端 Playwright 4 spec），但存在严重缺口：

1. **认证状态持久化未测**：reload 后登录态保持、token 跨重启持久化、refresh token 冷启动 — 这些场景无 E2E 覆盖，导致问题4（reload 跳登录页）长期未发现
2. **数据一致性未测**：agent 通过工具创建数据（如日历事件）后，UI 能否看到 — 无端到端验证，导致问题2（日历事件看不到）长期未发现
3. **前端视图覆盖不足**：仅 login/chat/calendar/terminal 4个 spec，skills/documents/bitable/evolution/monitor/settings/admin 等视图零覆盖
4. **CI 完全无测试**：`.github/workflows/` 和 `.gitea/workflows/` 都没有测试 job，所有测试依赖开发者手动运行
5. **对话管理 CRUD 未测**：创建、删除、切换对话的端到端流程未覆盖，导致问题1（对话无法删除）长期未发现

## Requirements

- R1: 认证状态持久化 E2E — 覆盖 reload、token 跨重启、refresh token 冷启动
- R2: 数据一致性 E2E — 覆盖 agent 工具创建数据后 UI 可见性（日历优先）
- R3: 对话管理 CRUD E2E — 覆盖创建、删除、切换、历史加载
- R4: 前端全视图 E2E — 覆盖 skills/documents/bitable/evolution/monitor/settings/admin
- R5: 后端 API E2E 补充 — 覆盖未测的 REST 端点（experts/mcp/workflows 等）
- R6: CI workflow — GitHub Actions + Gitea 自动运行测试

## Key Technical Decisions

- **KTD1: Playwright 作为前端 E2E 主框架**。项目已安装 `@playwright/test@^1.59.0` 且配置完善（双服务器自动启动、global-setup 创建测试用户），无需引入新框架。扩展新 spec 复用现有 helpers.ts。
- **KTD2: 后端 E2E 复用 `tests/e2e/conftest.py` 基础设施**。MockLLMProvider + 端口 18765 + `scripts/run_e2e.sh` 已成熟，新测试直接扩展。不引入 testcontainers（项目已声明但未使用，保持一致性）。
- **KTD3: CI 用 docker-compose.test.yml 启动依赖**。PostgreSQL pgvector (5434) + Redis (6381) 已配置，CI 中 `docker-compose -f docker-compose.test.yml up -d` 即可。不引入 testcontainers 以保持与本地环境一致。
- **KTD4: 认证状态测试用 `page.reload()` + `evaluate` 验证 localStorage**。不 mock Tauri Keychain（Web 模式下走 localStorage fallback），直接验证持久化行为。
- **KTD5: 数据一致性测试用 "agent 路径写入 + UI 路径读取" 双向验证**。先通过 API/WS 让 agent 创建日历事件，再通过 UI 验证事件可见。这是本次问题的核心回归测试。

---

## U1. 认证状态持久化 E2E

**Goal:** 验证登录状态跨 reload、跨服务器重启持久化，捕获问题4（reload 跳登录页）的回归。

**Requirements:** R1

**Dependencies:** 无

**Files:**
- `src/agentkit/server/frontend/e2e/auth-persistence.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/helpers.ts` (modify — 添加 `reloadAndWaitAuth` helper)

**Approach:**
- 测试1：登录 → reload → 验证仍处于已认证状态（不跳 login）
- 测试2：登录 → 清除 localStorage → reload → 验证跳 login
- 测试3：登录 → 服务器重启（Playwright 无法直接重启服务器，改为验证 token 过期场景）→ 验证 refresh token 冷启动
- 测试4：登录 → 访问受保护页面 → 验证 Authorization header 携带 access token
- 测试5：登录 → 等待 access token 过期（mock 时间或短 TTL）→ 验证 silent refresh

**Patterns to follow:** `e2e/login.spec.ts` 的 `loginViaApi` + `loginAndHydrate` 模式

**Test scenarios:**
- Happy path: 登录后 reload 保持登录态
- Edge case: localStorage 为空时 reload 跳 login
- Error path: refresh token 无效时跳 login 并清除存储
- Integration: access token 过期时自动 refresh，不中断用户操作

**Verification:** `npm run test:e2e -- --grep "auth-persistence"` 全部通过

---

## U2. 对话管理 CRUD E2E

**Goal:** 验证对话的创建、删除、切换、历史加载端到端流程，捕获问题1（对话无法删除）的回归。

**Requirements:** R3

**Dependencies:** U1

**Files:**
- `src/agentkit/server/frontend/e2e/conversation-management.spec.ts` (create)

**Approach:**
- 测试1：新建对话 → 发送消息 → 验证对话出现在列表
- 测试2：删除对话 → 验证从列表消失 → reload → 验证不再出现（未被"复活"）
- 测试3：多对话切换 → 验证消息历史正确加载
- 测试4：删除当前活跃对话 → 验证自动切换到下一个或新建
- 测试5：删除所有对话 → 验证空状态显示

**Patterns to follow:** `e2e/chat.spec.ts` 的 `sendChatMessage` + `waitForLlmResponse` 模式

**Test scenarios:**
- Happy path: 创建 → 发消息 → 删除 → 验证消失
- Edge case: 删除进行中的对话（pending 状态）
- Error path: 删除不存在的对话（404）→ UI 正确处理
- Integration: 多对话切换时消息历史隔离

**Verification:** `npm run test:e2e -- --grep "conversation-management"` 全部通过

---

## U3. 日历数据一致性 E2E

**Goal:** 验证 agent 通过 calendar 工具创建事件后，UI 日历视图能显示该事件，捕获问题2（日历事件看不到）的回归。

**Requirements:** R2

**Dependencies:** U1

**Files:**
- `src/agentkit/server/frontend/e2e/calendar-data-consistency.spec.ts` (create)

**Approach:**
- 测试1：通过 chat 让 agent 创建日历事件（"帮我创建下周一上午10点的项目会议"）→ 切换到日历视图 → 验证事件可见
- 测试2：通过 UI 创建事件 → 通过 API 查询 → 验证 user_id 一致
- 测试3：通过 chat 创建事件 → 通过 API 查询 → 验证 user_id 不是 hallucinate 值（"default"/"zhangsan"）
- 测试4：多事件场景 → 验证日历正确渲染所有事件
- 测试5：删除事件 → 验证 UI 和 API 同步消失

**Patterns to follow:** `e2e/calendar.spec.ts` 的 E1-E8 模式 + `e2e/chat.spec.ts` 的 agent 交互

**Test scenarios:**
- Happy path: agent 创建 → UI 可见
- Data integrity: user_id 一致性（agent 路径 vs UI 路径）
- Edge case: agent 创建事件但 LLM 未提供 user_id → 使用 default_user_id
- Integration: UI 创建 + agent 创建混合场景

**Verification:** `npm run test:e2e -- --grep "calendar-data-consistency"` 全部通过

---

## U4. 前端全视图 E2E 补充

**Goal:** 为 skills/documents/bitable/evolution/monitor/settings/admin 视图补充 E2E spec，确保所有关键视图可访问且基本功能正常。

**Requirements:** R4

**Dependencies:** U1

**Files:**
- `src/agentkit/server/frontend/e2e/skills-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/documents-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/bitable-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/evolution-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/monitor-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/settings-view.spec.ts` (create)
- `src/agentkit/server/frontend/e2e/admin-view.spec.ts` (create)

**Approach:**
每个视图至少覆盖：
- 页面加载（无白屏、无 401）
- 核心功能（如 skills 列表加载、documents 上传按钮可见等）
- 导航交互（侧边栏切换、标签页切换）
- 错误状态（空数据、加载失败）

**Patterns to follow:** `e2e/calendar.spec.ts` 的 E1（面板加载）模式

**Test scenarios:** 每个视图 3-5 个测试（加载、核心功能、空状态、错误处理）

**Verification:** `npm run test:e2e` 全部 spec 通过

---

## U5. 后端 API E2E 补充

**Goal:** 补充未覆盖的后端 REST 端点 E2E 测试（experts/mcp/workflows/llm gateway 等）。

**Requirements:** R5

**Dependencies:** 无

**Files:**
- `tests/e2e/test_api_coverage.py` (create)

**Approach:**
- 遍历 `/api/v1/` 下所有路由前缀
- 对未覆盖的端点编写基础 E2E（健康检查、认证要求、CRUD 基础）
- 重点覆盖：`/experts`、`/mcp`、`/workflows`、`/llm/chat`（SSE）、`/config`、`/system`

**Patterns to follow:** `tests/e2e/test_basic_api.py` 的 `api_client` fixture 模式

**Test scenarios:**
- Happy path: 每个端点的基础 GET/POST 返回预期状态码
- Auth: 受保护端点无 token 返回 401
- Error path: 无效参数返回 4xx

**Verification:** `python3 -m pytest tests/e2e/test_api_coverage.py -v` 通过

---

## U6. CI workflow 建立

**Goal:** 在 GitHub Actions 和 Gitea Actions 中建立测试 workflow，自动运行后端 pytest + 前端 vitest + Playwright E2E。

**Requirements:** R6

**Dependencies:** U1, U2, U3, U4, U5

**Files:**
- `.github/workflows/test.yml` (create)
- `.gitea/workflows/test.yml` (create)

**Approach:**
- GitHub Actions workflow：
  - Trigger: push to main/develop, PR to main
  - Jobs: backend-test (pytest) + frontend-unit (vitest) + frontend-e2e (playwright)
  - Services: PostgreSQL (pgvector) + Redis via docker-compose.test.yml
  - Cache: pip + npm 依赖缓存
- Gitea Actions workflow：同上（Gitea 兼容 GitHub Actions 语法）

**Patterns to follow:** 标准 GitHub Actions Python + Node.js workflow 模式

**Test scenarios:**
- Happy path: PR 触发 workflow，所有测试通过
- Failure: 故意引入 bug，验证测试失败并阻止合并

**Verification:** 推送分支 → CI 自动运行 → 全绿

---

## Scope Boundaries

### In scope
- 前端 Playwright E2E spec（认证持久化、对话管理、日历一致性、全视图覆盖）
- 后端 API E2E 补充（未覆盖端点）
- CI workflow（GitHub Actions + Gitea）

### Deferred to Follow-Up Work
- Tauri 桌面端 E2E（需引入 tauri-driver，当前无基础设施）
- 真实 LLM E2E 扩展（成本高，保持现有 mock 策略）
- 性能/负载测试（本次聚焦功能正确性）
- 视觉回归测试（Percy/Chromatic，后续补充）

### Non-goals
- 重写现有测试框架
- 引入 testcontainers（保持与现有 docker-compose.test.yml 一致）
- 修改产品代码（测试发现的问题由 ce-debug 修复）

---

## Risks & Dependencies

| Risk | Mitigation |
|------|------------|
| Playwright E2E 执行慢（双服务器启动） | 已有 `reuseExistingServer: !CI` 配置，本地复用 |
| MockLLMProvider 响应不匹配新场景 | 扩展 `MOCK_LLM_RESPONSES` 字典，新增 calendar 场景 |
| CI 中 PostgreSQL pgvector 版本不匹配 | docker-compose.test.yml 已指定 `pgvector/pgvector:pg15` |
| calendar.spec.ts 已知 cold-start bug（refresh token） | 新 spec 使用 UI 表单登录，避开 localStorage 注入 |

---

## System-Wide Impact

- **开发者工作流**：PR 将自动触发 CI 测试，需要开发者在本地运行测试后再推送
- **部署流程**：CI 绿灯成为部署前置条件
- **测试维护**：新增 spec 需要维护，helpers.ts 扩展需保持向后兼容

---

## Open Questions

无 — 范围和 CI 策略已确认。

---

## Deferred to Implementation

- 各 spec 的具体选择器（需实际查看 DOM 结构）
- MockLLMProvider 的新场景响应内容
- CI workflow 的具体缓存键值
- 各视图 spec 的详细测试用例（需查看实际 UI）
