cj-vana/buttonmash

GitHub: cj-vana/buttonmash

一个基于 Playwright 的 Web 应用 CI 混沌测试工具,通过自动抓取页面并模拟随机交互来发现崩溃和错误,在检测到故障时导致构建失败。

Stars: 0 | Forks: 0

# 🐒 buttonmash [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/cj-vana/buttonmash/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/buttonmash.svg)](https://www.npmjs.com/package/buttonmash) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) **一个用于 web 应用的 CI 混沌猴子。** 将它指向你的网站,它就会**自动抓取每一个 页面** —— 在此过程中发现链接和站内 (SPA) 导航 —— 然后在每个页面上找到每一个按钮/链接/输入框并“狂按”它们:点击、 双击、输入随机按键、选择、滚动、调整大小、 导航。它甚至能**完成创建流程** —— 使用有效数据填写表单 并提交 —— 这样空应用就能自行填充数据,深层编辑器也能得到 测试。当出现故障(未捕获的错误、500 错误、崩溃、白屏、 图片损坏……)时,它会生成一份报告并**导致你的构建失败**。 它是确定性的(基于种子,因此任何故障都可以重现)、有边界的(受限于操作/时间 预算),并且**默认安全**:它会留在你的源站内,跳过破坏性 控件,拒绝针对真实的支付密钥运行,并对敏感信息进行脱敏处理。 ``` npx buttonmash run https://staging.example.com ``` ## 为什么使用 现有的页面内猴子工具(如 gremlins.js 等)会注入合成事件,并且 **永远不会真正导致你的 CI 失败** —— 它们只是将日志打印到控制台。buttonmash 彻底改变了这一点:它使用 Playwright 从 **harness** 端驱动页面,因此它 掌控着判定结果和退出代码。它还会枚举真实的元素(因此它能点击到 屏幕可视区域下方的按钮,这与基于坐标的点击器不同),分发**受信任的** 输入,并将发现的问题去重,生成一份带有可重现 种子的、可操作的报告。 ## 安装 ``` npm install --save-dev buttonmash npx playwright install --with-deps chromium # one-time browser install ``` 要求 Node 20+。 ## 快速开始 ``` # 1. (可选) 捕获已认证的 session — 打开浏览器,由你进行登录 npx buttonmash auth https://staging.example.com/login # → 将 cookies/localStorage 保存到 playwright/.auth/user.json # 2. 搭建一个 config (可选) npx buttonmash init # 3. 运行它 npx buttonmash run https://staging.example.com --auth playwright/.auth/user.json # 4. 精确重现一次失败 (每次运行都会打印出 seed) npx buttonmash run https://staging.example.com --seed ``` 当运行结束时,你会得到一个 `buttonmash-report/` 文件夹,其中包含 `report.html` (独立文件)、`results.json` 和 `junit.xml`。如果出现达到或高于你的失败阈值的错误,退出代码将为 `1`。 ## 在 CI 中使用 (GitHub Actions) 最快的方法是使用内置的 composite action(它会安装浏览器 + 运行 buttonmash + 上传报告): ``` name: buttonmash on: [pull_request] jobs: buttonmash: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v5 # start your app under test here (e.g. npm ci && npm run start &) and wait for it… - uses: cj-vana/buttonmash@v0.1.8 with: target: http://localhost:3000 args: --seed ci --max-actions 800 ``` 或者手动配置以获得完全控制权: ``` name: buttonmash on: [pull_request] jobs: buttonmash: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: { node-version: 20, cache: npm } - run: npm ci - run: npx playwright install --with-deps chromium # start your app under test here (e.g. npm run start &) and wait for it… - run: npx buttonmash run http://localhost:3000 --seed ci --fail-on high env: # storageState captured locally and stored as a secret (base64 or file) STORAGE_STATE: ${{ secrets.BUTTONMASH_STORAGE_STATE }} - uses: actions/upload-artifact@v5 if: ${{ !cancelled() }} with: { name: buttonmash-report, path: buttonmash-report/ } ``` buttonmash 会自动检测 GitHub Actions,并发出行内注释以及 job-summary 表格。非零的退出代码将导致 job 失败。 ## 抓取整个站点 默认情况下,buttonmash 会**自动抓取**:从你的目标开始,它会发现 每一个同源的 `` 链接,*以及*应用通过按钮/`navigate()` 导航到的 每一个客户端路由(它会 hook `pushState`/`popstate`),将它们 加入队列,并按广度优先顺序进行处理。当链接边界耗尽时,它 会返回起点并继续点击 —— 因此由按钮驱动的 SPA 外壳(其导航 不是 ``)仍然能被完全覆盖。一次运行,覆盖整个可达站点: ``` npx buttonmash run https://staging.example.com # crawls everything it can reach ``` 控制项: - `budget.maxPages` — 每次运行中不同页面的上限(默认为 100),从而保证 CI 受到限制。 - `routes` — 可选的**提示**:没有任何链接指向的页面(例如深层编辑器的 URL)。 它们会作为初始边界;抓取过程会发现其余的页面。也可以通过 `--route ` 设置。 - `explore.crawl: false` — 禁用自动抓取,仅扫描 `target` 和 `routes`。 危险路径(登出/删除/取消)和非同源 URL 永远不会被加入队列。 基于 Hash 路由的 SPA 享有头等支持:`#/route` 和 `#!/route` 片段在 边界和统计信息中被视为不同的页面(普通的 `#anchor` 片段则不会),并且 像 `blockedPathPatterns` 这样的路径守卫同样适用于 hash 路由 —— `#/account/delete` 链接的守卫方式与 `/account/delete` 完全一样。 发现机制甚至能深入**打开的 shadow DOM** 内部(web 组件设计系统 —— Salesforce LWC、Ionic、Shoelace/Lit/Material Web)以及**同源的 iframe** (内嵌编辑器、向导),因此基于组件的应用对它来说也不会是隐形的。 它专为在漫长的 CI 扫描中存活于杂乱的真实应用而构建:它可以**从 渲染器崩溃中恢复**(重新创建页面并继续运行,跳过崩溃的页面),打开 **自定义 ARIA 下拉菜单** 并选择一个选项,**拒绝文件 选择器** 以免 file input 挂起运行,并且你可以使用 `guardrails.includePaths` / `excludePaths` 来**限制抓取范围**。 ## 自填充(表单完成) 一个全新的应用大多是空列表 —— 因此 buttonmash 会**创建自己的数据**。当 它找到一个可填写的表单(或打开了一个“新建/添加/创建”流程)时,它会填写每一个 必填字段 —— 以及一部分可选字段 —— 使用根据每个字段的类型/标签/模式/最值/选项推断出的 **有效的、确定性的** 值(真实的电子邮件、在范围内的数字、基于种子的日期、选定的 `