npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@autotest/agent

v0.0.23

Published

AutoTest Agent — AI 驱动的自动化测试执行代理,支持 HarmonyOS/Android/iOS

Downloads

1,751

Readme

@autotest/agent

基于 AI 的自动化测试执行代理核心包,通过多模态模型的视觉理解能力自主执行 HarmonyOS/Android/iOS 设备测试。

项目简介

AutoTest Agent 是一个智能化的移动设备自动化测试框架,支持 单层 Agent双层 Agent 两种架构模式,能够理解自然语言指令,通过多模态模型自主执行测试操作、发现 Bug、分析失败根因并生成测试报告。

核心特性

  • 多架构模式single(统一 Agent)、layered(Planner + Executor)两种模式可切换
  • 多模态视觉理解:通过多模态模型观察屏幕截图、定位 UI 元素、判断操作结果
  • 自然语言交互:中文描述测试步骤,自动转换为设备操作
  • 多平台支持:HarmonyOS(纯 TS 直驱 HDC,35 个设备操作全覆盖)、Android、iOS
  • MCP Server:42 个工具(35 设备操作 + 7 管理)通过 JSON-RPC 2.0 对外暴露
  • Bug 自动发现与根因分析:执行中主动发现异常,analyze 命令基于报告生成根因分析与改进建议
  • 录屏/雪碧图模式:动态场景(toast/加载动画/弹窗/倍速等瞬态效果)自动触发录屏(3 秒),抽取关键帧拼成雪碧图供多模态逐帧验证,避免单张截图漏判瞬态效果;报告内可"查看雪碧图"/"播放录屏"
  • 坐标二次定位 + 文字元素点击:点击类工具支持 text 参数按控件树文字定位元素中心;基于 dumpLayout 对裸坐标二次修正到最近可点击元素(coord snap),提升点击精度
  • 自愈闭环(Loop):执行→归因→改写→重执行的多轮自愈,自动修复用例问题或补充知识,支持 5 种执行模式与死循环检测
  • 多格式报告:执行报告生成 HTML / JSON,归因分析生成 JSON / HTML / Markdown 与批量汇总
  • 批量执行:JSONL/JSON 批量用例执行,支持断点续跑、进度报告、分类汇总
  • Skills 系统:加载技能步骤指导 Agent 执行复杂操作
  • 知识库:按 App 维度管理领域知识(如华为商城 vmall)
  • Debug 调试模式:任务执行后通过浏览器与 Agent 交互式复盘

目录结构

AutoTest-nodejs/
├── src/
│   ├── autotest-cli.ts            # CLI 入口(run/list-devices/analyze/config)
│   ├── index.ts                  # 包导出
│   ├── api/                      # AgentAPI 对外接口
│   │   ├── agent_api.ts
│   │   └── types.ts
│   ├── common/                   # 公共模块
│   │   ├── config/               # 配置(config.yaml / manager.ts / types.ts)
│   │   ├── model/                # LLM 调用封装
│   │   ├── llm_cache/            # LLM 响应缓存
│   │   ├── dfx/                 # 诊断/可观测性(LLM 流量记录)
│   │   ├── usage/                # Token 用量统计
│   │   ├── case_manager.ts       # 用例管理
│   │   ├── collect_case.ts      # 用例收集
│   │   ├── image_helper.ts       # 图片处理
│   │   ├── image_cacher.ts       # 图片缓存
│   │   ├── image_similarity.ts   # 图片相似度
│   │   ├── logger.ts             # 日志
│   │   ├── utils.ts              # 工具函数
│   │   ├── path_utils.ts         # 路径工具
│   │   ├── common_errors.ts      # 结构化错误(AgentError)
│   │   ├── datetime.ts           # 日期时间工具
│   │   ├── layout_parser.ts      # dumpLayout 解析 + 坐标二次定位(coord snap)
│   │   └── result_parser.ts      # 结果解析
│   ├── core/
│   │   ├── agent/                # Agent 实现
│   │   │   ├── single_agent/     # 单层 Agent
│   │   │   │   ├── agent.ts
│   │   │   │   ├── context_builder.ts   # 上下文构建
│   │   │   │   ├── hooks.ts / hook_manager.ts
│   │   │   │   ├── image_utils.ts
│   │   │   │   ├── llm_helper.ts         # LLM 调用辅助
│   │   │   │   ├── processors.ts         # 消息/工具处理
│   │   │   │   ├── report_hook.ts         # 报告 Hook
│   │   │   │   ├── scroll_search_agent.ts   # 滚动搜索子 Agent
│   │   │   │   ├── subagent_manager.ts      # 子 Agent 管理
│   │   │   │   └── tool_recorder_hook.ts
│   │   │   ├── layered_agent/   # 双层 Agent(Planner + Executor)
│   │   │   │   ├── decision.ts       # Planner 决策
│   │   │   │   ├── agent_registry.ts # Agent 注册表
│   │   │   │   ├── ability_helper.ts # 能力辅助
│   │   │   │   └── execute_agent/    # Executor 执行
│   │   │   ├── report_analyzer_agent/ # 失败根因分析 Agent(agent / data_loader / trace_extract / design_tool / analysis_progress / report_markdown / report_html_template/ / prompts/)
│   │   │   ├── rewrite_agent/    # 报告改写 Agent(agent / guardrails / parse / mapping / result_writer / types / prompts)
│   │   │   ├── design_doc/       # 设计文档 Agent(design_doc.ts)
│   │   │   ├── utils/
│   │   │   └── types.ts
│   │   ├── device/               # 设备抽象层
│   │   │   ├── device_protocol.ts # 设备协议抽象
│   │   │   ├── index.ts          # HDC 设备实现(封装 hdc/ 模块)
│   │   │   ├── types.ts
│   │   │   └── hdc/              # HDC 协议(device/input/screenshot/apps + capture_card_recorder / screen_recorder 录屏)
│   │   ├── mcp/                  # MCP 适配器
│   │   │   ├── base_adapter.ts
│   │   │   ├── harmony_hdc_adapter.ts # HarmonyOS 适配器(纯 TS 直驱 hdc,35 设备操作)
│   │   │   ├── android_adapter.ts # Android 适配器
│   │   │   ├── ios_adapter.ts     # iOS 适配器
│   │   │   ├── adapter_factory.ts # 适配器工厂
│   │   │   ├── mcp_tools.ts      # 双层 Agent MCP 工具
│   │   │   └── local_tools.ts   # 本地工具(wait / load_skill)
│   │   ├── prompt/               # 版本化提示词
│   │   │   ├── prompt_loader.ts
│   │   │   └── templates/        # single / hypium / planner / debug / fast_action / splitter 模板
│   │   ├── skill/                # Skills 系统(skill_manager.ts)
│   │   ├── memory/               # 记忆系统(memory_manager / compressed_session / context_compressor / reflector / tool_player / tool_recorder / session_factory)
│   │   └── preprocessor/         # 任务预处理
│   ├── data_types/               # 数据模型(action / agent / case / device / report / screen / task)
│   ├── reporter/                 # 报告生成(generator.ts / batch_summary.ts / json_report.ts / html_template/ / types.ts)
│   ├── loop/                     # 自愈闭环编排(执行→归因→改写→重执行,cli / orchestrator / result_writer / types)
│   ├── mcp-server/               # MCP server(42 工具:35 设备操作 + 7 管理)
│   │   ├── server.ts            # JSON-RPC 2.0 HTTP 服务 + adapter 委托
│   │   └── types.ts             # 工具枚举 + Zod schema + 描述
│   └── tools/                    # 工具
│       ├── batch_runner.ts       # 批量执行(发布为 autotest-batch 二进制)
│       ├── case_runner/          # 结构化用例执行(setup/process/teardown,发布为 autotest-case)
│       ├── config/               # 配置管理 CLI(init/get/set/list,发布为 autotest-config)
│       ├── gen_report.ts         # 分析报告 HTML 生成(--prev/--truth/--dir/--output)+ resolveReportHref 用例查看链接解析
│       ├── gen_analysis_report.ts # 批量后分析报告 HTML(batch_runner import 调;--reports token;KPI/混淆矩阵/明细)
│       ├── prompt_compare/       # 多 Prompt 批量对比(发布为 autotest-prompt-compare)
│       ├── token_comparison/     # Token 用量对比
│       └── runner.mjs            # caseTest/batchCaseTest 一键封装(自动 install/build)
├── types/
│   └── ai-stub.d.ts              # ai/@ai-sdk/openai 类型桩(仅 .d.ts 生成时使用,避免 OOM)
├── tests/                        # 单元测试(vitest,约 230 个用例 / 15 文件)
├── app_config.json               # App bundle/ability 映射
├── tsconfig.json                 # 主 tsconfig(JS 编译,--noCheck)
├── tsconfig.emit.json            # .d.ts 生成配置(用桩文件替换 ai 泛型)
└── package.json

架构说明

架构模式选择

| 架构模式 | agent.mode | 说明 | |----------|--------------|------| | 单层 Agent | single(默认) | 统一 Agent 处理规划与执行,基于 AI SDK,效率高 | | 双层 Agent | layered | Planner 决策 + Executor 执行,适合复杂任务拆解 |

单层 Agent 工作流程

用户任务 → SingleAgent → 多模态视觉理解 + 决策 → MCP 设备操作 → 报告生成
             (AI SDK)                          (HDC/ADB/WDA)   (HTML/MD/JSON)
  1. SingleAgent:接收用户任务,分析屏幕状态,生成操作指令
  2. 多模态视觉理解:通过多模态模型理解截图,定位 UI 元素,判断操作结果
  3. 设备层:通过 MCP 适配器与设备通信,执行点击、滑动等操作
  4. 报告生成:记录执行过程,输出测试报告

双层 Agent 工作流程

用户任务 → Planner(decision) → 原子操作指令 → Executor(execute) → 设备操作
                                                               (HDC 设备)
  1. Planner:分析当前状态,生成具体操作指令
  2. Executor:通过视觉识别定位 UI 元素,执行点击、滑动等操作
  3. 设备层:通过 HDC 协议与 HarmonyOS 设备通信

环境要求

系统要求

  • 操作系统:Windows / Linux / macOS
  • Node.js:推荐 22+ LTS(最低 18)
  • 包管理器:pnpm(启用 workspaces)

HarmonyOS 设备驱动(纯 TS)

HarmonyOS 设备测试通过纯 TypeScript 的 HDC 适配器直接驱动 hdc 命令。

HarmonyOS 适配器(src/core/mcp/harmony_hdc_adapter.ts)通过 hdc shell 执行 uitest uiInput(点击/滑动/输入)、snapshot_display(截图)、uitest dumpLayout(布局)、aa(应用启停)、bm(清数据)、power-shell(点亮/解锁)、uinput(多指手势)等原语,支持全部 35 个设备操作,进程内直接完成设备操作,无子进程、无 HTTP 服务。

Android/iOS 平台使用 @mobilenext/mobile-mcp(通过 npx 自动安装)。

设备要求

  • HarmonyOS 设备:支持 HDC 协议的设备或模拟器
  • HDC 工具:已安装并配置 hdc 命令行工具(加入 PATH)
  • 网络连接:开发机与设备网络连通

快速开始

cd AutoTest-nodejs
npm install              # 安装依赖
npm run build            # 构建项目
npm run setup            # 生成 config.yaml 配置文件(项目根目录)

npm run setup 会在项目根目录创建 config.yaml(基于模板,含占位符),并提示需要修改的字段。编辑该文件填入你的配置:

model:
  unified:
    name: "qwen3.8-flash"                          # 模型名
    api_key: "sk-xxx"                              # 你的 DashScope API Key
    base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"

device:
  device_sn: "LNG0223721000045"                  # hdc list targets 查看

config.yaml 已加入 .gitignore,不会被提交,可安全填入真实密钥。

也可用 autotest-config 命令行工具修改:

node dist/tools/config/config_tool.js set model.unified.api_key "sk-xxx"
node dist/tools/config/config_tool.js set model.unified.name "qwen3.8-flash"
node dist/tools/config/config_tool.js set device.device_sn "YOUR_DEVICE_SN"

配置完成后即可运行测试:

node dist/autotest-cli.js run --task "打开设置应用,查看 WiFi 列表"

配置说明

配置文件位于 src/common/config/config.yaml(构建后随包发布到 dist/common/config/config.yaml)。ConfigManager 按以下顺序分层加载并合并(后者覆盖前者):

  1. 包内默认 config.yaml
  2. 包内 config.local.yaml(可选)
  3. 当前工作目录(项目根目录)config.yaml(可选,适合本地覆盖 API Key / 模型)
  4. 当前工作目录 config.local.yaml(可选)
  5. CLI --config <path> 指定的文件(最高优先级)

模型配置

推荐模型qwen3.8-flash(多模态,DashScope 兼容模式 https://dashscope.aliyuncs.com/compatible-mode/v1)。实测在 100 条 verify 用例上准确率 84% / F1 0.887;双层模式下 execute/decision/verify 各槽位均可使用 qwen3.8-flash,也可为 execute 单独配置专用 GUI 模型(如下方示例)。

model:
  unified:                        # 单层模式使用
    name: "qwen3.8-flash"
    base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
    api_key: "YOUR_API_KEY_HERE"  # 必填
    provider: "openai"            # openai / azure
    temperature: 0.1
    top_p: 0.9
    frequency_penalty: 0.5
    max_tokens: 1024
    timeout: 600
    max_retries: 3
    prompt_type: "v2.0"            # 提示词版本

  execute:                        # 双层模式 — 执行模型
    name: "gui-plus-2026-02-26"
    base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
    api_key: "YOUR_API_KEY_HERE"  # 必填
    provider: "mai-ui"
    max_steps: 3

  decision:                       # 双层模式 — 决策模型
    name: "qwen3.8-flash"
    base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
    api_key: "YOUR_API_KEY_HERE"  # 必填
    provider: "openai"
    temperature: 0.0
    top_p: 0.1
    frequency_penalty: 1.0

  verify:                         # 验证模型(可选,留空回退到 decision)
    name: ""
    base_url: ""
    api_key: ""
    provider: "openai"

Agent 配置

agent:
  unified:                           # 统一 Agent 配置(single/layered 共用)
    mode: "single"                    # single / layered
    max_steps: 50                     # 最大执行步数
    lang: "zh"                        # 语言
    enable_preprocess: false          # 任务预处理
    stream_log: false                 # 流式输出模型回复
    debug_mode: null                  # null / "memory" / "file"(预留,尚未实现)
    parse_mode: "native"              # 解析模式:custom(文本标签)/ native(SDK 函数调用)
    tool_provider: "device"           # 工具提供者:device / mcp
    action_interval: 1.5              # 操作间隔(秒)
    max_history_image: 3              # 历史截图保留数量
    screenshot_max_pixels: 1500       # 截图最大像素
    include_previous_screenshot: true       # 是否包含上一步截图
    previous_screenshot_compress_ratio: 0.7 # 上一步截图压缩比
    max_history_actions: 10           # 历史操作保留数量
    role: null                        # Agent 角色(控制提示词和工具过滤,如 planner)
    session_type: "compressed"        # 会话类型:sqlite / compressed(自动压缩历史)
    prompt_name: "single_v2.0"        # 提示词名称(全文件名,优先于 prompt_version)
    prompt_version: ""                # 提示词版本覆盖
    max_loops: 0                      # 自愈闭环:>0 启用(N 轮迭代),0 禁用
    enable_cache: true                # 启用 LLM 缓存
    screenshot_on_tool_end: true      # 工具执行后截图
    verbose: false                    # 详细日志
    json_output: false                # JSON 输出
    apirec: false                     # API 录制

设备配置

device:
  device_sn: null                         # 设备序列号(留空自动检测)
  ip: "127.0.0.1"                         # 设备 IP
  port: 8710                              # HDC 端口
  hdc_path: "hdc"                         # HDC 工具路径
  reset_device: true                      # true=回主页+清后台, false=跳过, 列表=指定包名 force-stop
  screen_always_on: true                  # 测试期间保持屏幕常亮
  device_impl: "HDCDevice"                # 设备实现:"HDCDevice"(默认)或 "HDCDeviceInner"
  app_config: ""                          # app_config.json 路径(MCP bundle 映射,留空不使用)
  operation_mode: "phone"                # 操作模式:"phone"(默认)或 "pc"
  keepalive_process_whitelist: []         # 清后台时保留的进程白名单(包名列表),这些进程不会被 force-stop
  # keepalive_process_whitelist:
  #   - "com.hm.screenrecorder"
  #   - "com.hm.keeprunning"
  skip_clear_process: false               # true=每次用例执行前跳过清理后台进程(等价于 --skip-clear-process)

进程清理与白名单

每次用例执行前,Agent 会调用 adapter.reset() 执行设备重置:回到主页 + 清理后台进程。通过以下配置控制行为:

  • reset_device: true(默认):回到主页,清理所有后台进程(白名单内除外)
  • reset_device: false:完全跳过重置
  • reset_device: ["pkg1", "pkg2"]:仅 force-stop 指定包名
  • keepalive_process_whitelist:白名单内的进程不会被 force-stop(仅在 reset_device: true 模式下生效)
  • skip_clear_process: true 或 CLI --skip-clear-process:完全跳过 adapter.reset(),不清理任何进程
  • CLI --keepalive pkg1 pkg2:运行时设置白名单(别名 --keepalive-process-whitelist),与 keepalive_process_whitelist 配置等价

白名单在 reset() 执行时从 ConfigManager 动态读取,因此 CLI --keepalive 和 config.yaml 中的 keepalive_process_whitelist 均能实时生效,无需关心 adapter 初始化顺序。

日志 / 输出 / 网络配置

log:
  level: "INFO"
  device_log_level: "info"
  verbose: true
  max_log_size: 10            # 单文件最大 MB
  max_log_file_num: 5
  enable_console_log: true
  enable_file_log: true

output:
  json_output: false
  report_dir: null            # 自定义报告目录
  root_dir: "reports"         # 报告根目录
  report_name: "autotest_report"
  embed_images: false
  embed_max_pixels: 800

network:
  timeout: 600
  max_retries: 3
  no_proxy: ""

失败分析配置(analyze 命令)

analyze:
  model_name: ""              # 留空则回退到 decision
  base_url: ""
  api_key: ""
  temperature: 0.1
  max_tokens: 4096
  timeout: 90
  max_retries: 3
  enable_multimodal: true
  max_screenshot_pixels: 800
  max_key_steps: 5
  only_fail: true             # 仅分析失败用例

使用方法

以下命令均在 AutoTest-nodejs/ 目录下运行。

测试用例有三种运行方式,按场景选择:

| 方式 | 命令 | 适用场景 | |------|------|---------| | caseTest(推荐) | npm run caseTest -- <参数> | 日常单用例运行,自动增量构建 | | batchCaseTest | npm run batchCaseTest <文件> | 批量执行 JSONL/JSON 用例 | | 直接 CLI | node dist/autotest-cli.js run <参数> | 需手动 build,适合调试编译产物 |

方式一:caseTest(推荐)

caseTest 通过 runner.mjs 自动检测源码变更并增量构建,无需手动 npm run build,然后以 run 子命令调用 dist/autotest-cli.js

cd AutoTest-nodejs

# 基本用法:-- 后传递 CLI 参数
npm run caseTest -- --task "打开设置应用,查看 WiFi 列表"

# 指定模式 / 平台
npm run caseTest -- --task "测试任务描述" --mode layered --platform harmony

# 从 JSON 用例文件加载(第 10 条用例)
npm run caseTest -- --case-file cases.json --case-index 10

# 指定配置文件
npm run caseTest -- --task "测试任务" --config /path/to/config.yaml

# 列出设备
npm run caseTest -- list-devices

# 查看配置
npm run caseTest -- config --show

# 分析失败任务
npm run caseTest -- analyze --task-id 20260714_145936_001 --case-idx 0

使用示例

示例1:通知栏测试

npm run caseTest -- --task "动作:打开 com.example.saltplayerharmony -> 播放歌曲 -> 下拉通知栏观察歌曲显示 -> 切换歌曲 -> 再次下拉通知栏
预期结果:通知栏显示当前歌曲封面,与 App 内一致;切歌时通知内容自动更新"

示例2:长按预览测试

npm run caseTest -- --task "测试步骤:
1、打开 com.example.webfifth8,点击【6.0.0.37】按钮,点击【SR20250224905259】按钮,
连续向上滑动找到黑色加粗字体的【地址】,长按【广州市白云区机场路1234号】,5 秒后点击右侧空白
2、长按【123 Queen's Road, London, UK】,5 秒后点击右侧空白
预期结果:
1、弹出预览项和【导航前往】【复制】【选择文本】菜单
2、不弹出预览项和菜单"

示例3:指定模式 / 平台 / 配置文件

npm run caseTest -- \
  --task "打开设置应用,查看 WiFi 列表" \
  --mode layered \
  --platform harmony \
  --config /path/to/config.yaml

示例4:从 JSON 用例文件加载

npm run caseTest -- --case-file cases.json --case-index 10

示例5:列出设备 / 查看配置 / 分析失败

npm run caseTest -- list-devices
npm run caseTest -- config --show
npm run caseTest -- analyze --task-id 20260714_145936_001 --case-idx 0

方式二:批量执行

通过 batchCaseTest 批量执行 JSONL/JSON 用例,具备断点续跑、进度报告、分类汇总能力。同样通过 runner.mjs 自动增量构建。

cd AutoTest-nodejs

# 位置参数:第 1 个 = 用例文件,第 2 个 = category(可选,默认 default)
npm run batchCaseTest cases.jsonl
npm run batchCaseTest cases.jsonl smoke

# 显式用 -- 标志(等价写法)
npm run batchCaseTest -- --testcases cases.jsonl --category smoke

# 跳过清理后台进程(保留上条用例的进程状态)
npm run batchCaseTest -- --testcases cases.jsonl --skip-clear-process

# 指定最大执行用例数
npm run batchCaseTest -- --testcases cases.jsonl --max-cases 5

批量执行参数

| 参数 | 说明 | |------|------| | --testcases <path> | 用例文件路径(JSON/JSONL) | | --category <name> | 用例分类名(默认 default,用于报告与回写) | | --task-dir <dir> | 报告输出目录(默认 reports/<date>/<time>/) | | --testset-root <dir> | 用例集根目录,用于回写 auto_result 到原始 JSON | | --config <path> | 配置文件路径 | | --mode <m> | Agent 模式:single / layered | | --prompt-name <name> | 按名称加载提示词 | | --max-cases <n> | 限制执行用例数量 | | --skip-clear-process | 每条用例执行前跳过清理后台进程 |

作为已安装的 npm 包使用时,也可调用发布的 autotest-batch 二进制:

npx autotest-batch cases.jsonl
npx autotest-batch cases.jsonl smoke

批量执行特性

  • 支持断点续执行(自动跳过已完成用例)
  • 支持指定起始索引
  • 定期进度报告(每 10 例)
  • 自动更新原始用例文件状态与分类报告
  • 输出 JSONL/CSV 结果与汇总
  • 单个用例超时 10 分钟

方式三:直接调用 CLI(需先构建)

cd AutoTest-nodejs
npm run build              # 两步构建:tsc --noCheck 生成 JS + tsc -p tsconfig.emit.json 生成 .d.ts
node dist/autotest-cli.js run --task "打开设置应用,查看 WiFi 列表"

CLI 命令参考

Usage: autotest <command> [options]

Commands:
  run           Run a test task
  list-devices  List connected devices
  analyze       Analyze a failed task
  config        Show or update configuration
  --version     Show version (alias: -v, version)

Run options:
  --task <desc>          Task description
  --case-file <path>     Path to a JSON case file (use with --case-index)
  --case-index <n>       1-based case index in the file
  --device <sn>          Device serial number
  --platform <p>         Platform: harmony | android | ios
  --mode <m>             Agent mode: single | layered
  --ip <addr>            Device IP address
  --port <num>           Device port number
  --task-name <name>     Test case name
  --case-num <num>       Case number
  --report-dir <dir>     Report output directory
  --prompt-version <v>   Prompt version
  --prompt-name <name>   Load prompt by name (priority over --prompt-version)
  --app-config <path>    App→bundle mapping config file path
  --config <path>        Path to config.yaml (default: bundled config.yaml)
  --loop                 Enable self-healing loop (execute→analyze→rewrite→re-execute), default 3 iterations
  --max-loops <n>        Max loop iterations (>=2 enables FULL_LOOP; 0 disables)
  --analyze-after        Auto-analyze after task execution (requires --task)
  --analyze <dir>        Analyze-only: attribute an existing report dir (alias: --analyze-dir)
  --rewrite <dir>        Rewrite-only: rewrite from an existing analysis (alias: --rewrite-dir)
  --keepalive-process-whitelist <pkg1> <pkg2> ...
                         Keep these processes alive during device reset (alias: --keepalive)
                         e.g. --keepalive com.hm.screenrecorder com.hm.app
  --skip-clear-process   Skip clearing background processes before each test case

Analyze options:
  --task-id <id>         Task ID to analyze
  --case-idx <n>        Case index within the task

自愈闭环(Loop)

Loop 是 AutoTest 的自愈闭环编排器,将"执行→归因→改写→重执行"串成多轮状态机,自动修复失败的测试任务。

工作原理

┌─────────────────────────────────────────────────────────────────┐
│  FULL_LOOP 单轮流程(Step 1→9)                                  │
│                                                                  │
│  Step 1  执行(hybrid_agent_chat)→ report_dir                   │
│  Step 2  归因(ReportAnalyzerAgent)→ root_cause                 │
│  Step 3  PASS 判定 ──── PASS? → 终止 PASSED                      │
│  Step 4  UNREWRITEABLE 判定 ── 应用/环境/无问题? → 终止           │
│  Step 5  死循环检测 ──── 连续 2 轮相同根因? → 终止 DEAD_LOOP     │
│  Step 6  改写(RewriteAgent)→ rewrite_action                    │
│  Step 7  知识注入 ──── ADD_KNOWLEDGE → args.task += 知识文本     │
│  Step 8  任务改写 ──── REWRITE_TASK → args.task = 改写后文本     │
│  Step 9  记录本轮 → 下一轮(回到 Step 1)                        │
│                                                                  │
│  终止条件: PASSED / UNREWRITEABLE / MAX_LOOPS / DEAD_LOOP / ERROR │
└─────────────────────────────────────────────────────────────────┘

5 种执行模式

| 模式 | 触发条件 | 跳步 | 说明 | |------|----------|------|------| | FULL_LOOP | --max-loops >= 2--loop | Step 1→9 | 完整闭环,多轮迭代 | | EXECUTE_ANALYZE | --analyze-after | Step 1→2 | 执行 + 归因,单轮 | | EXECUTE_ONLY | 仅 --task(默认) | Step 1 | 仅执行,单轮 | | ANALYZE_ONLY | --analyze <dir> | Step 2 | 仅归因(对已有报告) | | REWRITE_ONLY | --rewrite <dir> | Step 6→9 | 仅改写(对已有分析结果) |

改写动作

RewriteAgent 根据根因分析输出决定改写策略:

| 动作 | 适用场景 | 行为 | |------|----------|------| | REWRITE_TASK | 用例问题 | 替换 args.task 为 LLM 改写后的完整文本 | | ADD_KNOWLEDGE | Agent 问题 | 在 args.task 末尾追加知识文本 | | BOTH | Agent 理解性问题 | 先替换 task,再追加知识 | | NO_REWRITE | 不可改写 | 终止(UNREWRITEABLE) |

启动方式

CLI:

# 完整闭环(默认 3 轮)
npm run caseTest -- --task "打开设置" --loop

# 指定轮数
npm run caseTest -- --task "打开设置" --max-loops 5

# 执行 + 归因(单轮,不改写)
npm run caseTest -- --task "打开设置" --analyze-after

# 仅归因(对已有报告目录)
npm run caseTest -- --analyze reports/20260714_145936_001

# 仅改写(对已有分析结果)
npm run caseTest -- --rewrite reports/20260714_145936_001

编程调用:

import { AutoTestAgent } from '@autotest/agent';

const agent = new AutoTestAgent({ apiKey, modelName, baseUrl });

// FULL_LOOP
await agent.runTask('打开设置', { maxLoops: 3 });

// EXECUTE_ANALYZE
await agent.runTask('打开设置', { analyzeAfter: true });

// REWRITE_ONLY
await agent.runTask('', { rewriteReportDir: 'reports/20260714_145936_001' });

配置文件启用:

agent:
  unified:
    max_loops: 3   # >0 即启用闭环(N 轮迭代),0 禁用

max_loops 是 loop 的唯一配置参数。>= 2 进入 FULL_LOOP,1 进入 EXECUTE_ONLY。CLI --max-loops 优先于配置文件。

输出产物(仅 FULL_LOOP)

reports/<taskId>/
├── iter_1/                    # 第 1 轮
│   ├── screenPath/            # 截图
│   ├── layout/                # 布局
│   ├── log/                   # 日志
│   ├── <iter_1>.html          # 执行报告(文件名 = 目录名脱敏)
│   └── analysis/              # 根因分析报告(json/html/md 三件)
├── iter_2/                    # 第 2 轮(改写后重执行)
│   └── ...
├── loop_result.json           # 闭环结果(各轮记录 + 终止原因 + task 演进)
└── loop_summary.html          # 闭环汇总(Tab 切换各轮执行/分析报告)
  • loop_result.json:序列化的 LoopResult,含每轮 IterationRecord(归因摘要、改写动作、改写后 task、知识文本)
  • loop_summary.html:Tab 页面,Loop 汇总(终止原因 + 各轮概览表 + 任务演进时间线)+ iframe 内嵌各轮执行/分析报告

报告目录结构

reports/
└── <taskId>/                  # 如 20260714_145936_001
    ├── <taskId>.html          # HTML 报告(文件名 = 目录名脱敏)
    ├── <taskId>.json          # JSON 数据(增量与终态同名渐进覆盖)
    ├── layout/                # 布局数据
    ├── log/                   # 日志文件
    ├── screenPath/            # 截图目录
    └── analysis/              # analyze 命令的根因分析报告(json/html/md 三件)

报告内容

  • 执行时间线:每一步操作与结果
  • Bug 发现:异常与缺陷记录
  • 截图记录:每步操作截图
  • Token 消耗:模型 Token 统计
  • 最终判定:测试通过 / 失败
  • 根因分析analyze 命令):失败原因、改进建议、关键截图、评分

Debug 调试模式

注意:此功能目前尚未实现。配置字段 agent.unified.debug_mode 已在 schema 中预留(接受 null / "memory" / "file"),但浏览器交互式复盘 Dashboard 尚未开发。配置该字段不会产生错误,也不会启用任何调试行为。

作为三方库集成

本包可作为 npm 依赖被其他工程集成,通过 AutoTestAgent 门面类创建实例并下发任务。

安装

npm install @autotest/agent
# 或
pnpm add @autotest/agent

快速开始

import { AutoTestAgent } from '@autotest/agent';

const agent = new AutoTestAgent({
  apiKey: 'sk-xxx',
  modelName: 'qwen3.8-flash',
  baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
  deviceSn: 'LNG0223721000045',   // 可选,留空自动检测
});

const result = await agent.runTask('打开设置应用,查看 WiFi 列表');
console.log(result.status);       // 'completed' | 'failed'
console.log(result.tip);          // 执行摘要
console.log(result.reportDir);    // 报告目录路径

配置参数

AutoTestAgent 构造函数接收 AutoTestAgentConfig

| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | apiKey | string | 是 | LLM API Key(unified 模型使用) | | modelName | string | 是 | 模型名称 | | baseUrl | string | 是 | LLM API 地址 | | provider | string | 否 | 模型提供商,默认 'openai' | | executeModel | ModelSlotConfig | 否 | 双层模式 Execute 模型配置(apiKey/modelName/baseUrl/provider/temperature/topP/maxTokens);未设置时回退到 unified | | decisionModel | ModelSlotConfig | 否 | 双层模式 Decision 模型配置;未设置时回退到 unified | | deviceSn | string | 否 | 设备序列号,留空自动检测 | | ip | string | 否 | 设备 IP,默认 127.0.0.1 | | port | number | 否 | 设备端口,默认 8710 | | platform | 'harmony' \| 'android' \| 'ios' | 否 | 指定平台,跳过自动检测 | | agentMode | 'single' \| 'layered' | 否 | Agent 模式,默认 'single' | | maxSteps | number | 否 | 最大执行步数,默认 100 | | reportDir | string | 否 | 报告输出目录,默认 reports | | enableCache | boolean | 否 | 启用 LLM 缓存,默认 true | | configPath | string | 否 | 加载完整 YAML 配置文件路径 | | configOverrides | Record<string, unknown> | 否 | 高级覆盖,结构同 AppConfig |

runTask 方法

const result = await agent.runTask(task: string, options?: RunTaskOptions);

RunTaskOptions 可选参数(覆盖构造时的配置):

| 参数 | 类型 | 说明 | |------|------|------| | agentMode | AgentMode | 覆盖 Agent 模式 | | platform | DevicePlatform | 覆盖平台 | | deviceSn | string | 覆盖设备序列号 | | ip / port | string / number | 覆盖设备地址 | | reportDir | string | 覆盖报告目录 | | taskName | string | 用例名称 | | caseNum | string | 用例编号 | | maxSteps | number | 覆盖最大步数 | | skipClearProcess | boolean | 跳过清理后台进程(等价 --skip-clear-process) | | configOverrides | Record<string, unknown> | 运行时配置覆盖 |

其他方法

// 查询任务结果
const result = await agent.getTaskResult(taskId);

// 分析失败根因
const analysis = await agent.analyzeFailure(taskId, caseIdx);

// 列出设备
const devices = await agent.listDevices();

// 停止正在运行的任务
agent.stopTask();

// 读取/更新配置
const config = agent.getConfig();
agent.updateConfig({ agent: { maxSteps: 50 } });

使用完整 YAML 配置

如果需要配置双层 Agent(execute/decision 模型)、分析模型等高级选项,可通过 configPath 加载完整 YAML:

const agent = new AutoTestAgent({
  apiKey: 'sk-xxx',        // 覆盖 YAML 中的 api_key
  modelName: 'qwen3.8-flash',
  baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
  configPath: '/path/to/config.yaml',
});

日志显示

日志格式:<时间> - AutoTest - <级别> - <消息>。控制台默认输出 INFO+(INFO→stdout,WARNING/ERROR→stderr),runTask 时另落盘全量(DEBUG+)到报告目录 log/agent_<taskId>.log。各场景默认即可见 INFO+:

| 场景 | 日志去向 | |------|----------| | cmd / opencode 跑 node ... | stdout/stderr → 终端或被父进程捕获 | | 脚本 spawn node | 管道,需同时读 child 的 stdout+stderr | | 脚本内 new AutoTestAgent(...) | 当前进程 stdout;可用 addLogSink 接入自定义流 |

场景一:cmd / opencode 直接跑 CLI

无需额外配置,INFO+ 默认打印到控制台:

node dist/autotest-cli.js run --task "打开设置应用"

场景二:脚本内 spawn 子进程

INFO 走 stdout、WARN/ERROR 走 stderr,需同时捕获两路才能拿到完整 INFO+:

import { spawn } from 'child_process';

const child = spawn('node', ['dist/autotest-cli.js', 'run', '--task', '打开设置'], {
  stdio: ['ignore', 'pipe', 'pipe'],
});

child.stdout.on('data', (d) => process.stdout.write(`[out] ${d}`));
child.stderr.on('data', (d) => process.stderr.write(`[err] ${d}`));
child.on('exit', (code) => console.log('exit', code));

场景三:进程内 new AutoTestAgent 接入自定义日志流

默认日志会进当前进程的 stdout。若要接入自己的日志系统(winston / pino / 远程上报等),用 addLogSink 订阅——回调按 INFO+ 阈值投递,返回取消订阅函数:

import { AutoTestAgent, addLogSink } from '@autotest/agent';

// 接入自定义日志流
const unsubscribe = addLogSink((level, message, formatted) => {
  // level: 'INFO' | 'WARNING' | 'ERROR'(DEBUG 已被默认 INFO 阈值过滤)
  myLogger.log({ level, message });
  // 或转发完整带时间戳行:formatted
});

const agent = new AutoTestAgent({ apiKey, modelName, baseUrl });
await agent.runTask('打开设置应用,查看 WiFi 列表');

unsubscribe(); // 可选:停止订阅

调整详细度

import { configureLogger } from '@autotest/agent';

configureLogger({ consoleLevel: 'DEBUG' }); // 控制台 + sink 同时放行 DEBUG

consoleLevel 是控制台与 sink 的共同「详细度」旋钮;文件日志始终为 DEBUG(落盘全量)。控制台写入已做 EPIPE 保护,消费方管道意外关闭不会导致 agent 崩溃。

脚本

AutoTest-nodejs/ 目录下:

cd AutoTest-nodejs
npm run build          # 两步构建:tsc --noCheck 生成 JS + tsc -p tsconfig.emit.json 生成 .d.ts
npm run setup          # 生成 config.yaml 配置文件(首次使用前执行)
npm run caseTest       # 单用例运行(自动增量构建,推荐)
npm run batchCaseTest  # 批量用例运行(自动增量构建)
npm test               # 运行单元测试(vitest run)
npm run test:watch     # 监听模式单元测试
npm run typecheck      # 类型检查(tsc --noEmit)
autotest --version     # 查看版本号

构建说明:由于 ai SDK 的深层泛型类型会导致 tsc OOM,构建拆分为两步:

  1. tsc --noCheck — 跳过类型检查,快速生成 .js 文件
  2. tsc -p tsconfig.emit.json — 使用 types/ai-stub.d.ts 桩文件替换 ai/@ai-sdk/openai 的复杂泛型类型,生成 .d.ts 类型声明
  3. copyfiles — 拷贝 yaml/md 资源文件

单元测试

单元测试位于 tests/,使用 vitest,共 205 个测试(13 个文件):

| 测试文件 | 覆盖模块 | 测试数 | |---------|---------|-------| | config-manager.test.ts | 配置加载/合并/Zod 校验 | 22 | | agent-error.test.ts | 结构化错误/序列化/分类 | 22 | | agent-api.test.ts | AgentAPI 接口/状态转换 | 24 | | adapter.test.ts | 适配器/平台差异/工厂选择 | 19 | | llm-caller.test.ts | LLM 调用封装/mock | 15 | | report-generator.test.ts | 报告生成/HTML marker/标签剥离 | 11 | | analyzer-parse.test.ts | 失败分析输出解析 | 10 | | single-agent.test.ts | Agent 执行/截图注入/abort | 9 | | key-steps-builder.test.ts | 关键步骤构建 | 9 | | data-loader.test.ts | 数据加载 | 9 | | hdc-adapter.test.ts | HarmonyHdcAdapter 35 设备操作全覆盖 | 42 | | autotest-agent.test.ts | 门面类(mock adapter_factory,密闭) | 8 | | logger.test.ts | 文件日志/格式 | 5 |

cd AutoTest-nodejs
npm test                                          # 运行全部测试
npx vitest run tests/config-manager.test.ts        # 运行单个文件

开发扩展

自定义提示词

编辑提示词模板:src/core/prompt/templates/single/ · hypium/ · planner/ · debug/ · fast_action/ · splitter/)。

添加新的 MCP 工具

  1. src/core/mcp/mcp_tools.ts(双层)或 local_tools.ts(本地)中添加
  2. src/core/mcp/harmony_hdc_adapter.tscallTool switch 中添加设备操作 case
  3. src/mcp-server/types.ts 中添加工具枚举 + Zod schema
  4. src/mcp-server/server.ts 中注册到 SCHEMA_MAPDEVICE_TOOL_NAMES

自定义适配器

参考 src/core/mcp/harmony_hdc_adapter.ts,继承 base_adapter.ts 中的 MCPDeviceAdapter,并在 adapter_factory.ts 注册。

常见问题

Q1: 设备连接失败

  • 确认 HDC 工具已安装并加入 PATH
  • 运行 hdc list 查看设备是否在线
  • 检查 device.ip / device.port 配置

Q2: 如何使用自定义模型?

config.yaml 修改对应模型的 base_urlapi_key,支持所有 OpenAI 兼容 API。

Q3: 如何切换 Agent 架构模式?

  • 修改 config.yamlagent.mode
  • 或命令行 --mode single|layered

Q4: 如何查看测试报告?

查看 reports/<taskId>/<taskId>.html