teshi-engine
测试自动化执行引擎 — 录制 → 生成 → 执行 → 自愈,通过 NDJSON 协议统一通信。
> 当前阶段:v0.4.0 — NDJSON 协议全面集成 + TUI 自动生成 PageObject/StepDef
>
> | 里程碑 | 目标 | 状态 |
> |--------|------|------|
> | v0.1 | 骨架搭建 — 基础 NDJSON 协议 + Playwright 执行 | ✅ |
> | v0.2 | 录制闭环 — 统一 Action 模型 + 录制归一化 | ✅ |
> | v0.3 | 自愈系统 — 规则回退 + SmartLocator 增强 + BDD + TUI | ✅ |
> | v0.4 | NDJSON 全面集成 — TUI 内录制/回放走 NDJSON + 自动生成 PO/StepDef | ✅ |
> | v1.0 | 多技术栈 — 至少一个额外适配器(Appium / WinUI3) | 🚧 |
快速开始
# 1. 安装依赖
pip install -e .
# 2. 安装 Playwright 浏览器
playwright install chromium
# 3. 运行端到端验证(GitHub 主页场景)
cat scenarios/github_home.json | python -m engine run
你会看到 NDJSON 格式的 STEP_EXECUTED 和 SCENARIO_FINISHED 消息逐行输出到 stdout。
工作区(Workspace)
TUI 与录制数据相对于工作区根目录,而不是 engine 安装目录。首次启动会自动创建下列文件夹:
/
├── features/ # Gherkin .feature 文件
├── recordings/ # 录制会话
├── tests/page_objects/ # Gen 生成的 Page Object
├── tests/step_defs/ # Gen 生成的 step definitions
└── logs/ # TUI 日志
features/、recordings/、tests/page_objects/、tests/step_defs/ 已加入 .gitignore,请在各自工作区目录管理业务文件。
指定工作区
方式一:进入项目目录(推荐)
cd D:\Projects\my-automation
python -m engine tui
方式二:命令行参数
python -m engine tui --workspace D:\Projects\my-automation
python -m engine tui -w D:\Projects\my-automation
方式三:环境变量
# cmd
set TESHI_WORKSPACE=D:\Projects\my-automation
python -m engine tui
# PowerShell
$env:TESHI_WORKSPACE = "D:\Projects\my-automation"
python -m engine tui
优先级:--workspace / -w > TESHI_WORKSPACE > 当前工作目录。
-w 可写在子命令前或后,以下等价:
python -m engine tui -w D:\Projects\my-automation
python -m engine -w D:\Projects\my-automation tui
启动后日志面板会显示 Workspace: <路径>。record 模式同样支持 -w,录制写入该工作区的 recordings/。
CLI 用法
run — 标准 NDJSON 服务模式
从 stdin 读取 NDJSON 消息,处理后将结果写入 stdout。这是 teshi 启动引擎时的默认通信方式。
# 直接从 stdin 发送 RUN_SCENARIO
echo '{"type":"RUN_SCENARIO","scenario_id":"demo","steps":[{"id":"s1","action":"goto","url":"https://github.com"}]}' | python -m engine run
record — 录制模式
打开一个可视化的 Playwright 浏览器,记录你的操作并输出 NDJSON 到 stdout。
python -m engine record --url https://github.com
选项:
| 选项 | 默认 | 说明 |
|---|
--browser | chromium | 浏览器引擎 (chromium, firefox, webkit) |
--headed | 无头 | 显示浏览器窗口 |
--url | https://github.com | 起始页面 |
--channel | chrome | 系统浏览器通道 (chrome, msedge, chrome-beta 等) |
--run | false | 录制停止后立即回放 |
--screenshot | false | 每个操作后截图 |
-w, --workspace | 当前目录 | 工作区根目录(见上文) |
tui — 图形界面模式
启动 Textual TUI 界面,提供文件树浏览、Feature 编辑、录制控制、代码预览和实时执行反馈。
python -m engine tui
python -m engine tui -w D:\Projects\my-automation
界面布局:
┌─ Header ───────────────────────────────────────────────────┐
│ ┌─ Files ─┐ ┌─ Feature (Gherkin) ─┐ ┌─ Steps (code) ─────┐│
│ │📂 Scenarios│ │ Feature: GitHub │ │ Steps | PO | Defs ││
│ │📂 Features │ │ Scenario: ... │ │ [Record] [Stop] ││
│ │📂 Generated│ │ Given 打开... │ │ [Run] [Save] [Gen] ││
│ │ 📄 PO │ │ [editable] │ │ [Heals] [Trace] ││
│ │ 📄 Steps │ └──────────────────┘ │ ┌─ Code ──────────┐││
│ └────────────┘ ┌─ Steps Table ─────┐│ │ page.goto(...) │││
│ │ # │Action│Target│S││ │ page.click(...)│││
│ │ 1 │ click│ Sign │✓││ │ ... │││
│ │ 2 │ fill │ box │✗││ └────────────────┘││
│ └────────────────────┘└────────────────────┘│
├─ Log Panel ────────────────────────────────────────────────┤
├─ Status Bar Ready Steps: 7 ✓ 6 ✗ 1 File: — View: PO ─┤
└────────────────────────────────────────────────────────────┘
快捷键:
| 快捷键 | 功能 |
|---|
Ctrl+R | 开始录制 |
Ctrl+S | 停止录制 |
Ctrl+Enter | 回放录制的步骤 |
Ctrl+Shift+S | 保存场景 |
Ctrl+L | 清空日志 |
Ctrl+Q | 退出 |
F5 | 刷新文件树 |
录制:
- 点击 Record 或
Ctrl+R → 自动打开 Playwright 浏览器
- 浏览器操作实时捕获,左侧 Steps 表格实时新增行
- 智能定位器升级:
testid > role+aria-label > role+text > label > placeholder > text > css
- 所有录制的操作通过 NDJSON
RecordStep 消息传输
回放:
- 点击 Run 或
Ctrl+Enter → 通过 ExecutionEngine 执行,走 NDJSON 协议
- Steps 表格实时显示每步执行结果:
✓ 5422ms / ✗ timeout / ⟐ 320ms(自愈)
- 当前执行行自动高亮,状态栏实时更新通过/失败计数
ScenarioTrace 自动存入 TraceView,点击 Trace 可查看完整执行轨迹
- 自愈记录通过
HealDiff NDJSON 消息自动持久化到 HealStore
自动生成:
录制停止后自动完成以下流程(也可手动点击 Generate):
- 调用
PageObjectGenerator → 生成 Playwright PageObject 类
- 调用
StepDefGenerator → 生成 behave 中文步骤定义
- 自动写入
tests/page_objects/ 和 tests/step_defs/ 目录
- 持久化到 HealStore(
page_objects + mappings 表)
- 生成匹配的 Gherkin Feature 文本,自动填入左侧编辑框
- 代码区默认切换到 PageObject 视图,可通过 Steps / Page Object / Step Defs 标签切换
辅助视图:
| 按钮 | 功能 |
|---|
| Heals | 弹出自愈历史表格(策略、原始定位器、修复后的定位器、审批状态) |
| Trace | 弹出执行轨迹表格(每步状态、耗时、自愈标记、错误信息) |
| Generate | 手动触发 PageObject / StepDef 重新生成 |
功能特性
执行引擎
支持 10 种操作动作:
| 动作 | 说明 |
|---|
goto | 导航到指定 URL |
click | 点击元素 |
fill | 输入文本 |
wait_for | 等待元素可见 |
screenshot | 全页截图 |
assert_visible | 断言元素可见 |
assert_text | 断言元素文本内容 |
hover | 悬停元素 |
press | 按键操作 |
select | 选择下拉选项 |
关键能力:
- 步骤级重试 — 每个步骤可单独配置重试次数
- 步骤级超时 — 每个步骤可单独配置超时时间(默认 30s)
- 失败自动截图 — 步骤失败时自动截图并记录路径
录制系统
- JS 事件注入 — 捕获 click / change / keydown / popstate / framenavigated
- 智能归一化 — 原始事件转为运行器兼容的 step dict(自动生成 id、填充默认值)
- SmartLocator 增强 — 录制后批处理,将 CSS 选择器升级为更鲁棒的定位策略
- 优先级:
testid > role+aria-label > role+text > label > placeholder > text > css
自愈系统
运行时定位器自动修复,支持 5 类可愈错误:
| 错误类型 | 说明 |
|---|
strict mode | 定位器匹配到多个元素 |
timeout | 元素超时未出现 |
no element | 元素不存在 |
target closed | 目标页面已关闭 |
detached | 元素已从 DOM 分离 |
5 级回退链:原始定位器(.first()) → 属性探测定位置换 → CSS 兜底 → 模糊 text 匹配 → CSS(.first()) 兜底
自愈结果通过协议透传(self_healed 计数 + 原始错误信息)。
BDD 行为驱动
集成 behave 框架,支持中文自然语言步骤。
内置步骤(tests/features/steps/web_steps.py):
| 步骤模式 | 说明 |
|---|
Given 打开浏览器到 "{url}" | 导航到指定 URL |
When/Then 等待 "{spec}" 可见 | 等待元素可见 |
When/Then 点击 "{spec}" | 点击元素 |
When 输入 "{text}" 到 "{spec}" | 输入文本 |
Then "{spec}" 可见 | 断言元素可见 |
Then 按钮 "{name}" 可见 | 断言按钮可见 |
定位器支持智能解析:role:name、heading:text、button:name、testid:value、placeholder:text、label:text、CSS 选择器。
自动生成的步骤(通过 TUI 录制后产生在 tests/step_defs/):
TUI 录制完成后自动生成对应录制操作的 PageObject 和 behave 步骤定义,步骤模式与 StepDefGenerator 一致:
| 来源 | Gherkin 模式 |
|---|
goto → navigate() | Given 打开 "{page}" 页面 |
click → click_{key}() | When 点击 "{key}" |
fill → fill_{key}() | When 输入 "{text}" 到 "{key}" |
hover → hover_{key}() | When 悬停 "{key}" |
select → select_{key}() | When 选择 "{value}" 从 "{key}" |
press → press_{key}() | When 按下 "{key}" 键 |
NDJSON 协议 (v1)
所有通信均使用 Newline-Delimited JSON,每行一条完整 JSON 消息。
引擎支持两种 Transport:
NdjsonTransport — 基于 stdin/stdout,用于 CLI 模式(teshi-engine run)
QueueTransport — 基于 asyncio.Queue,用于 TUI 模式(teshi-engine tui),消息在进程内传递
两种 Transport 使用完全相同的 Pydantic 消息模型,保证 CLI 和 TUI 行为一致。
入站(teshi → engine)
| 类型 | 说明 |
|---|
RUN_SCENARIO | 启动一个测试场景 |
RECORD_START | 开始录制会话 |
RECORD_STOP | 停止录制 |
PING | 心跳探测 |
出站(engine → teshi)
| 类型 | 说明 |
|---|
STEP_EXECUTED | 单步执行结果(含状态、耗时、截图路径、自愈标记) |
SCENARIO_FINISHED | 场景最终结果(含汇总统计、自愈计数) |
SCENARIO_TRACE | 完整执行轨迹(每步的原始/愈合定位器、BDD 步骤映射) |
RECORD_START | 录制会话开始 |
RECORD_STEP | 录制的单个操作 |
RECORD_STOPPED | 录制结束(含所有操作) |
PONG | 心跳应答 |
ERROR | 错误信息 |
HEAL_DIFF | 自愈差异记录(策略、原始/修复定位器) |
PAGE_OBJECT_GENERATED | PageObject 生成事件 |
MAPPING_UPDATED | 步骤-定位器映射更新事件 |
项目结构
engine/
├── engine/ # Python 包
│ ├── cli.py # CLI 入口(run / record / tui / generate)
│ ├── protocol/
│ │ ├── messages.py # NDJSON 消息模型 (pydantic)
│ │ └── transport.py # NdjsonTransport + QueueTransport
│ ├── core/
│ │ ├── runner.py # TestRunner 抽象接口
│ │ ├── engine.py # 执行引擎(场景编排、重试、超时、NDJSON 输出)
│ │ ├── recorder.py # Recorder 抽象接口
│ │ ├── heal_store.py # SQLite 存储(自愈记录、PageObject、映射)
│ │ ├── mapper.py # StepMapper(步骤↔PageObject 映射)
│ │ └── trace.py # TraceCollector(执行轨迹收集)
│ ├── generators/
│ │ ├── page_object.py # PageObjectGenerator(PO 代码 + 映射生成)
│ │ └── step_defs.py # StepDefGenerator(behave 步骤定义生成)
│ ├── adapters/
│ │ └── playwright/
│ │ ├── runner.py # PlaywrightTestRunner(10 种动作执行)
│ │ ├── recorder.py # PlaywrightRecorder(JS 注入录制)
│ │ ├── enhancer.py # SmartLocatorEnhancer(定位器升级)
│ │ └── healer.py # SelfHealer(运行时自愈)
│ └── tui/
│ ├── app.py # TeshiApp — Textual TUI 界面
│ ├── heal_view.py # HealView — 自愈历史弹窗
│ └── trace_view.py # TraceView — 执行轨迹弹窗
├── scenarios/ # JSON 场景文件
│ └── github_home.json
├── tests/
│ ├── test_protocol.py # 消息模型序列化测试
│ ├── test_protocol_new.py # 扩展消息模型测试
│ ├── test_transport.py # NDJSON 收发单元测试
│ ├── test_recorder.py # 录制归一化测试
│ ├── test_heal_store.py # HealStore 存储测试
│ ├── test_trace.py # TraceCollector 测试
│ ├── test_page_object_generator.py # PageObject 生成器测试
│ ├── test_step_def_generator.py # StepDef 生成器测试
│ ├── page_objects/ # 自动生成的 PageObject(TUI 录制后产生)
│ ├── step_defs/ # 自动生成的 StepDefs(TUI 录制后产生)
│ └── features/ # behave BDD 特性
│ ├── environment.py # 浏览器生命周期钩子
│ ├── github_home.feature # GitHub 主页验证场景
│ └── steps/
│ └── web_steps.py # 中文步骤定义
├── logs/ # 运行日志
│ └── tui.log
├── pyproject.toml
├── behave.ini
└── README.md
开发
# 安装开发依赖
pip install -e . pytest pytest-asyncio
# 运行测试
pytest
# 运行 BDD 测试
behave
# 添加新适配器
# 1. 实现 engine.core.runner.TestRunner 接口
# 2. 放到 engine/adapters//
# 3. 在 cli.py 中注册