150 lines
3.8 KiB
Markdown

---
name: uncaged-test
version: 3.1.0
description: >
Uncaged Web UI 场景化测试。场景文件在 uncaged 代码库的 tests/e2e/scenes/,
subagent 按场景描述自主操作验证。失败时收集 logs 并开 bug issue。
metadata:
requiredTools: ["secret"]
---
# Uncaged Test
场景化 E2E 测试,设计给 subagent 自主执行。
**场景文件在代码库:** `<uncaged-repo>/tests/e2e/scenes/`
**回归脚本在代码库:** `<uncaged-repo>/tests/e2e/scripts/run-tests.sh`
## 使用方式
### 验证单个场景
```
读 <uncaged-repo>/tests/e2e/scenes/<场景>.md,按描述验证。失败了收集 logs 开 bug。
```
### 跑全部场景(快速回归)
```bash
bash <uncaged-repo>/tests/e2e/scripts/run-tests.sh [TOKEN_NAME]
```
### 可用场景
| 场景文件 | 说明 |
|:---------|:-----|
| `scenes/auth.md` | 认证:token 登录、session、refresh |
| `scenes/chat.md` | 聊天:发消息、历史、清空 |
| `scenes/streaming.md` | SSE 流式响应 |
| `scenes/tool-gateway.md` | Tool Gateway:builtin 列表、invoke |
| `scenes/tool-search.md` | 输入框工具搜索(本地过滤) |
| `scenes/error-handling.md` | 异常处理:401、404、429 |
## 环境准备
### 登录获取 cookies
```bash
TOKEN=$(secret get UNCAGED_AGENT_TOKEN_XINGYUE)
curl -s -X POST "https://uncaged.shazhou.work/auth/token" \
-H "Content-Type: application/json" \
-d "{\"token\": \"$TOKEN\"}" \
-c /tmp/uncaged-cookies.txt
```
### 常量
```
BASE_URL = https://uncaged.shazhou.work
AGENT_PATH = /scott/doudou
COOKIES = /tmp/uncaged-cookies.txt
REPO = oc-xiaoju/uncaged
```
## 失败处理
### 1. 收集 Worker 日志
```bash
CF_TOKEN=$(secret get CLOUDFLARE_API_TOKEN)
CF_ACCOUNT=$(secret get CLOUDFLARE_ACCOUNT_ID)
cd <uncaged-repo>/packages/worker
CLOUDFLARE_API_TOKEN="$CF_TOKEN" CLOUDFLARE_ACCOUNT_ID="$CF_ACCOUNT" \
npx wrangler tail --format json > /tmp/worker-logs.json 2>/dev/null &
sleep 3
# 复现失败请求
# ...
sleep 10; kill %1 2>/dev/null
python3 -c "
import sys, json
for line in open('/tmp/worker-logs.json'):
try:
e = json.loads(line.strip())
logs, excs = e.get('logs',[]), e.get('exceptions',[])
status = e.get('event',{}).get('response',{}).get('status','?')
if logs or excs or (isinstance(status,int) and status >= 400):
url = e.get('event',{}).get('request',{}).get('url','?')
print(f'[{status}] {url}')
for l in logs: print(f' LOG: {l.get(\"message\",l)}')
for x in excs: print(f' ERR: {x.get(\"message\",x)}')
except: pass
"
```
### 2. 收集前端状态
```bash
curl -s https://uncaged.shazhou.work/auth/session -b /tmp/uncaged-cookies.txt | python3 -m json.tool
curl -s https://uncaged.shazhou.work/scott/doudou/api/history -b /tmp/uncaged-cookies.txt | python3 -c "
import sys,json
for m in json.load(sys.stdin).get('history',[])[-3:]:
print(f' [{m[\"role\"]}] {str(m.get(\"content\",\"\"))[:100]}')
"
```
### 3. 开 Bug Issue
```bash
gh issue create --repo oc-xiaoju/uncaged \
--title "bug: <简短描述>" \
--body "## Bug Report
### 场景
<场景文件 + 步骤>
### 期望
<应该发生什么>
### 实际
<实际发生了什么>
### 复现
\`\`\`bash
<curl 命令>
\`\`\`
### Worker 日志
\`\`\`
<日志>
\`\`\`
---
*Auto-generated by uncaged-test skill*" \
--label "bug"
```
## API 速查
| 端点 | 方法 | 说明 |
|:-----|:-----|:-----|
| `/auth/token` | POST | Token 登录 |
| `/auth/session` | GET | 检查 session |
| `/auth/refresh` | POST | 刷新 token |
| `/:o/:a/api/chat` | POST | 发消息(⚠️ 不是 /api/v1/chat) |
| `/:o/:a/api/chat/stream` | POST | SSE 流式 |
| `/:o/:a/api/history` | GET | 历史记录 |
| `/:o/:a/api/v1/tools/builtin` | GET | Builtin 工具列表 |
| `/:o/:a/api/v1/tools/:slug/invoke` | POST | 直接调用工具 |