测试 forge
AI动力QA自动化. 把它指向一个项目 然后扫描代码, 为每个特性起草一个行走文件,并生成种子 Jest 和 符合项目自身结构的Playwright测试.
在任何项目中工作,与任何AI CLI(默认给克洛德).
安装
npm install -D @activate-core/test-forge
```
testforge calls a local AI CLI to do its work. By default it uses
`claude -p`, so make sure the Claude CLI is installed and logged in.
To use a different CLI, see [Configuration](#).
## Quick start
From your project root:
```bash
testforge setup # one-time: inspect project, map it, draft journey docs
testforge generate # generate tests + seed files from the docs
之后 setup,审查 docs/ 修补一切
AI错了——它们是测试的真相来源. 然后运行
generate。 。 。 .
当您的代码稍后更改时 :
testforge update # re-check and refresh only what changed
在一次旅程中工作
update 是整个项目命令:如果代码已移动,则重映射,
重新起草 每个 医生和再生。 大多数时候你想要的
旅行,两步走 --journey (或 --area:
# the spec for one journey changed — re-draft just that doc, then its tests
testforge discover --journey payment
testforge generate --journey payment
# adding a journey that the reference now describes
testforge discover --journey refund-flow
testforge generate --journey refund-flow
# everything in one area
testforge generate --area ops
在自己的文档中到达的特性
门票上出现PDF,或者一个特性的规格. 点 discover 临τ
直接的,你没有给行程起名, AI读文件并工作
它描述的是:
testforge discover --reference ./docs/tickets/zh-4521.pdf
参考文献只写它实际覆盖的旅程. 罚单的PDF
从来没有听说过你其他的旅程, 所以他们的文件是完全像他们
是,而项目本身的真相来源 仍然停留在原地。 测试Forge 然后
记得这段旅程来自那份文件, 并刷新它从
有在每一个后期 update ——不是来自项目类别,至今没有
说说看.
当一个参考物真的是整个产品的新规格时,就这么说:
testforge discover --reference ./docs/prd-v2.md --replace
一个旅程 实值 其医生: generate 读取 docs/ {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}并处理每一次减价
将这里作为一次旅程。 所以,一个医生你手写—— 对于一个特征:
参考文献尚未涵盖,或者从一张票上取出一张,其效果完全像一张
起草一个。 那就写医生吧 generate --journey <name>。 。 。 .
如果你自己编辑一个医生,跳过 discover 完全并直接去
generate --journey <name>。 。 。 .
重生替换: 当一个行程被重生时, 测试文件以检查 不再存在被删除——但只有TestForge所写的文件. 你自己的测试是 从来没有碰过.
图标
| 命令 | 它会做什么 |
|---|---|
testforge setup | 一次性设置:运行init,映射,并依序发现,有进展. |
testforge generate | 写每个旅行医生的测试。 更改后的文件只更新了更改的规则的测试. 只写:它没有运行. |
testforge update | 当 源代码 或 参考文献 已经改变。 如果两者都没有,则跳过一切(没有AI呼叫). 广义的设计——一次旅程,见下文. |
高级( 运行一阶)
| 命令 | 它会做什么 |
|---|---|
testforge init | 检查工程并写入 testforge.config.json 只有这个. |
testforge map | 重建项目地图testforge.md仅此而已. |
testforge discover | 重新起草每个行程的文件 docs/ 只有这个. |
testforge env | 重建 .env.testing.example 仅从文件. |
testforge run | 运行生成的测试( R)--journey 编号 : --area 编号 : --env-file) (中文(简体) ). 特性不在代码中的文件被扣为待决文件( Q)--all 运行它们. |
testforge bind | 在特性船后:哪个测试文件的代码已经准备好,哪个等待特性,它使用这个代码的名称拼写不同. --accept "doc=code" 使用代码的措辞。 没有AI. |
testforge review | 询问AI审查者最后的失败是缺陷,测试错误还是环境. 仅供求. |
testforge report | 向仪表板公布结果—— --results 经过一次逃亡, --inventory 以注册每个生成的检查. |
值得一提的旗帜
| 旗帜 | 打开 | 它会做什么 |
|---|---|---|
--journey <name> | 发现、生成、运行 | 工作在一个旅程中,而不是所有他们. |
--area <name> | 发现、生成、运行 | 一个领域的工作(api, web, ops...). |
--force | 生成 | 即使在医生没有改变的时候也要再生. |
--plan-only | 生成 | 计划并检查每次行程(testforge/memory/<area>/<id>/plan-check.md,不写测试. |
--refresh | 发现 | 再次获取引用, 而不是上次运行时保存的副本 . |
--all | 运行 | 同时运行其特性尚未在代码中的文件 . |
--refresh-docs | 更新 | 即使没有明显变化,仍重新起草文件——见下文. |
--reference <file|url> | 设置 | 将文件以光谱而不是代码地图为基础. |
--source map | 设置 | 把文件放在下面 testforge.md,没有迅速. |
当无法检查引用时
update 比较两件事:一个是源代码的散列,另一个是源代码的散列
引用文档来源。 它可以读取的参考文献( 文件, 或普通 URL)
直接比较,所以代码不变时移动的光谱是
被侦测到的——这个案例过去是默默地传入的"一切都是最新的".
有些参考文献完全无法阅读。 名称或关联链接回答 a plain 获取应用程序, 而不是文档: 无页面内容, 以及构建 印花,每个供应商部署时都会有变化。 痛恨这比不痛 检查——它会报告"不变" 当光谱移动,"改变"每一个 是卖家发货的时间 TestForge拒绝了,告诉你什么是无法做到的 检查 :
No source changes detected.
Note: the reference could not be checked — app.notion.com serves an app
shell, not the document — its content needs the API.
If the specification has changed, run `testforge update --refresh-docs`.
如何运作
设置 分三个阶段编制项目:
- 输入 - 检测布局(monorepo或单一应用程序,测试之处)
互联网档案馆的存檔,存档日期2013-12-16
testforge.config.json。 。 。 . - 地图 写作
testforge.md:一份简短的行程清单和一个 数据层摘要(数据库、模型、关键字段)。 大赦国际 而不是每次重新扫描所有的代码. - 发现 - 写一个丰富的医生每程
docs/- 实地, 行动、预期结果、边缘案例、安全说明和数据a 测试需要.
生成 将每个医生变成一个测试。 一个旅行与 Type: api
a. 成为测试标准(HTTP + 数据库检查); Type: web 变成一个
剧作家测试. 其他领域使用配置中设定的框架. 还有
生成一个种子文件,提供每个测试需要的测试数据.
生成 将每个文件交给项目自己的 ESLint
--fix 在继续前进之前 格式差异得到纠正——CI
运行在运行测试前的 lint 和正确但缩进的文件
不同的是,建设仍然失败。 任何无法修复的插件( 未使用)
据报道,这是对这次旅行的警告,因为
任何检查都不值得一个人注意 如果项目没有
ESLint,步骤被跳过.
更新 使用您的源代码 和参考文献来自, 并将两者比作最后一场比赛。 没有改变意味着没有工作 没有AI 电话; 任何改变一个触发器 刷新, 它说哪个。 参考它 无法读取被报告为准确的, 而不是“最新”.
真相来源
路由记录 docs/ 是检验真理的来源
generate 阅读文件,没有别的。 医生从哪里来
决定一切.
默认文件来源于您 代码 (大赦国际读到
项目, 写 testforge.md,然后从中起草文件。 这是
快速, 但是它继承了任何代码: 如果流是buggy 或 a
假设处理不当,AI忠实记录错误的行为,
然后把错误的行为锁定起来.
因此,当起草文件时 testforge setup (或 testforge discover——考福奇问,它们应该基于什么:
What should the journey docs be based on?
[1] testforge.md (what the AI derived from your code) (default)
[2] An external reference (a file/PDF in scope, a website, or a Notion link)
选择 [2] 以提供权威参考 预期 行为 — repo 中的规格或要求 doc, PDF, a 网站,或编号页面。 那么测试 forge:
- 阅读参考文献并将其与
testforge.md, (中文(简体) ), - 写一个完整的比较
testforge/reference/diff.md打印一个短 概述差异, - 请你确认,并在确认后确认 从 参考文献 ——预期行为来自参考,而路由, 字段,模型,和env var 名称来自代码/地图,
generate然后像往常一样把这些文件变成测试.
引用成为真理的来源 人类的预期行为
或客户端, 不只是代码的发生。 选择被记住
内 testforge/source.json晚点再说 testforge update 刷新该
同一来源的文档,没有再次询问。 你的回顾
testforge/reference/diff.md 留作对差异和原因的审计.
非交互使用( CI, 脚本) :
testforge setup --source map # base the docs on testforge.md, no prompt
testforge setup --reference ./spec.md # base the docs on a reference, no prompts
testforge setup --reference https://… # a URL or Notion link works too
同样的旗帜工作 testforge discover没有旗帜和终点站
测试 forge不阻断 —— 它回到 testforge.md 财务报告和审定财务报表
打印一个字条.
运行生成的测试
testforge 生成测试和种子文件——您用您的 自己的测试跑者, 你的项目已经做的。 测试 forge 不 为你运行测试; 这使得它在你的测试设置和CI.
典型运行 :
-
提供测试证书. 测试和种子读取了数据库 URL和任何来自环境变量的秘密——从未被硬编码.
testforge setup写入.env.testing.example给你的 它列出了 按区域(api / web / ops)分类, 并用它作记号 特性需要哪些证书,可以跳过 不运行的特性。 例如:
# ========================================
# API
# ========================================
DB_URL= # used by: (all)
TOKEN_SECRET= # used by: auth, user
STRIPE_SECRET_KEY= # used by: payments, subscription
# ========================================
# WEB
# ========================================
StripePublicKey= # used by: payments
复制给 .env.testing,填入真实值,并保存该文件
退出版本控制( 添加到 .gitignore. 重新运行 setup
或者说 update 当代码更改时刷新示例.
注:有些证书不是静态的,例如用户访问/更新 来自登录流的符号。 属于自己的测试机构(a) global setup或 sent step),不在env文件中.
保留此文件脱离版本控制( 添加到 .gitignore) (中文(简体) ). 这个
确切的可变名称来自您自己的代码—— 行程文件
工程地图列出了每个行程需要的 env var 名称.
- 运行种子 将已知的测试数据放入数据库。 运行
种子文件在
seedOutput(参见配置)与您的运行时间, 例如 :
npx tsx path/to/seed/<journey>.seed.ts # or: node <journey>.seed.js
- 运行测试 与项目本身的指令,例如:
# api (Jest)
NODE_ENV=testing npx jest
# web (Playwright)
npx playwright test
试跑者自行制作通关/故障报告.
在 CI( GitHub 动作)
npx testforge ci --github # run only when started by hand
npx testforge ci --github --schedule weekdays # also Mon–Fri 06:00 UTC (daily, weekly or a cron line too)
npx testforge ci --github --env-name staging --force
工作流程运行 testforge run 手动(和时间表,如果给出的话)
并发布每个运行到仪表板。 它读它
来自寄存器密钥的值, 其名称与您的 env 文件相同
(TestForge只读名字,从来不读值),加 TESTFORGE_KEY, (中文(简体) ),
和寄存器变量中的仪表板地址
TESTFORGE_DASHBOARD_URL。在已部署的应用程序中标出基础 URL 秘密.
测试结果作为工作流程文物保存了14天.
配置
testforge setup 写入 testforge.config.json 给你的 你可以编辑其内容:
{
"aiCommand": "claude -p",
"testOutput": {
"api": "packages/api/test",
"web": "packages/webapp/tests",
"ops": "packages/ops/tests"
},
"framework": {
"api": "jest",
"web": "playwright",
"ops": "playwright"
},
"seedOutput": "packages/api/test/helpers/seed",
"testExtension": ".test.ts",
"externalModules": ["shipengine", "@customerio/cdp-analytics"]
}
- 命令 ——CLI曾称AI. 任何读取
由 stdin 提示并打印回覆工作, 因此 testforge 没有绑定
给一个供应商。 测试forge 附加右相旗:
设置阶段( init/ map/ discover) 运行时有编辑权限, 因为
模型写入文件,而生成阶段(测试/种子)运行于
无工具( e)
--allowedTools ""因此,模型只是打印代码 而不是试图创建文件,否则会泄露"the 写作没有被批准... ... - 测试输出 ——每个区域进行测试的地方. 区域没有固定——使用
无论你的项目是什么
api, (中文(简体) ),web, (中文(简体) ),ops, (中文(简体) ),lambda(中文(简体) ). - 框架 每个区域使用的测试框架.
- 种子输出 ——种子文件去的地方.
- 测试 —— 说
.test.ts或者说.test.js。 。 。 . - 外部模块 ——第三方网络服务项目 以测试方式命名的会谈将导入它们。 生成后端测试 在不嘲弄的情况下进口的,在写作前被拒绝: 单枪匹马会到达现场 所以断线 可以发射真实的电费、信息或货运。 试 forge 已经知道 常见的 SDKs(支付,短信,电子邮件,云,身份),此列表是 在他们身上添加,永远不要代替他们——所以只点出具体的名字 你的产品。 每一个领域都有一些东西: 一个航运公司,一个CMS, 一个售票或流出后端,一个广告网络.
- 相关数字 ——其他重置此项目取决于,只读,例如.
["../backend"]一个前端的API和数据库在隔壁. 每个AI相相可以读取它们,所以地图可以捕捉真实的数据层和 测试可以检查API存储什么. 无头跑不能在外边读 否则,项目. - 决定 - 列出尚不构成要求的文件或链接: 公开产品决定和已知问题被故意忽略。 医生没有 把它们变成标准 一个失败的测试 属于一个 报告为待决决定,绝不是缺陷。 保留引用 您与一个客户端共享干净, 而测试仍然知道什么是未知的.
怎么样 generate 降低人工智能成本
旅行医生被读过一次 并保留为旅程的 内存
(单位:千美元)testforge/memory/<area>/<id>/其规则及其来源、水平、测试和
历史,计划和密码事实。 以后再不派医生来.
- 规矩. 医生被分为规则(R1,R2.),没有AI. 规则编号留下 当医生改变时稳定。 每个规则都记录它的源,文件 测试它,为什么它被跳过, 以及它以前的措辞.
- 计划,没有AI. 医生的每个编号区域变成一个测试文件
(单位:千美元)
"planner": "ai"请求大赦国际。 规则另一个旅程已经测试 不再计划。 计划检查plan-check.md列出所有规则 得到测试,每个跳跃 及其原因,和任何 必须 排除了这一点. - 密码事实,一次. 医生指向的资料来源(它引用的文件、 其控件以下列名称命名: 在没有AI的情况下收集,并在一个电话中概述.
- 写作. 每次通话都会写出一些文件(
filesPerCall,默认 3)和 (c) 仅获得其规则、其控制事实和测试设备的出口 编写测试的共享规则是一个缓存系统提示 。 测试查找每个 元素为kit.find(page, kind, name),检查结果而不是标记, 并断绝他们不能创造的状态. - 检查之前,任何事情运行. 文件被拒绝, 并再次写入
如果它睡了一段时间,就跳过,因为元素是
缺少,没有测试或没有断言,花费超过
maxTestsPerRule在一条规则上进行测试,或者在代码和医生中找不到的标签名称. - 每一个规则,一个可以失败的测试. 每个场景都来自医生
(加上边缘、安全和用户案例 TestForge 添加); 代码是什么
或缺乏 永远不会删除一个。 每一次测试都单独检查:每一次计划
规则有一个测试,或者——只有当它需要外部服务时,测试
无法驱动( 付款提供者在内部, 电子邮件收件箱, 另一个应用程序) ——
(单位:千美元)
// cannot-test: R7 — <the service>线条; 没有断言接受好结果和坏结果 整个文本,只坐在一个if,或重复它自己的根部返回的东西;kit.find正在等待并按屏幕显示的名称查找元素;kit.openStep标出测试Kit的一步 。 检查失败的测试是 他们的规矩又用一个小电话写出来 错误被删除并报告。 总结线说有多少计划规则 有测试,不能在这里测试 和为什么,没有rules.json编号 :plan-check.md记录相同. - 医生换了. 仅被触摸到的更改: 重命名的标签被替换 在测试中,删除一条删除的规则的测试(两者均无AI); a 重新措辞或新规则的测试用一个小调写成.
名称 产品给出. 测试通过名称到达产品:a
路径、按钮的标签、命令、表格或字段。 当代码已经
有一个,测试用它。 当它没有(仍然是),测试要求用一个
普通名称 - need('order summary URL') 从
@activate-core/test-forge/reporters/interface.cjs - 名字已经列出
内 testforge/interface.json 带有空值。 开发者填充一次
它的存在; testforge run 财务报告和审定财务报表 bind 拖放文件, 列出它等待什么
因为,而它的一个名字是空的。 TestForge 从未覆盖一个值 .
每跑一步的人工智能成本(写作、打地、种子、用具.)结束.
还没活下来的特征. 打开 Status: not built 或者说
Status: behind flag <name> 在旅行医生的头。 每一个文件
行程已印出 // testforge-pending: …,以及 testforge run (和 bind(中文(简体) )
把它挡住,直到线被取出; --all 运行它反正。 没有种子被写入它:它的测试会制作自己的数据.
generate 运行什么. testforge run 运行套房; testforge review
当你要求的时候 判断失败.
每一次Claude的通话都报告其实际用途和成本; TESTFORGE_TRACE=1
记录每个电话的快速和事件 testforge/runs/trace/。 。 。 .
项目状态
所有测试Forge的生活 testforge/提交,但 runs/
(运行输出和AI日志):一个从你的记忆,计划开始拉动的队友
而不是再付钱 由老人创办的项目
版本从 test-artifacts/ 在第一个命令.
页:1
- 生成的测试和docs是一个很强的草稿,而不是最终的. 检查一下. 如果无法证实某事,则将进行测试 说明(和仪表板).
- 秘密从不写给文件、配置或测试 连接使用 环境变量名称; 真实值来自您 运行时的环境.
许可证
麻省理工学院