-
安装工具(只需做一次):
npm install -g cursor-cli # 安装 Cursor 命令行工具 npm install --save-dev cypress # 安装 Cypress 测试框架 npm install --save-dev jq # 安装 jq(用于解析 JSON 报告)
-
配置脚本与文件:
-
将
auto-dev.sh放在项目根目录,执行:chmod +x auto-dev.sh
-
确保
package.json包含: -
在项目根添加并填写
cypress.config.js。
-
-
快速启动:
-
编辑以下章节中"7. 验收标准与测试方法",将需求直接复制到脚本参数中。
-
运行:
./auto-dev.sh feature/login specs/login.md
-
脚本会循环执行「AI 生成 → 本地测试 → AI 修复 → 重测」直至所有测试通过。
-
全绿后,手动提交:
git add . && git commit -m "feat: 完成登录模块" && git push
-
-
业务目标: 通过 AI 语音交互,为 Web3 用户提供 MCP 服务入口;支持 MCP 内置服务与第三方 API。
-
主要用户群:
- 普通用户:使用平台提供的语音功能和 MCP/第三方服务。
- 第三方开发者:上传并管理自己封装的 API(如 Dify 或 Coze),扩展平台功能。
-
技术栈: React 18 + Vite、Ant Design Mobile、MSW、Cypress、Cursor CLI。
-
架构: 组件化 + Hook 封装 + Mock 服务 + 自动化脚本。
src/
├── components/ # 通用 UI 组件
├── hooks/ # 自定义 Hooks (useVoice, useApi, useIntent)
├── services/ # API 调用封装 (apiClient)
├── contexts/ # 全局状态 (Session, UserConfig, Theme, Auth)
├── mocks/ # Mock 数据 (仅 dev 环境)
├── utils/ # 工具函数 (格式化、schema 校验)
├── styles/ # 主题与全局样式 (tokens.css)
├── pages/ # 页面级组件 (主页面、登录、设置等)
├── App.jsx # 应用根组件
└── index.js # 入口文件
响应式策略(Mobile-First + Desktop-Enhance)
-
移动优先 (Mobile-First)
- 默认样式针对最小设备(≥320px)编写,使用不带前缀的 Tailwind 类或基础 CSS 直接应用于所有设备。
- 确保在最小视口下布局和交互可用,不需要额外的媒体查询。
-
断点设计 (Breakpoints)
- sm (≥640px):小屏平板 / 大手机
- md (≥768px):常规平板
- lg (≥1024px):小笔记本
- xl (≥1280px):大屏
示例 Tailwind 配置:
// tailwind.config.js module.exports = { theme: { screens: { sm: '640px', md: '768px', lg: '1024px', xl: '1280px', }, container: { center: true, padding: '1rem', }, }, };
-
流式网格布局 (Fluid Grid)
-
CSS Grid
.grid-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--spacing-md); }
-
Tailwind
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4"> <!-- 卡片列表 --> </div>
-
-
流式排版 & 容器宽度
-
字体响应式:使用
clamp()随视口变化h1 { font-size: clamp(1.5rem, 5vw, 2.5rem); }
-
容器:
.container { max-width: 1200px; width: 100%; padding: 0 var(--spacing-md); margin: 0 auto; }
-
-
关键组件适配示例
<form class="max-w-md mx-auto p-4 bg-secondary rounded-lg"> <label class="block mb-2">用户名</label> <input class="w-full p-2 mb-4 rounded border" /> <label class="block mb-2">密码</label> <input class="w-full p-2 mb-4 rounded border" type="password" /> <button class="w-full py-2 rounded bg-primary text-white">登录</button> </form>
max-w-md(Tailwind 默认 28rem)保证小屏全宽,大屏居中显示。
-
测试 & 校验
- 在 Chrome DevTools 中模拟手机和平板断点预览。
- Cypress 中使用
cy.viewport('iphone-6')、cy.viewport(1280,800)验证 E2E 脚本。
| 序号 | 模块名称 | 说明 | 依赖 |
|---|---|---|---|
| 1 | 登录组件 | 用户名+密码表单,错误提示 | API: /api/login |
| 2 | 注册组件 | 用户名+邮箱+密码表单,表单校验 | API: /api/register |
| 3 | 首页列表 | 列表渲染,可分页、下拉刷新 | API: /api/items |
| 4 | 语音录制控件 | 录音/停止按钮,超时提示 | -- |
| 5 | 语音识别结果展示 | STT 结果 + 自动触发后续执行 | API: /api/interpret |
| 6 | 技能服务目录 | 动态展示 MCP & 第三方服务列表 | API: /api/services |
| 7 | 进度条组件 | "识别中 → 理解中 → 执行中 → 完成" 四阶段进度反馈 | -- |
| 8 | 通用弹窗/Toast | 错误、成功、超时、重试提示 | -- |
| 9 | 全局布局 | Header/Footer/主内容区 | -- |
| 10 | 错误边界 | React ErrorBoundary 捕获渲染错误并展示友好提示 | -- |
| 11 | Mock 服务 | MSW 拦截 /api/* 请求,提供本地模拟响应 |
-- |
| 12 | 第三方开发者控制台 | 允许开发者通过表单创建和管理 Dify/Coze API 集成。支持列表查看、启用/禁用、删除等功能。核心UI DeveloperConsolePage 已完成并通过单元测试。 |
API: /api/v1/dev/integrations |
| 13 | 主题切换与设置 | 支持深色/浅色模式切换,自定义主题颜色、圆角等 | ThemeContext, localStorage |
| 14 | 样式调试面板 | 允许开发者在运行时修改设计令牌并导出配置 | -- |
- 各模块的详细验收标准见第7章"验收标准与测试方法",无需单独创建
specs/目录。
前端样式采用 设计变量 + 主题系统,确保在开发或上线后可以运行时灵活调整:
:root {
--color-primary: #4FD1C5;
--bg-primary: #1E1E2F;
--text-primary: #F8F8F8;
--error-color: #F56565;
--warning-color: #ECC94B;
--radius-base: 8px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--font-base: 'Inter', sans-serif;
}import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
less: {
modifyVars: {
'@primary-color': 'var(--color-primary)',
'@layout-body-background': 'var(--bg-primary)',
'@text-color': 'var(--text-primary)',
'@border-radius-base': 'var(--radius-base)',
},
javascriptEnabled: true,
}
}
}
});export const theme = {
colors: {
primary: 'var(--color-primary)',
background: 'var(--bg-primary)',
text: 'var(--text-primary)',
error: 'var(--error-color)',
warning: 'var(--warning-color)',
},
radii: { base: 'var(--radius-base)' },
spacing: {
sm: 'var(--spacing-sm)',
md: 'var(--spacing-md)',
lg: 'var(--spacing-lg)',
},
fontFamily: 'var(--font-base)',
};-
动态切换: 提供
ThemeProvider(通过ThemeContext) 和相关设置组件 (ThemeToggle,ThemeSettings),允许用户切换预设主题(如深色/浅色)或自定义主题参数。修改会通过 CSS 变量实时生效:document.documentElement.style.setProperty('--color-primary', newColor);
-
集成:通过
import StyleEditor from '@/components/StyleEditor'嵌入到设置页面或特定的开发者调试区域。
-
布局: 侧边栏 + 主区;底部状态栏展示录音/识别/执行进度。
-
动效: 使用 Framer Motion:
- 页面过渡淡入淡出 (
opacity 0→1,y 10→0,duration 0.3s) - 按钮点击波纹(Ripple)效果
- 页面过渡淡入淡出 (
-
可调整参数: 动效时长与缓动可通过
theme.transitions进行全局配置。
- 保持所有样式通过变量驱动,避免硬编码。
- 在 Storybook 中建立"Theme Switcher"体验,确保每个组件响应变量改变。
- 组件库(shadcn/ui、AntD)均能通过上述变量层面实现不改源码的主题定制。
#!/usr/bin/env bash
set -e
FEATURE_BRANCH=$1
SPEC_FILE=$2
if [ -z "$FEATURE_BRANCH" ] || [ -z "$SPEC_FILE" ]; then
echo "Usage: ./auto-dev.sh <feature/xxx> <path/to/spec.md>"
exit 1
fi
git checkout -b "$FEATURE_BRANCH"
echo "🔧 AI 生成首版代码…"
cursor complete --prompt "$(cat $SPEC_FILE)" > /dev/null
while true; do
echo "🧪 本地运行测试…"
npm ci
npm run test:ci
FAILS=$(jq '.stats.failures' reports/test-results.json)
if [ "$FAILS" -eq "0" ]; then
echo "✅ 测试全通过!"
break
fi
echo "❌ 测试失败 ($FAILS), AI 修复补丁…"
cursor complete \
--prompt "请根据测试结果 JSON,生成可打补丁修复方案:" \
--file reports/test-results.json \
--output cursor-fix.patch
git apply cursor-fix.patch
done
echo "🎉 功能完成,请审查并提交远程分支。"package.json
{
"scripts": {
"test:ci": "cypress run"
},
"devDependencies": {
"cypress": "^12.0.0",
"jq": "^1.6",
"cypress-mochawesome-reporter": "^3.0.0"
}
}安装额外的测试依赖 (如果尚未安装):
# (在 frontend 目录下)
npm install --save-dev cypress-mochawesome-reporter jq cypress-axe axe-corecypress.config.js (已集成HTML报告器)
const { defineConfig } = require('cypress')
module.exports = defineConfig({
reporter: 'cypress-mochawesome-reporter',
reporterOptions: {
charts: true,
reportPageTitle: 'Echo Project E2E Test Report',
embeddedScreenshots: true,
inlineAssets: true,
saveAllAttempts: false,
},
e2e: {
baseUrl: 'http://localhost:3000',
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
on('task', {
log(message) {
console.log(message)
return null
},
table(message) {
console.table(message)
return null
},
})
},
},
})测试报告:
当通过 npm run test:ci 或 cypress run 执行测试后,详细的HTML测试报告会自动生成在 cypress/reports/html/index.html。
无障碍测试 (Accessibility Testing) with cypress-axe:
为了确保应用的无障碍性,我们在E2E测试中集成了 cypress-axe。
- 确保已导入
cypress-axe在frontend/cypress/support/e2e.js文件中:// frontend/cypress/support/e2e.js import './commands' import 'cypress-axe' // 确保这行已取消注释
- 在你的测试用例中,通常在页面加载或重要UI交互后,注入并运行检查:
// 示例: my_test.cy.js cy.visit('/some-page'); cy.injectAxe(); cy.checkA11y(); // 检查整个页面 // cy.checkA11y('.specific-component', { /* options */ }); // 或检查特定组件
### 5.3 AI 调用模板
```bash
cursor complete --prompt "基于 ADM + React,按第7章内容生成登录组件。"
cursor complete --prompt "基于第7章内容生成 Cypress E2E 脚本。"
cursor complete --prompt "以下是测试结果 JSON,请生成修复补丁:" --file reports/test-results.json --output cursor-fix.patch
// src/mocks/handlers.js
import {rest} from 'msw'; export const handlers=[rest.post('/api/login',(req,res,ctx)=>{const{password}=req.body;return password==='correct'?res(ctx.status(200),ctx.json({token:'abc'})):res(ctx.status(401),ctx.json({message:'密码不正确'}));}),rest.get('/api/services',(req,res,ctx)=>res(ctx.status(200),ctx.json([{id:'translate',name:'文本翻译',description:'中英互译',icon:'/icons/translate.svg'}]))];
// src/mocks/browser.js
import{setupWorker}from'msw';import{handlers}from'./handlers';export const worker=setupWorker(...handlers);
// src/index.js
if(process.env.NODE_ENV==='development'){import('./mocks/browser').then(({worker})=>worker.start());}export function ServiceDirectory(){const[services,setServices]=useState([]);useEffect(()=>fetch('/api/services').then(r=>r.json()).then(setServices),[]);return (<div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(140px,1fr))',gap:'16px'}}>{services.map(svc=>(<Card key={svc.id}><img src={svc.icon}/><h4>{svc.name}</h4><p>{svc.description}</p><Button>调用</Button></Card>))}</div>);} - 流程:
auto-dev.sh自动化执行 AI 生成 →npm run test:ci→ 解析reports/test-results.json→ AI 修复 → 直至测试通过 - 无需手动触发测试或查看日志,全部由脚本与工具完成。
npm version patch
git add package.json
git commit -m "chore: bump version"
git push origin HEAD --follow-tags- 功能: 通过表单创建、管理 Dify/Coze API 集成
- 访问控制: 仅对具有 "developer" 或 "admin" 角色的用户可见
- 创建流程:
- 开发者登录后进入控制台,点击"创建 API 集成"
- 选择平台类型(Dify 或 Coze)
- 填写表单:
- Dify:集成名称、描述、API Key (app-*),响应模式自动设为 blocking
- Coze:集成名称、描述、API Key (pat-*)、Bot ID
- 点击"创建并测试连接"
- 后端自动执行:
- 格式验证(API Key 格式、HTTPS 检查)
- 连通性测试(发送测试消息到 Dify/Coze)
- 自动生成 tool_id 和 request_schema
- Dify 自动强制使用 blocking 模式(SSE 流式暂未支持)
- 测试通过 → 创建成功,立即可用
- 测试失败 → 显示详细错误(如"API Key 无效"、"Bot ID 不存在")
- 管理功能:
- 列表查看:显示所有已创建的 API 集成
- 启用/禁用:控制集成在服务目录中的可见性
- 删除:移除不再需要的集成
- UI 要点:
- 表单动态切换(根据平台显示不同字段)
- 实时验证(前端格式校验 + 后端连通性测试)
- 详细错误反馈(连接失败时显示具体原因)
- 创建成功后自动刷新列表
-
使用 React Context + useReducer 管理核心状态:
- SessionContext: { sessionId, stage }
- UserConfigContext: { contacts, wallets }
- ThemeContext: { theme, setTheme }
- AuthContext: { user, token, role }
-
关键 Hooks:
useSession(): 对话流程与阶段切换useVoice(): 封装 Web Speech API 录音与 TTSuseIntent(): 意图分类与分发useApi(): apiClient 封装与错误处理
-
用户角色:
user: 普通用户,访问基本功能developer: 开发者用户,可访问开发者控制台,上传和管理自定义APIadmin: 管理员用户,拥有所有权限
-
权限控制实现:
- 基于
AuthContext中存储的用户角色信息 - 使用增强的
ProtectedRoute组件,支持requireRole参数 - 根据用户角色动态生成导航菜单项
- 后端通过JWT中携带的角色信息验证API访问权限
- 基于
-
界面差异:
- 普通用户: 不显示"开发者"导航项,无法访问开发者控制台
- 开发者用户: 显示"开发者"导航项,可访问开发者控制台管理自己的API
- 管理员用户: 拥有所有界面访问权限
以下集中列出各模块的 Gherkin 场景与测试要点,复制即可用作 auto-dev.sh 的 Spec 输入。
Feature: 登录组件
Scenario: 正常登录
Given 登录页已打开
When 输入用户名 "alice" 和密码 "correct"
And 点击 "登录" 按钮
Then 页面应跳转到首页
Scenario: 密码错误
Given 登录页已打开
When 输入用户名 "alice" 和密码 "wrong"
And 点击 "登录" 按钮
Then 页面应显示红色提示 "密码不正确"测试要点: 单元(Jest+RTL)、E2E(Cypress)、Mock(MSW)
Feature: 注册组件
Scenario: 成功注册
Given 注册页已打开
When 输入邮箱 "test@example.com"、用户名 "bob" 和密码 "123456"
And 点击 "注册" 按钮
Then 页面应显示绿色提示 "注册成功"
Scenario: 邮箱格式错误
Given 注册页已打开
When 输入邮箱 "invalid-email"
And 点击 "注册" 按钮
Then 页面应显示红色提示 "请输入有效邮箱"测试要点: 表单校验、E2E 脚本、Mock
Feature: 首页列表
Scenario: 列表加载
Given 首页已打开
When 后端返回 5 条条目
Then 页面应渲染 5 个列表项
Scenario: 下拉刷新
Given 列表已渲染
When 用户下拉页面
Then 发送新请求并刷新列表测试要点: 组件渲染、下拉操作、Mock 响应
Feature: 语音录制控件
Scenario: 点击录音
Given 页面加载完毕
When 点击 "录音" 按钮
Then 按钮文本变为 "停止" 且开始捕获音频流
Scenario: 录音超时
Given 录音进行 60 秒
Then 页面弹出 "录音超时" 并自动停止测试要点: 模拟 Timer、fake-audio、超时逻辑
Feature: 语音识别结果展示
Scenario: STT 成功
Given 录音上传完成
When 后端返回文本 "你好"
Then 页面应显示 "你好" 并触发执行流程测试要点: Hook 模拟、E2E 断言结果
Feature: 服务目录
Scenario: 服务列表加载
Given 服务页已打开
When 后端返回 3 个服务
Then 页面应展示 3 个卡片
Scenario: 搜索过滤
Given 在搜索框输入关键字
When 匹配服务列表
Then 只显示匹配卡片测试要点: 列表渲染、搜索输入、Mock 响应
Feature: 进度条组件
Scenario: 阶段渲染
Given 状态为 "理解中"
Then 进度条填充至 50% 并高亮文本测试要点: Props 驱动渲染、样式断言
Feature: 全局提示
Scenario: 显示错误信息
Given 调用 showError("错误消息")
Then 页面顶部出现红色 Toast 文本 "错误消息"测试要点: 调用函数、断言组件显示
Feature: 全局布局 & 404 (包括Header, Footer)
Scenario: 访问首页应包含页眉和页脚
Given 用户访问首页
Then 页面应正确渲染 Header 组件
And 页面应正确渲染 Footer 组件
Scenario: 未知路由
Given 访问 `/unknown`
Then 展示 404 页面测试要点: 路由断言、404 文案、Header/Footer 组件渲染、已集成 jest-axe 进行无障碍测试 (Footer)。
Feature: 错误边界
Scenario: 组件抛错
Given 子组件抛出异常
Then ErrorBoundary 捕获并展示友好提示测试要点: 手动抛错、断言异常 UI
Feature: Mock 服务
Scenario: 返回模拟登录成功
Given 开发环境已开启 Mock
When 访问 "/api/login" 并传入正确密码
Then MSW 应返回 {"token":"abc"}
Scenario: 关闭 Mock 回退真实后端
Given 开发环境已关闭 Mock
When 访问 "/api/login"
Then 请求应发送到真实后端服务测试要点: 验证 handlers.js 中的 Mock 逻辑,E2E 场景断言接口返回及环境切换
Feature: 第三方开发者控制台 - Dify API 集成创建
Scenario: 成功创建 Dify API 集成
Given 已以开发者身份登录控制台
And 选择平台类型为 "Dify"
When 填写集成名称 "客服助手"
And 填写 API Key "app-validkey123"
And 点击 "创建并测试连接" 按钮
Then 页面应显示 "正在测试连接..."
And 后端应自动将响应模式设为 blocking(强制)
And 后端应发送测试消息到 Dify API
And 页面应显示 "创建成功"
And 集成列表中应出现 "客服助手"
Scenario: API Key 格式错误
Given 已以开发者身份登录控制台
When 填写 API Key "wrong-key"(不以 app- 开头)
And 点击创建按钮
Then 页面应立即显示错误 "Dify API Key 必须以 'app-' 开头"
And 不应发送测试请求
Scenario: 连通性测试失败
Given 填写了格式正确但无效的 API Key "app-invalidkey"
When 点击创建按钮
Then 后端应尝试连接 Dify API
And 页面应显示详细错误 "连通性测试失败 (dify):API Key 无效或已过期,请检查后重新提交"
And API 集成不应被创建
Feature: 第三方开发者控制台 - Coze API 集成创建
Scenario: 成功创建 Coze API 集成
Given 选择平台类型为 "Coze"
When 填写 API Key "pat_validkey"
And 填写 Bot ID "7234567890"
And 点击创建按钮
Then 应成功创建 API 集成
Scenario: Bot ID 不存在
Given 填写了正确的 API Key 但错误的 Bot ID
When 点击创建按钮
Then 页面应显示 "连通性测试失败 (coze):Bot ID 不存在,请确认 Bot ID 是否正确"
Feature: 第三方开发者控制台 - 管理功能
Scenario: 启用/禁用 API 集成
Given 控制台列表中有 API 集成 "客服助手"(状态为启用)
When 点击 "禁用" 按钮
Then 集成状态应变为 "已禁用"
And 该集成在服务目录中应不可见
Scenario: 删除 API 集成
Given 控制台列表中有 API 集成 "客服助手"
When 点击 "删除" 按钮
And 确认删除操作
Then API 集成应从列表中移除测试要点:
- 表单提交与验证(格式校验 + 连通性测试)
- 错误处理(网络错误、API 错误、超时)
- 列表渲染、状态切换、删除操作
- Mock 与真实后端联调
DeveloperConsolePage组件单元测试(Jest+RTL)
Feature: 主题切换与设置
Scenario: 切换主题模式
Given 用户在设置页面
When 点击主题切换按钮 (ThemeToggle)
Then 应用的主题(如背景色、文字颜色)应在深色/浅色模式间切换
And 主题选择应被持久化存储
Scenario: 调整自定义主题参数
Given 用户在主题设置组件 (ThemeSettings)
When 修改主色调或圆角大小
Then 应用界面的对应样式应实时更新
Scenario: 无障碍访问检查
Given ThemeToggle, ThemeSettings, SettingsPage 组件已渲染
Then 组件应通过 jest-axe 无障碍规范检查测试要点: UI交互、样式变更断言、localStorage持久化验证、已集成 jest-axe 进行无障碍测试。
文档完