You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

6.4 KiB

AI八荣八耻

  1. Shame in guessing APIs, Honor in careful research.
  2. Shame in vague execution, Honor in seeking confirmation.
  3. Shame in assuming business logic, Honor in human verification.
  4. Shame in creating interfaces, Honor in reusing existing ones.
  5. Shame in skipping validation, Honor in proactive testing.
  6. Shame in breaking architecture, Honor in following specifications.
  7. Shame in pretending to understand, Honor in honest ignorance.
  8. Shame in blind modification, Honor in careful refactoring.

必须遵循

  • 注意代码的解耦,做到高内聚,低耦合
  • 安装依赖时,必须写死依赖的版本,禁止任何升级的可能,如存在需要升级的场景,必须手动执行安装新版本命令
  • 新建的mono包必须在根目录安装
  • 使用nuxt时遇到不清楚的,必须先加载nuxt-remote查询文档再进行分析
  • 能够用toast提示的尽量用toast
  • 数据库schema编写完成之后,必须使用命令进行迁移,不能自己生成

代码抽离与复用

  • 编写任何前端组件/工具函数时,必须评估是否可以抽离为通用模块,加入对应 packages(bolt-ui、common 等)
  • bolt-ui 只放基础通用 UI 组件(Button、Input、Modal、Container 等),业务相关组件留在 app/components/
  • 开发时随时查看 bolt-ui 已有组件(Button、ConfigProvider、Container 等),优先复用,避免重复造轮子
  • 新增 bolt-ui 组件需遵循现有模式:components/<Name>/src/<Name>.vue + index.ts(使用 withInstall 注册),并在 components/index.ts 中导出
  • 必须时刻注意bolt-ui中readme.md的更新

设计方案

开发页面与组件时必须参考 DESIGN.md

E2E 测试

架构

  • 框架:Playwright 1.49.1 + @nuxt/test-utils 3.15.4
  • 测试目录:e2e/(specs/、helpers/、fixtures/)
  • 测试服务器:build + preview 模式,global-setup.ts 自动执行 build → migrate → seed → spawn server
  • 数据库隔离:独立 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 流式响应

运行命令

bun run test:e2e          # 运行全部 E2E 测试(headless)
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 对话:欢迎页、输入框、发送消息、流式回复、连续对话
specs/agent-documents.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= 参数,测试应兼容此情况
  • 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