snapdiff-cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,242 +1,242 @@
1
- <p align="center">
2
- <h1 align="center">snapdiff</h1>
3
- <p align="center">一行命令的视觉回归测试工具</p>
4
- <p align="center">
5
- <a href="https://www.npmjs.com/package/snapdiff-cli"><img src="https://img.shields.io/npm/v/snapdiff-cli" alt="npm"></a>
6
- <a href="https://github.com/zixuanlongxi/snapdiff"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license"></a>
7
- </p>
8
- </p>
9
-
10
- ---
11
-
12
- ## 概述
13
-
14
- **snapdiff** 是一个基于 Playwright + pixelmatch 的视觉回归测试工具。你在改代码前截一张基线截图,改完代码后再截一张,它会告诉你**哪些地方变了、变了多少**,并生成可直观对比的 HTML 报告。
15
-
16
- 适合场景:
17
-
18
- - 改 CSS/组件后检查是否有意外的布局变化
19
- - PR 提交前自动对比视觉差异
20
- - CI 流水线中集成视觉回归检查
21
-
22
- ---
23
-
24
- ## 快速开始
25
-
26
- ```bash
27
- # 初始化项目(交互式向导,自动完成首次截图)
28
- npx snapdiff-cli init
29
-
30
- # 修改代码后,对比变化
31
- npx snapdiff-cli diff
32
-
33
- # 查看基线状态
34
- npx snapdiff-cli status
35
-
36
- # 确认变更,更新基线
37
- npx snapdiff-cli approve <name>
38
- ```
39
-
40
- 第一次运行 `init` 会自动:
41
-
42
- 1. 创建配置文件 `snapdiff.config.json`
43
- 2. 截取首张基线截图
44
- 3. 将 `.snapdiff/diffs/` 和 `.snapdiff/reports/` 加入 `.gitignore`
45
-
46
- ---
47
-
48
- ## 命令参考
49
-
50
- ### `init`
51
-
52
- 初始化 snapdiff 配置(交互式向导,自动完成首次截图)。
53
-
54
- ```bash
55
- npx snapdiff-cli init # 交互式
56
- npx snapdiff-cli init --yes # 非交互式,使用默认值
57
- npx snapdiff-cli init --yes --ci # 非交互式 + 生成 CI 配置文件
58
- ```
59
-
60
- 如果 stdin 不是终端(例如在 CI 环境中),`init` 会自动切换为非交互模式。
61
-
62
- ### `capture`
63
-
64
- 截取当前页面作为基线截图。
65
-
66
- ```bash
67
- # 从配置文件批量截取
68
- npx snapdiff-cli capture
69
-
70
- # 截取单个页面
71
- npx snapdiff-cli capture https://example.com --name my-page
72
-
73
- # 指定选择器:等待元素出现后再截图
74
- npx snapdiff-cli capture https://example.com --name home --selector "#app-root"
75
-
76
- # 自定义视口大小
77
- npx snapdiff-cli capture https://example.com --name mobile -w 375 -h 812
78
- ```
79
-
80
- 多页面模式下自动 **3 并发** 并行截图。
81
-
82
- ### `diff`
83
-
84
- 对比当前页面与基线截图。
85
-
86
- ```bash
87
- # 对比配置文件中的所有页面(并行截图 + HTML 报告)
88
- npx snapdiff-cli diff
89
-
90
- # 对比单个页面
91
- npx snapdiff-cli diff https://example.com --name my-page
92
-
93
- # 设置更宽松的阈值(允许 0.5% 以内的差异)
94
- npx snapdiff-cli diff -t 0.5
95
- ```
96
-
97
- 运行后自动生成 **HTML 报告** 到 `.snapdiff/reports/` 目录,可直接用浏览器打开查看。
98
-
99
- ### `approve`
100
-
101
- 接受当前差异为新基线(覆盖旧基线)。
102
-
103
- ```bash
104
- npx snapdiff-cli approve my-page
105
- ```
106
-
107
- 即使配置文件中没有定义该页面,也会尝试从基线元数据中恢复 URL。
108
-
109
- ### `status`
110
-
111
- 查看所有基线状态(表格展示)。
112
-
113
- ```bash
114
- npx snapdiff-cli status
115
- ```
116
-
117
- 输出示例:
118
-
119
- ```
120
- 📸 snapdiff 基线状态
121
-
122
- 名称 URL 基线时间 状态
123
- ──────────────────────────────────────────────────────────────────────────────────────────
124
- homepage https://example.com 2026/6/5 10:30 ✅ 正常
125
- pricing https://example.com/pricing 2026/6/5 10:31 ✅ 正常
126
- dashboard https://example.com/dashboard — ⚠ 未截取
127
- ```
128
-
129
- ---
130
-
131
- ## 配置文件
132
-
133
- 在项目根目录创建 `snapdiff.config.json`:
134
-
135
- ```json
136
- {
137
- "snaps": [
138
- {
139
- "name": "homepage",
140
- "url": "https://example.com",
141
- "viewport": { "width": 1440, "height": 900 },
142
- "threshold": 0.1
143
- },
144
- {
145
- "name": "pricing",
146
- "url": "https://example.com/pricing",
147
- "selector": "#app-root",
148
- "viewport": { "width": 1440, "height": 900 },
149
- "threshold": 0.1
150
- }
151
- ]
152
- }
153
- ```
154
-
155
- | 字段 | 类型 | 必填 | 说明 |
156
- |---|---|---|---|
157
- | `name` | string | 是 | 截图名称,用于标识 |
158
- | `url` | string | 是 | 页面 URL |
159
- | `selector` | string | 否 | 等待该 CSS 选择器出现后再截图 |
160
- | `viewport` | object | 否 | 视口大小,默认 `{ width: 1440, height: 900 }` |
161
- | `threshold` | number | 否 | 差异阈值百分比,默认 `0.1`,超出则判定失败 |
162
-
163
- ---
164
-
165
- ## 目录结构
166
-
167
- ```
168
- 项目根目录/
169
- ├── snapdiff.config.json # 配置文件
170
- ├── .gitignore # 自动添加 .snapdiff/diffs/ 和 .snapdiff/reports/
171
- └── .snapdiff/
172
- ├── baselines/ # 基线截图(需纳入 git 管理)
173
- │ ├── homepage.png
174
- │ └── homepage.json # 元数据(URL、视口、时间等)
175
- ├── diffs/ # 差异对比图(已加入 .gitignore)
176
- │ └── homepage-1234567890-diff.png
177
- └── reports/ # HTML 报告(已加入 .gitignore)
178
- └── report-1234567890.html
179
- ```
180
-
181
- 基线截图纳入 git 管理,这样 PR diff 里可以直接看到图片变化。差异图和报告不纳入 git。
182
-
183
- ---
184
-
185
- ## CI 集成
186
-
187
- ### GitHub Actions
188
-
189
- ```yaml
190
- # .github/workflows/snapdiff.yml
191
- name: Visual Regression Test
192
- on: [pull_request]
193
- jobs:
194
- snapdiff:
195
- runs-on: ubuntu-latest
196
- steps:
197
- - uses: actions/checkout@v4
198
- - uses: actions/setup-node@v4
199
- with:
200
- node-version: 20
201
- - run: npx snapdiff-cli diff
202
- ```
203
-
204
- 也可以通过 `init --ci` 自动生成:
205
-
206
- ```bash
207
- npx snapdiff-cli init --yes --ci
208
- ```
209
-
210
- ---
211
-
212
- ## 技术栈
213
-
214
- | 组件 | 用途 |
215
- |---|---|
216
- | [Playwright](https://playwright.dev) | 浏览器截图引擎 |
217
- | [pixelmatch](https://github.com/mapbox/pixelmatch) | 像素级对比 |
218
- | [pngjs](https://github.com/lukeapage/pngjs) | PNG 图片处理 |
219
- | [commander](https://github.com/tj/commander.js) | CLI 框架 |
220
-
221
- ---
222
-
223
- ## 开发
224
-
225
- ```bash
226
- git clone <repo>
227
- cd snapdiff
228
-
229
- # 依赖已内置于 CLI 包
230
- cd packages/cli
231
- npm install
232
- npm run build
233
-
234
- # 本地测试
235
- node dist/index.js --help
236
- ```
237
-
238
- ---
239
-
240
- ## 许可证
241
-
1
+ <p align="center">
2
+ <h1 align="center">snapdiff</h1>
3
+ <p align="center">一行命令的视觉回归测试工具</p>
4
+ <p align="center">
5
+ <a href="https://www.npmjs.com/package/snapdiff-cli"><img src="https://img.shields.io/npm/v/snapdiff-cli" alt="npm"></a>
6
+ <a href="https://github.com/zixuanlongxi/snapdiff"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license"></a>
7
+ </p>
8
+ </p>
9
+
10
+ ---
11
+
12
+ ## 概述
13
+
14
+ **snapdiff** 是一个基于 Playwright + pixelmatch 的视觉回归测试工具。你在改代码前截一张基线截图,改完代码后再截一张,它会告诉你**哪些地方变了、变了多少**,并生成可直观对比的 HTML 报告。
15
+
16
+ 适合场景:
17
+
18
+ - 改 CSS/组件后检查是否有意外的布局变化
19
+ - PR 提交前自动对比视觉差异
20
+ - CI 流水线中集成视觉回归检查
21
+
22
+ ---
23
+
24
+ ## 快速开始
25
+
26
+ ```bash
27
+ # 初始化项目(交互式向导,自动完成首次截图)
28
+ npx snapdiff-cli init
29
+
30
+ # 修改代码后,对比变化
31
+ npx snapdiff-cli diff
32
+
33
+ # 查看基线状态
34
+ npx snapdiff-cli status
35
+
36
+ # 确认变更,更新基线
37
+ npx snapdiff-cli approve <name>
38
+ ```
39
+
40
+ 第一次运行 `init` 会自动:
41
+
42
+ 1. 创建配置文件 `snapdiff.config.json`
43
+ 2. 截取首张基线截图
44
+ 3. 将 `.snapdiff/diffs/` 和 `.snapdiff/reports/` 加入 `.gitignore`
45
+
46
+ ---
47
+
48
+ ## 命令参考
49
+
50
+ ### `init`
51
+
52
+ 初始化 snapdiff 配置(交互式向导,自动完成首次截图)。
53
+
54
+ ```bash
55
+ npx snapdiff-cli init # 交互式
56
+ npx snapdiff-cli init --yes # 非交互式,使用默认值
57
+ npx snapdiff-cli init --yes --ci # 非交互式 + 生成 CI 配置文件
58
+ ```
59
+
60
+ 如果 stdin 不是终端(例如在 CI 环境中),`init` 会自动切换为非交互模式。
61
+
62
+ ### `capture`
63
+
64
+ 截取当前页面作为基线截图。
65
+
66
+ ```bash
67
+ # 从配置文件批量截取
68
+ npx snapdiff-cli capture
69
+
70
+ # 截取单个页面
71
+ npx snapdiff-cli capture https://example.com --name my-page
72
+
73
+ # 指定选择器:等待元素出现后再截图
74
+ npx snapdiff-cli capture https://example.com --name home --selector "#app-root"
75
+
76
+ # 自定义视口大小
77
+ npx snapdiff-cli capture https://example.com --name mobile -w 375 -h 812
78
+ ```
79
+
80
+ 多页面模式下自动 **3 并发** 并行截图。
81
+
82
+ ### `diff`
83
+
84
+ 对比当前页面与基线截图。
85
+
86
+ ```bash
87
+ # 对比配置文件中的所有页面(并行截图 + HTML 报告)
88
+ npx snapdiff-cli diff
89
+
90
+ # 对比单个页面
91
+ npx snapdiff-cli diff https://example.com --name my-page
92
+
93
+ # 设置更宽松的阈值(允许 0.5% 以内的差异)
94
+ npx snapdiff-cli diff -t 0.5
95
+ ```
96
+
97
+ 运行后自动生成 **HTML 报告** 到 `.snapdiff/reports/` 目录,可直接用浏览器打开查看。
98
+
99
+ ### `approve`
100
+
101
+ 接受当前差异为新基线(覆盖旧基线)。
102
+
103
+ ```bash
104
+ npx snapdiff-cli approve my-page
105
+ ```
106
+
107
+ 即使配置文件中没有定义该页面,也会尝试从基线元数据中恢复 URL。
108
+
109
+ ### `status`
110
+
111
+ 查看所有基线状态(表格展示)。
112
+
113
+ ```bash
114
+ npx snapdiff-cli status
115
+ ```
116
+
117
+ 输出示例:
118
+
119
+ ```
120
+ 📸 snapdiff 基线状态
121
+
122
+ 名称 URL 基线时间 状态
123
+ ──────────────────────────────────────────────────────────────────────────────────────────
124
+ homepage https://example.com 2026/6/5 10:30 ✅ 正常
125
+ pricing https://example.com/pricing 2026/6/5 10:31 ✅ 正常
126
+ dashboard https://example.com/dashboard — ⚠ 未截取
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 配置文件
132
+
133
+ 在项目根目录创建 `snapdiff.config.json`:
134
+
135
+ ```json
136
+ {
137
+ "snaps": [
138
+ {
139
+ "name": "homepage",
140
+ "url": "https://example.com",
141
+ "viewport": { "width": 1440, "height": 900 },
142
+ "threshold": 0.1
143
+ },
144
+ {
145
+ "name": "pricing",
146
+ "url": "https://example.com/pricing",
147
+ "selector": "#app-root",
148
+ "viewport": { "width": 1440, "height": 900 },
149
+ "threshold": 0.1
150
+ }
151
+ ]
152
+ }
153
+ ```
154
+
155
+ | 字段 | 类型 | 必填 | 说明 |
156
+ |---|---|---|---|
157
+ | `name` | string | 是 | 截图名称,用于标识 |
158
+ | `url` | string | 是 | 页面 URL |
159
+ | `selector` | string | 否 | 等待该 CSS 选择器出现后再截图 |
160
+ | `viewport` | object | 否 | 视口大小,默认 `{ width: 1440, height: 900 }` |
161
+ | `threshold` | number | 否 | 差异阈值百分比,默认 `0.1`,超出则判定失败 |
162
+
163
+ ---
164
+
165
+ ## 目录结构
166
+
167
+ ```
168
+ 项目根目录/
169
+ ├── snapdiff.config.json # 配置文件
170
+ ├── .gitignore # 自动添加 .snapdiff/diffs/ 和 .snapdiff/reports/
171
+ └── .snapdiff/
172
+ ├── baselines/ # 基线截图(需纳入 git 管理)
173
+ │ ├── homepage.png
174
+ │ └── homepage.json # 元数据(URL、视口、时间等)
175
+ ├── diffs/ # 差异对比图(已加入 .gitignore)
176
+ │ └── homepage-1234567890-diff.png
177
+ └── reports/ # HTML 报告(已加入 .gitignore)
178
+ └── report-1234567890.html
179
+ ```
180
+
181
+ 基线截图纳入 git 管理,这样 PR diff 里可以直接看到图片变化。差异图和报告不纳入 git。
182
+
183
+ ---
184
+
185
+ ## CI 集成
186
+
187
+ ### GitHub Actions
188
+
189
+ ```yaml
190
+ # .github/workflows/snapdiff.yml
191
+ name: Visual Regression Test
192
+ on: [pull_request]
193
+ jobs:
194
+ snapdiff:
195
+ runs-on: ubuntu-latest
196
+ steps:
197
+ - uses: actions/checkout@v4
198
+ - uses: actions/setup-node@v4
199
+ with:
200
+ node-version: 20
201
+ - run: npx snapdiff-cli diff
202
+ ```
203
+
204
+ 也可以通过 `init --ci` 自动生成:
205
+
206
+ ```bash
207
+ npx snapdiff-cli init --yes --ci
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 技术栈
213
+
214
+ | 组件 | 用途 |
215
+ |---|---|
216
+ | [Playwright](https://playwright.dev) | 浏览器截图引擎 |
217
+ | [pixelmatch](https://github.com/mapbox/pixelmatch) | 像素级对比 |
218
+ | [pngjs](https://github.com/lukeapage/pngjs) | PNG 图片处理 |
219
+ | [commander](https://github.com/tj/commander.js) | CLI 框架 |
220
+
221
+ ---
222
+
223
+ ## 开发
224
+
225
+ ```bash
226
+ git clone <repo>
227
+ cd snapdiff
228
+
229
+ # 依赖已内置于 CLI 包
230
+ cd packages/cli
231
+ npm install
232
+ npm run build
233
+
234
+ # 本地测试
235
+ node dist/index.js --help
236
+ ```
237
+
238
+ ---
239
+
240
+ ## 许可证
241
+
242
242
  MIT
package/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
- #!/usr/bin/env node
2
1
  export {};
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
- #!/usr/bin/env node
1
+ import { createRequire } from "module";
2
+ const require = createRequire(import.meta.url);
3
+ const pkg = require("../package.json");
2
4
  import { Command } from "commander";
3
5
  import pc from "picocolors";
4
6
  import { initCommand } from "./commands/init.js";
@@ -6,36 +8,33 @@ import { captureCommand } from "./commands/capture.js";
6
8
  import { diffCommand } from "./commands/diff.js";
7
9
  import { approveCommand } from "./commands/approve.js";
8
10
  import { statusCommand } from "./commands/status.js";
9
- // Global error handler — prevent raw stack traces from leaking to users
11
+ // Global error handler
10
12
  process.on("unhandledRejection", (err) => {
11
13
  const msg = err instanceof Error ? err.message : String(err);
12
14
  console.error(pc.red(`\n ⚠ 意外错误: ${msg}`));
13
- console.error(pc.dim(` 如需帮助,请提供以上完整输出来排查问题。`));
15
+ console.error(pc.dim(" 如需帮助,请提供以上完整输出来排查问题。"));
14
16
  process.exit(1);
15
17
  });
16
18
  process.on("uncaughtException", (err) => {
17
19
  console.error(pc.red(`\n ⚠ 意外错误: ${err.message}`));
18
- console.error(pc.dim(` 如需帮助,请提供以上完整输出来排查问题。`));
20
+ console.error(pc.dim(" 如需帮助,请提供以上完整输出来排查问题。"));
19
21
  process.exit(1);
20
22
  });
21
- // Detect non-TTY stdin early — e.g. piped input in CI
22
23
  const isInteractive = process.stdin.isTTY;
23
24
  const program = new Command();
24
25
  program
25
26
  .name("snapdiff")
26
27
  .description(pc.cyan("一行命令的视觉回归测试工具"))
27
- .version("0.1.0");
28
+ .version(pkg.version);
28
29
  program
29
30
  .command("init")
30
31
  .description("初始化 snapdiff 配置(交互式向导,自动完成首次截图)")
31
32
  .option("--ci", "同时生成 GitHub Action 配置文件")
32
33
  .option("--yes", "跳过交互提问,使用默认值")
33
- .addHelpText("after", pc.dim(`\n示例:\n $ snapdiff init\n $ snapdiff init --yes 非交互式,快速初始化\n $ snapdiff init --yes --ci 非交互式 + CI 配置\n`))
34
+ .addHelpText("after", pc.dim("\n示例:\n $ snapdiff init\n $ snapdiff init --yes 非交互式,快速初始化\n $ snapdiff init --yes --ci 非交互式 + CI 配置\n"))
34
35
  .action((opts) => {
35
- // If stdin is not a TTY and --yes not given, auto-enable --yes to avoid hanging
36
- if (!isInteractive && !opts.yes) {
36
+ if (!isInteractive && !opts.yes)
37
37
  opts.yes = true;
38
- }
39
38
  initCommand(opts);
40
39
  });
41
40
  program
@@ -46,7 +45,7 @@ program
46
45
  .option("-s, --selector <selector>", "等页面中该元素出现后再截图,如 #app-root")
47
46
  .option("-w, --width <width>", "视口宽度", "1440")
48
47
  .option("-h, --height <height>", "视口高度", "900")
49
- .addHelpText("after", pc.dim(`\n示例:\n $ snapdiff capture 从配置文件批量截取\n $ snapdiff capture https://ex.com -n my-page 截取单个页面\n $ snapdiff capture https://ex.com -n home -s #main\n`))
48
+ .addHelpText("after", pc.dim("\n示例:\n $ snapdiff capture 从配置文件批量截取\n $ snapdiff capture https://ex.com -n my-page 截取单个页面\n $ snapdiff capture https://ex.com -n home -s #main\n"))
50
49
  .action(captureCommand);
51
50
  program
52
51
  .command("diff")
@@ -54,18 +53,18 @@ program
54
53
  .argument("[url]", "页面 URL")
55
54
  .option("-n, --name <name>", "截图名称")
56
55
  .option("-t, --threshold <threshold>", "允许的差异阈值百分比,超出即判定为失败", "0.1")
57
- .addHelpText("after", pc.dim(`\n示例:\n $ snapdiff diff 对比配置文件中的所有页面\n $ snapdiff diff https://ex.com -n my-page 对比单个页面\n $ snapdiff diff -t 0.5 设置更宽松的阈值\n`))
56
+ .addHelpText("after", pc.dim("\n示例:\n $ snapdiff diff 对比配置文件中的所有页面\n $ snapdiff diff https://ex.com -n my-page 对比单个页面\n $ snapdiff diff -t 0.5 设置更宽松的阈值\n"))
58
57
  .action(diffCommand);
59
58
  program
60
59
  .command("approve")
61
60
  .description("接受当前差异为新基线(覆盖旧基线)")
62
61
  .argument("<name>", "截图名称(必填)")
63
- .addHelpText("after", pc.dim(`\n示例:\n $ snapdiff approve my-page 将我页面的新状态设为基线\n`))
62
+ .addHelpText("after", pc.dim("\n示例:\n $ snapdiff approve my-page 将我页面的新状态设为基线\n"))
64
63
  .action(approveCommand);
65
64
  program
66
65
  .command("status")
67
66
  .description("查看所有基线状态(表格展示)")
68
- .addHelpText("after", pc.dim(`\n示例:\n $ snapdiff status 查看哪些页面有基线,哪些还未截取\n`))
67
+ .addHelpText("after", pc.dim("\n示例:\n $ snapdiff status 查看哪些页面有基线,哪些还未截取\n"))
69
68
  .action(statusCommand);
70
69
  program.addHelpText("afterAll", `
71
70
  ${pc.bold("快速开始")}:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
- {
1
+ {
2
2
  "name": "snapdiff-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "????????????????????????? Playwright + pixelmatch",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,4 +47,4 @@
47
47
  "diff",
48
48
  "cli"
49
49
  ]
50
- }
50
+ }