From 63f28a57f52ec98d6d238f089a59b02b36042864 Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Sun, 9 Aug 2026 10:08:30 +0800 Subject: [PATCH] docs: update E2E test docs with mock LLM architecture and agent chat test details Co-authored-by: CodeFree --- AGENTS.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 404eb39..28dc4e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,6 +40,7 @@ - 数据库隔离:独立 SQLite 文件 `packages/drizzle-pkg/db.test.sqlite`,workers=1 避免并发 - 验证码注入:业务代码分支方式,`server/service/captcha/challenge.ts` 中 `E2E_TEST_MODE` 门控返回固定验证码 - 环境变量:`.env.test` 文件,由 `global-setup.ts` 和 `playwright.config.ts` 内部代码解析注入 +- Mock LLM 服务器:global-setup 中内联启动,端口 3600,OpenAI 兼容 SSE 流式响应 ### 运行命令 @@ -49,10 +50,61 @@ bun run test:e2e:headed # 有头模式运行 bun run test:e2e:ui # Playwright UI 模式 ``` +> **注意**:Playwright 命令必须传 `--config=e2e/playwright.config.ts`,否则找不到 config 文件会跳过 globalSetup。package.json 脚本中已包含。 + +### 测试文件 + +| 文件 | 测试数 | 说明 | +|------|--------|------| +| `specs/smoke.spec.ts` | 5 | 冒烟测试:页面可访问、验证码 API、全局配置 API | +| `specs/auth-login.spec.ts` | 7 | 登录流程:表单验证、成功登录、失败场景、登出 | +| `specs/auth-register.spec.ts` | 6 | 注册流程:表单验证、成功注册、重复用户名、注册后登录 | +| `specs/auth-guard.spec.ts` | 9 | 路由守卫:未登录重定向、已登录访问、白名单页面 | +| `specs/agent-chat.spec.ts` | 10 | Agent 对话:欢迎页、输入框、发送消息、流式回复、连续对话 | + +### Mock LLM 架构 + +Agent 对话测试依赖 Mock LLM 服务器,在 `global-setup.ts` 中内联启动: + +``` +global-setup.ts 流程: + 1. 加载 .env.test + 2. 删除旧测试数据库 + 3. build Nuxt 应用 + 4. 运行数据库迁移 + 5. 运行 seed(创建 bootstrap admin 用户) + 6. 启动 Mock LLM 服务器(端口 3600,OpenAI 兼容 SSE) + 7. 向测试数据库插入 LLM provider + model + userConfig + 8. 启动 preview 服务器(端口 3400) + 9. 等待服务器就绪 +``` + +**Mock LLM 服务器**(内联在 global-setup.ts 中): +- 监听端口:`MOCK_LLM_PORT`(默认 3600) +- 端点:`POST /v1/chat/completions` +- 响应格式:OpenAI 兼容 SSE 流式(`data: {"choices":[{"delta":{"content":"x"}}]}`) +- 固定回复内容:`你好!这是一个测试回复。`(逐字符流式输出,20ms 间隔) +- 不校验 API key,不校验请求体 + +**数据库 seed**(步骤7,直接 SQL 插入): +- `llm_providers` 表:id=1, user_id=1, name="mock-provider", slug="mock-provider", base_url="http://localhost:3600/v1", parse_mode="openai-compatible" +- `llm_models` 表:id=1, provider_id=1, name="mock-model", model_id="mock-model", enabled=1, supports_tools=0 +- `user_configs` 表:user_id=1, key="preferredLlmModelId", value="1", value_type="number" + +> **注意**:Mock LLM 逻辑内联在 global-setup.ts 中,不通过 import 外部 .ts 文件。原因是 Playwright + Node ESM 无法正确解析 `.ts` 扩展名导入。独立文件 `e2e/mock-llm-server.ts` 仍保留但不再被导入。 + ### 编写测试注意事项 - 用户名规则:`/^[a-zA-Z0-9_]{3,20}$/`(3-20字符,仅字母数字下划线),生成动态用户名时注意长度 - `toHaveURL` 匹配完整 URL(含 host),正则应匹配路径结尾而非开头 - 已登录状态测试:通过 UI 登录设置 cookie,不要用 `request` context(cookie 不共享到 `page`) - 避免使用 `waitForLoadState("networkidle")`,部分页面有持续网络请求会导致超时 -- SSR 中间件重定向可能不带 `?redirect=` 参数,测试应兼容此情况 \ No newline at end of file +- SSR 中间件重定向可能不带 `?redirect=` 参数,测试应兼容此情况 +- `execSync` 的 `stdio` 必须用 `"pipe"` 而非 `"inherit"`,否则在 Playwright 子进程中可能导致管道阻塞 +- Agent 对话测试间会共享数据库 session,登录后需点击"新建会话"按钮(`.new-chat-btn`)避免跨测试 session 污染 +- 示例卡片(`.example-card`)点击后直接发送消息,不是填充输入框 +- Agent 消息 DOM:用户消息 `.agent-message.is-user .user-bubble`,助手消息 `.agent-message.is-assistant .agent-markdown` +- Agent 输入 DOM:`textarea.agent-textarea`,发送按钮 `button.btn-send`,停止按钮 `button.btn-stop` +- 登录页面 DOM:`#login-username`、`#login-password`、`#login-captcha`,提交 `button[type="submit"]` +- 固定验证码:`FIXED_CAPTCHA` 常量在 `e2e/fixtures/test-users.ts` +- 测试用户:`E2E_ADMIN`(username/password)在 `e2e/fixtures/test-users.ts` \ No newline at end of file