Skip to content

Commit e028a23

Browse files
chore(test): switch browser workflow to Playwright CLI and Test
1 parent 30fca74 commit e028a23

14 files changed

Lines changed: 388 additions & 6 deletions

File tree

‎.codex/README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
## 配置与启用
77

88
[Codex 官方 MCP 文档](https://developers.openai.com/codex/mcp)支持受信任项目使用 `.codex/config.toml`。
9-
本仓库三个服务配置为 `enabled = true`。首次使用前需完成本地配置;暂不使用的服务应设为 `enabled = false`,避免缺少配置时启动失败。
9+
TAPD、DBHub 保持启用;Playwright MCP 默认禁用。浏览器复现使用 Playwright CLI,回归使用 Playwright Test,配置和命令见 [`tests/browser/README.md`](../tests/browser/README.md)。首次使用前需完成本地配置;暂不使用的服务应设为 `enabled = false`,避免缺少配置时启动失败。
1010

1111
1. 在本机安装需要的 MCP 服务,记录其入口文件位置;启动器不会自动安装依赖。
1212
2. 将相应目录的 `.env.example` 复制为同目录 `.env.local`,填写自己的入口、解释器和项目配置。
@@ -21,7 +21,7 @@
2121
## 服务约定
2222

2323
- **TAPD**:填写 SQLBot 对应的 `TAPD_WORKSPACE_ID`、个人用户名、令牌和入口。配置保留参考项目的 Node/Python 两种实现的读取工具白名单,不开放写入工具。Python `mcp-server-tapd` 调用仍须显式传本项目 `workspace_id`;启动器不会自动注入每次调用。不要使用会另行加载其他个人凭据的包装入口。
24-
- **Playwright**:使用支持 Chrome、`--user-data-dir` 和 `--output-dir` 参数的 `@playwright/mcp` 入口,并准备本机 Chrome。浏览器资料位于 `playwright_mcp/browser-profile/`,截图等产物位于 `playwright_mcp/output/`。`TEST_BASE_URL` 是本机示例,需按实际测试环境调整;`TEST_*` 仅供执行测试时按需使用,启动器不会自动登录。
24+
- **Playwright MCP(历史兼容,默认禁用)**:使用支持 Chrome、`--user-data-dir` 和 `--output-dir` 参数的 `@playwright/mcp` 入口,并准备本机 Chrome。浏览器资料位于 `playwright_mcp/browser-profile/`,截图等产物位于 `playwright_mcp/output/`。`TEST_BASE_URL` 是本机示例,需按实际测试环境调整;`TEST_*` 仅供执行测试时按需使用,启动器不会自动登录。
2525
- **DBHub**:沿用参考项目针对 `@bytebase/dbhub@1.3.1` 的配置格式,入口须支持 `--config`。示例 DSN 已改为 PostgreSQL/sqlbot,仅用于展示格式。DSN 通过环境变量传递,`dbhub.toml` 为 `execute_sql` 设置 `readonly = true` 和最多 1000 行;数据库账号本身也必须只读。只在任务授权的测试环境使用,不用生产或共享业务库做配置验证。
2626

2727
## 运行时
@@ -43,3 +43,7 @@ python3 -B backend/tests/test_codex_mcp_runtime.py
4343

4444
离线测试覆盖配置校验、解释器选择和启动参数/环境变量传递,不连接外部服务。
4545
配置解析或离线测试通过不代表真实 MCP 握手、工具调用或数据库只读权限已经验证。
46+
47+
## 浏览器测试迁移
48+
49+
新任务不使用 Playwright MCP,也不在 CLI/Test 失败时自动回退。旧启动器和本地配置保留用于兼容;新工具不会读取旧凭据或复用旧浏览器资料。使用 `PLAYWRIGHT_BASE_URL` 显式指定 SQLBot 测试地址,登录状态保存到 `tests/browser/.auth/`。已有会话可能仍显示已加载的 MCP 工具;新建会话后按禁用配置加载。

‎.codex/config.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ enabled_tools = ["tapd_get_current_user", "tapd_parse_url", "tapd_get_story", "t
1010
[mcp_servers.playwright]
1111
command = "python3"
1212
args = [".codex/playwright_mcp/launch.py"]
13-
enabled = true
13+
enabled = false
1414
startup_timeout_sec = 30
1515
tool_timeout_sec = 120
1616

‎AGENTS.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ SQLBot 让业务用户用自然语言提问,基于已配置的数据源生成
1717

1818
| 路径 | 职责 |
1919
| --- | --- |
20-
| `backend/` | Python 3.11 / FastAPI / SQLModel 后端。`main.py` 组装应用、MCP、中间件、静态资源和 xpack;业务域在 `apps/`,共享代码在 `common/`,迁移在 `alembic/versions/`,全部测试(含仓库守卫)在 `tests/`。 |
20+
| `backend/` | Python 3.11 / FastAPI / SQLModel 后端。`main.py` 组装应用、MCP、中间件、静态资源和 xpack;业务域在 `apps/`,共享代码在 `common/`,迁移在 `alembic/versions/`,后端测试(含仓库守卫)在 `tests/`。 |
2121
| `frontend/` | Vue 3、TypeScript strict、Vite、Pinia、Vue Router 和 Element Plus。请求在 `src/api/`,共享实体在 `src/entity/`,状态在 `src/stores/`,路由在 `src/router/`,UI 在 `src/views/` 和 `src/components/`。 |
2222
| `g2-ssr/` | Node.js 图表渲染服务,使用 `@antv/g2-ssr`;图表实现位于 `charts/`,目录内有独立 `AGENTS.md`。 |
23+
| `tests/browser/` | 独立 Playwright CLI 复现与 Playwright Test 浏览器回归,使用方式见目录内 `README.md`。 |
2324
| `installer/` | 离线安装、卸载、配置模板和服务控制脚本。 |
2425
| `.codex/` | Codex 开发用 MCP 配置、启动器与本地配置模板;使用方式见 `.codex/README.md`,不属于 SQLBot 产品 MCP。 |
2526
| `Dockerfile*`、`docker-compose.yaml`、`start.sh` | 容器组装和运行时进程启动。 |
@@ -59,6 +60,7 @@ SQLBot 让业务用户用自然语言提问,基于已配置的数据源生成
5960
- 不要为了通过测试削弱安全守卫;安全、权限、SQL、Host、路径和嵌入认证改动必须有相关回归验证。
6061
- 修改 Docker、installer 或路径配置时,核对前端构建产物、后端工作目录、`/opt/sqlbot` 数据目录、图表输出和日志挂载仍然一致。
6162
- 依赖、lockfile 和版本号只在任务明确需要时更新;不要顺手刷新。
63+
- 浏览器问题使用 `tests/browser` 下的 Playwright CLI 复现、Playwright Test 回归,不使用 Playwright MCP;优先局部输出,失败时按需读取截图和 trace。
6264
- 按验收条件选择验证层级,不把构建或单元测试等同于产品验收。普通任务不默认构建镜像或启动完整运行栈;已要求真实接口、浏览器或部署验证时,可启动必要的隔离服务。环境范围、外部成本或数据用途不明确时先确认。
6365
- 除非用户明确要求,不要上传、发布或推送镜像 / wheel / 包。
6466
- 变更涉及本文件或 `docs/agents/` 描述的约定(目录职责、命令、流程)时,同步更新对应文档。

‎docs/agents/testing.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## 测试布局
44

5-
当前入库的自动化测试集中在 `backend/tests/`。以下命令从仓库根进入 `backend/` 后运行;其余文档中的命令也应按注明的工作目录执行:
5+
后端单元与仓库守卫测试位于 `backend/tests/`,浏览器复现和回归工具位于 `tests/browser/`。以下命令从仓库根进入 `backend/` 后运行;其余文档中的命令也应按注明的工作目录执行:
66

77
```bash
88
cd backend
@@ -62,7 +62,9 @@ npm run build
6262
- 类型、模板和打包验证由 `vue-tsc -b` 与 Vite 完成。
6363
- 修改少量文件时可用 `npx eslint <changed-file...> --fix`。
6464
- 不要默认运行全量自动修复脚本。
65-
- 当前不要自行引入 Vitest/Jest/Playwright 等新测试框架;若需要,先提出框架、运行成本和 CI 影响。
65+
- 浏览器复现使用 Playwright CLI,回归使用 Playwright Test,不使用 Playwright MCP。工具依赖独立于前端,固定版本及 lockfile 位于 `tests/browser/`;本次配置不增加 CI 作业。其他新测试框架仍需先说明运行成本和 CI 影响。
66+
- 安装:`npm --prefix tests/browser ci`;工具自检:`npm --prefix tests/browser run test:smoke`。业务冒烟需显式设置 `PLAYWRIGHT_BASE_URL`,不自动启动产品或执行迁移。完整命令见 [`tests/browser/README.md`](../../tests/browser/README.md)。
67+
- 每个缺陷使用独立 CLI 会话,优先 `find`、局部快照或合并 `run-code`,只读取必要输出。业务回归需增加明确的项目/testMatch,保留修复前失败、修复后通过的证据;工具自检不等同业务验收。
6668

6769
## 图表渲染服务
6870

‎tests/browser/.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
output/
3+
.playwright-cli/
4+
.auth/
5+
.env*
6+
!package-lock.json
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"browser": {
3+
"browserName": "chromium",
4+
"isolated": true,
5+
"launchOptions": {
6+
"channel": "chrome",
7+
"headless": true
8+
},
9+
"contextOptions": {
10+
"viewport": { "width": 1440, "height": 900 }
11+
}
12+
},
13+
"outputDir": "output/cli",
14+
"outputMode": "file",
15+
"console": { "level": "error" }
16+
}

‎tests/browser/README.md‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Playwright 浏览器复现与回归
2+
3+
工具独立于 `frontend`,不改变前端业务依赖或构建。CLI 用于探索和复现,Playwright Test 用于保存可重复执行的回归。两个工具均为 Apache-2.0 许可,具体版本固定在本目录的 `package.json` 和 `package-lock.json`。
4+
5+
## 安装与自检
6+
7+
需要 Node.js 20+、npm 和本机 Google Chrome。所有命令从仓库根目录执行:
8+
9+
```sh
10+
npm --prefix tests/browser ci
11+
npm --prefix tests/browser run test:smoke
12+
```
13+
14+
自检自动启动仅监听 `127.0.0.1:4198` 的静态页面,验证浏览器启动、页面加载、输入、点击和断言,结束后关闭页面服务。它不连接业务后端,也不代表 SQLBot 功能回归通过。端口冲突时可设置 `PLAYWRIGHT_DEMO_PORT`。
15+
16+
默认复用本机 Chrome,不自动下载浏览器。Test 可通过 `PLAYWRIGHT_CHANNEL=msedge` 改用已安装的 Edge。若 CI 使用 Playwright Chromium,先在本目录执行 `npm exec -- playwright install chromium`,再设置 `PLAYWRIGHT_CHANNEL=chromium`。CLI 的浏览器选择独立配置,默认 Chrome,可在 `open` 时指定 `--browser=msedge`。
17+
18+
## 使用 CLI 复现
19+
20+
确保目标开发或测试服务已就绪。本工具不启动 SQLBot 后端或执行数据库迁移。
21+
22+
```sh
23+
npm --prefix tests/browser run cli -- -s=tapd-1077724 open http://127.0.0.1:5173
24+
npm --prefix tests/browser run cli -- -s=tapd-1077724 find 登录
25+
npm --prefix tests/browser run cli -- -s=tapd-1077724 snapshot
26+
# 从快照取得目标 ref 后执行 click/fill,或使用稳定的 role/CSS 定位器。
27+
npm --prefix tests/browser run cli -- -s=tapd-1077724 console error
28+
npm --prefix tests/browser run cli -- -s=tapd-1077724 close
29+
```
30+
31+
每条缺陷使用不同的 `-s=` 会话名,所有命令带上同一会话名。`open` 默认无头;需要可视操作时加 `--headed`。CLI 使用独立、非持久化浏览器上下文,不使用个人 Chrome 用户资料。
32+
33+
配置位于 `.playwright/cli.config.json`。快照及控制台等输出写入 `output/cli/`,终端显示文件路径;优先 `find` 或局部 `snapshot`,只读取相关片段。已知操作可合并为一条 `run-code`,只返回必要结果。按需截图,避免每个动作后全页截图;不要把完整快照反复读回上下文。
34+
35+
CLI 自检可使用静态演示页。在一个终端启动:
36+
37+
```sh
38+
npm --prefix tests/browser run demo
39+
```
40+
41+
另一个终端执行:
42+
43+
```sh
44+
npm --prefix tests/browser run cli -- -s=tooling open http://127.0.0.1:4198
45+
npm --prefix tests/browser run cli -- -s=tooling run-code 'async page => { await page.getByLabel("测试内容").fill("CLI 已就绪"); await page.getByRole("button", { name: "显示内容" }).click(); return await page.getByLabel("显示结果").textContent(); }'
46+
npm --prefix tests/browser run cli -- -s=tooling close
47+
```
48+
49+
完成后在演示页终端按 Ctrl-C 停止服务。不要使用 `close-all` 或 `kill-all` 影响其他任务的浏览器。
50+
51+
## 使用 Test 回归
52+
53+
```sh
54+
# 工具自检 + 可选应用冒烟;未设置应用 URL 时明确跳过应用用例。
55+
npm --prefix tests/browser test
56+
57+
# 仅访问已经启动的指定环境,不会自动启动完整产品。
58+
PLAYWRIGHT_BASE_URL=http://127.0.0.1:5173 npm --prefix tests/browser run test:app
59+
60+
# 定向运行、调试及查看报告。
61+
npm --prefix tests/browser test -- --project=tooling
62+
npm --prefix tests/browser run test:smoke -- --headed
63+
npm --prefix tests/browser run report
64+
```
65+
66+
应用冒烟只验证 HTTP 导航、`#app` 挂载及挂载期间未捕获的页面脚本异常,不验证登录成功或任何业务流程。`PLAYWRIGHT_APP_PATH` 可指定入口路径,例如 `/#/login`。
67+
68+
`playwright.config.mjs` 使用单 worker,默认不重试,CI 重试一次。终端使用 dot 简短报告,HTML 报告保存在 `output/report/` 且不会自动打开。成功用例不保留截图、trace;失败时保留截图及 trace 到 `output/test-results/`,默认不录视频。失败后先查看断言和错误摘要,需要时再查看对应截图、trace。
69+
70+
新增业务回归时,将用例放在 `specs/`,并在配置中为实际项目增加明确的 `testMatch`;不要让应用用例误入工具自检项目。可按缺陷号建立文件,如 `tapd-1077724.spec.mjs`。优先 `getByRole/getByLabel` 等稳定定位,确有必要才给业务组件补 `data-testid`。回归必须包含能在修复前失败、修复后通过的行为断言;纯后端问题优先 Python 定向测试。
71+
72+
## 登录状态和输出
73+
74+
确需复用登录状态时,使用测试账号手动登录并保存到被忽略的 `.auth/`:
75+
76+
```sh
77+
mkdir -p tests/browser/.auth
78+
umask 077
79+
npm --prefix tests/browser run cli -- -s=login open http://127.0.0.1:5173 --headed
80+
# 在独立浏览器中完成登录后保存;路径相对 tests/browser。
81+
npm --prefix tests/browser run cli -- -s=login state-save .auth/local.json
82+
npm --prefix tests/browser run cli -- -s=login close
83+
PLAYWRIGHT_BASE_URL=http://127.0.0.1:5173 PLAYWRIGHT_STORAGE_STATE=.auth/local.json npm --prefix tests/browser run test:app
84+
```
85+
86+
`.auth/`、`output/`、CLI 临时输出、`.env*` 和 `node_modules/` 均被本目录 `.gitignore` 排除;`package-lock.json` 单独纳入版本管理。登录状态、快照、请求详情、截图和 trace 可能包含凭据或业务数据,不提交这些产物,也不要直接把原始内容贴到 TAPD 或公开报告。
87+
88+
## 参考
89+
90+
- [Playwright CLI](https://playwright.dev/docs/getting-started-cli)
91+
- [Playwright Test 配置](https://playwright.dev/docs/test-configuration)
92+
- [命令行运行测试](https://playwright.dev/docs/test-cli)

‎tests/browser/fixtures/index.html‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!doctype html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<link rel="icon" href="data:,">
7+
<title>浏览器测试工具自检</title>
8+
<style>
9+
body { max-width: 640px; margin: 48px auto; font-family: sans-serif; }
10+
input, button { padding: 8px; margin: 8px 0; }
11+
output { display: block; white-space: pre-wrap; }
12+
</style>
13+
</head>
14+
<body>
15+
<h1>浏览器测试工具自检</h1>
16+
<p>此页面仅验证 CLI 和 Test 工具,不连接 SQLBot 后端。</p>
17+
<form>
18+
<label for="message">测试内容</label>
19+
<input id="message" required autocomplete="off">
20+
<button type="submit">显示内容</button>
21+
<output aria-label="显示结果" aria-live="polite"></output>
22+
</form>
23+
<script>
24+
document.querySelector('form').addEventListener('submit', event => {
25+
event.preventDefault()
26+
document.querySelector('output').textContent = document.querySelector('input').value
27+
})
28+
</script>
29+
</body>
30+
</html>

‎tests/browser/fixtures/server.mjs‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { createServer } from 'node:http'
2+
import { readFile } from 'node:fs/promises'
3+
4+
const port = Number(process.env.PLAYWRIGHT_DEMO_PORT || '4198')
5+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
6+
throw new Error('PLAYWRIGHT_DEMO_PORT must be between 1 and 65535')
7+
}
8+
const html = await readFile(new URL('./index.html', import.meta.url))
9+
const server = createServer((req, res) => {
10+
if (req.url === '/healthz') {
11+
res.writeHead(200, { 'Content-Type': 'text/plain' })
12+
res.end('ok')
13+
} else if (req.url === '/' || req.url === '/index.html') {
14+
res.writeHead(200, {
15+
'Content-Type': 'text/html; charset=utf-8',
16+
'Cache-Control': 'no-store'
17+
})
18+
res.end(html)
19+
} else {
20+
res.writeHead(404)
21+
res.end()
22+
}
23+
})
24+
server.listen(port, '127.0.0.1', () => {
25+
console.log(`Browser tooling fixture: http://127.0.0.1:${port}`)
26+
})
27+
for (const signal of ['SIGINT', 'SIGTERM']) {
28+
process.on(signal, () => server.close())
29+
}

‎tests/browser/package-lock.json‎

Lines changed: 105 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)