web-corders-vrt 0.1.1
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/.claude/settings.local.json +13 -0
- package/README.md +169 -0
- package/bin/vrt.ts +77 -0
- package/dist/bin/vrt.js +917 -0
- package/dist/bin/vrt.js.map +1 -0
- package/package.json +46 -0
- package/src/commands/init.ts +82 -0
- package/src/commands/run.ts +259 -0
- package/src/constants.ts +39 -0
- package/src/core/comparator.ts +95 -0
- package/src/core/region-detector.ts +277 -0
- package/src/core/screenshotter.ts +137 -0
- package/src/core/stabilizer.ts +59 -0
- package/src/reporters/html.ts +163 -0
- package/src/reporters/json.ts +15 -0
- package/src/reporters/terminal.ts +86 -0
- package/src/schemas.ts +16 -0
- package/src/types/pixelmatch.d.ts +22 -0
- package/src/types.ts +117 -0
- package/test/comparator.test.ts +153 -0
- package/test/region-detector.test.ts +147 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +15 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npx tsup)",
|
|
5
|
+
"Bash(node dist/bin/vrt.js --help)",
|
|
6
|
+
"Bash(node dist/bin/vrt.js run --help)",
|
|
7
|
+
"Bash(node dist/bin/vrt.js init --help)",
|
|
8
|
+
"Bash(npm install -D prettier)",
|
|
9
|
+
"Bash(npx prettier --write .)",
|
|
10
|
+
"Bash(npm test)"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# web-corders-vrt
|
|
2
|
+
|
|
3
|
+
Webページのビジュアルリグレッションテスト (VRT) を行うCLIツール。
|
|
4
|
+
|
|
5
|
+
本番環境と開発環境のスクリーンショットをピクセル単位で比較し、差分を検出する。テスト結果は人間向け(HTMLレポート)とLLM/Claude向け(JSONレポート + diff画像)の両方で出力される。
|
|
6
|
+
|
|
7
|
+
## セットアップ
|
|
8
|
+
|
|
9
|
+
インストール不要。`npx` で直接実行できる。初回のみ Playwright のブラウザが必要:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx playwright install chromium
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 基本的な使い方
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx vrt run \
|
|
19
|
+
--before https://example.com \
|
|
20
|
+
--after http://localhost:3000 \
|
|
21
|
+
--paths /,/about,/pricing
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `--before` — 比較元URL(本番環境)
|
|
25
|
+
- `--after` — 比較先URL(開発環境 / ステージング)
|
|
26
|
+
- `--paths` — テスト対象のページパス(カンマ区切り)
|
|
27
|
+
|
|
28
|
+
実行すると `./vrt-results/` 以下にタイムスタンプ付きのディレクトリが生成され、スクリーンショット・diff画像・レポートが保存される。
|
|
29
|
+
|
|
30
|
+
## 出力
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
vrt-results/2026-02-28T10-00-00/
|
|
34
|
+
├── report.json # JSON レポート(Claude/LLM向け)
|
|
35
|
+
├── report.html # HTML レポート(人間向け・ブラウザで開く)
|
|
36
|
+
└── screenshots/
|
|
37
|
+
├── top--sp--before.png
|
|
38
|
+
├── top--sp--after.png
|
|
39
|
+
├── top--sp--diff.png
|
|
40
|
+
├── top--pc--before.png
|
|
41
|
+
├── top--pc--after.png
|
|
42
|
+
└── top--pc--diff.png
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### JSON レポートの構造
|
|
46
|
+
|
|
47
|
+
```jsonc
|
|
48
|
+
{
|
|
49
|
+
"version": "1.0",
|
|
50
|
+
"summary": {
|
|
51
|
+
"totalTests": 4,
|
|
52
|
+
"passed": 3,
|
|
53
|
+
"failed": 1,
|
|
54
|
+
"overallStatus": "fail",
|
|
55
|
+
},
|
|
56
|
+
"results": [
|
|
57
|
+
{
|
|
58
|
+
"page": { "path": "/about", "name": "about" },
|
|
59
|
+
"viewport": { "type": "sp", "width": 375, "height": 812 },
|
|
60
|
+
"status": "fail",
|
|
61
|
+
"comparison": {
|
|
62
|
+
"diffPercentage": 2.35,
|
|
63
|
+
"diffPixelCount": 12040,
|
|
64
|
+
},
|
|
65
|
+
"diffRegions": [
|
|
66
|
+
{
|
|
67
|
+
"id": 1,
|
|
68
|
+
"boundingBox": { "x": 0, "y": 480, "width": 750, "height": 200 },
|
|
69
|
+
"locationHint": {
|
|
70
|
+
"verticalPosition": "upper",
|
|
71
|
+
"horizontalPosition": "full-width",
|
|
72
|
+
"fromTopPx": 480,
|
|
73
|
+
"estimatedElement": "Likely a hero section or banner",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`diffRegions` の `locationHint` は、差分がページのどの位置にあるかを示す。Claudeがこれを読むことで、修正すべきCSS/HTMLの場所を推定できる。
|
|
83
|
+
|
|
84
|
+
## オプション一覧
|
|
85
|
+
|
|
86
|
+
| オプション | デフォルト | 説明 |
|
|
87
|
+
| -------------------- | ---------- | ----------------------------------------------------------------------- |
|
|
88
|
+
| `--before <url>` | (必須) | 比較元URL(本番環境) |
|
|
89
|
+
| `--after <url>` | (必須) | 比較先URL(開発環境 / ステージング) |
|
|
90
|
+
| `--paths <paths>` | (必須) | テスト対象のページパス(カンマ区切り) |
|
|
91
|
+
| `--threshold <n>` | `0.1` | 差分許容率(%)。これ以下の差分はPASS扱い |
|
|
92
|
+
| `--hide <selectors>` | — | 非表示にするCSSセレクタ(カンマ区切り)。例: `.ad-banner,.cookie-popup` |
|
|
93
|
+
| `--no-html` | — | HTMLレポートを生成しない |
|
|
94
|
+
| `--no-open` | — | HTMLレポートをブラウザで自動的に開かない |
|
|
95
|
+
|
|
96
|
+
ビューポートはSP(375x812)とPC(1440x900)の2種類で固定。フルページスクリーンショットを取得し、結果は `./vrt-results/` に出力される。
|
|
97
|
+
|
|
98
|
+
## 実用的な例
|
|
99
|
+
|
|
100
|
+
### 動的要素を隠してテスト
|
|
101
|
+
|
|
102
|
+
広告バナーやクッキー同意バーなど、毎回変わる要素を非表示にする:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx vrt run \
|
|
106
|
+
--before https://example.com \
|
|
107
|
+
--after http://localhost:3000 \
|
|
108
|
+
--paths / \
|
|
109
|
+
--hide ".cookie-banner,.ad-slot,[data-testid='live-chat']"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 差分許容率を緩めに設定
|
|
113
|
+
|
|
114
|
+
フォントレンダリング差異などを無視したい場合:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx vrt run \
|
|
118
|
+
--before https://example.com \
|
|
119
|
+
--after http://localhost:3000 \
|
|
120
|
+
--paths / \
|
|
121
|
+
--threshold 1
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Claude Code連携
|
|
125
|
+
|
|
126
|
+
`vrt init` コマンドで、Claude Codeのスキルファイル (`.claude/commands/vrt.md`) を自動生成できる。
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx vrt init \
|
|
130
|
+
--before https://example.com \
|
|
131
|
+
--after http://localhost:3000 \
|
|
132
|
+
--paths /,/about,/pricing
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
生成されたファイルをリポジトリにコミットすると、Claude Code上で `/vrt` コマンドを実行するだけで、VRTの実行 → 結果の読み取り → 差分箇所の特定 → コード修正 → 再テストまでを自律的に行えるようになる。
|
|
136
|
+
|
|
137
|
+
### スキルファイルの仕組み
|
|
138
|
+
|
|
139
|
+
生成される `.claude/commands/vrt.md` には以下の手順が記述される:
|
|
140
|
+
|
|
141
|
+
1. 開発サーバーを起動
|
|
142
|
+
2. VRTコマンドを実行
|
|
143
|
+
3. `report.json` を読んで差分を確認
|
|
144
|
+
4. diff画像を視覚的に確認
|
|
145
|
+
5. `locationHint` からCSS/HTMLの修正箇所を特定
|
|
146
|
+
6. コードを修正
|
|
147
|
+
7. 再度VRTを実行して確認
|
|
148
|
+
|
|
149
|
+
## 広告・計測系スクリプトのブロック
|
|
150
|
+
|
|
151
|
+
以下のドメインへのリクエストは自動的にブロックされる。見た目のテストに不要であり、ページ読み込み速度を改善するため。
|
|
152
|
+
|
|
153
|
+
- `googletagmanager.com`
|
|
154
|
+
- `google-analytics.com`
|
|
155
|
+
- `googleadservices.com`
|
|
156
|
+
- `googlesyndication.com`
|
|
157
|
+
- `doubleclick.net`
|
|
158
|
+
- `facebook.net` / `fbcdn.net`
|
|
159
|
+
- `analytics.yahoo.co.jp`
|
|
160
|
+
- `clarity.ms`
|
|
161
|
+
- `hotjar.com`
|
|
162
|
+
- `newrelic.com`
|
|
163
|
+
- `sentry.io`
|
|
164
|
+
- `datadoghq.com`
|
|
165
|
+
|
|
166
|
+
## 動作環境
|
|
167
|
+
|
|
168
|
+
- Node.js 18 以上
|
|
169
|
+
- Playwright Chromium(`npx playwright install chromium` でインストール)
|
package/bin/vrt.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { cliOptionsSchema } from "../src/schemas.js";
|
|
3
|
+
import { runVrt } from "../src/commands/run.js";
|
|
4
|
+
import { runInit } from "../src/commands/init.js";
|
|
5
|
+
import type { ResolvedOptions } from "../src/types.js";
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name("vrt")
|
|
11
|
+
.description("Visual Regression Testing CLI - Compare web pages visually")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command("run")
|
|
16
|
+
.description("Run visual regression tests")
|
|
17
|
+
.requiredOption("--before <url>", "Baseline URL (production)")
|
|
18
|
+
.requiredOption("--after <url>", "Comparison URL (local/staging)")
|
|
19
|
+
.requiredOption("--paths <paths>", "Page paths to compare (comma-separated)")
|
|
20
|
+
.option("--threshold <n>", "Diff tolerance percentage", "0.1")
|
|
21
|
+
.option("--hide <selectors>", "CSS selectors to hide (comma-separated)")
|
|
22
|
+
.option("--no-html", "Skip HTML report generation")
|
|
23
|
+
.option("--no-open", "Do not open HTML report in browser")
|
|
24
|
+
.action(async (rawOptions) => {
|
|
25
|
+
try {
|
|
26
|
+
const parsed = cliOptionsSchema.parse(rawOptions);
|
|
27
|
+
|
|
28
|
+
const options: ResolvedOptions = {
|
|
29
|
+
beforeUrl: parsed.before,
|
|
30
|
+
afterUrl: parsed.after,
|
|
31
|
+
paths: parsed.paths,
|
|
32
|
+
threshold: parsed.threshold,
|
|
33
|
+
hideSelectors: parsed.hide,
|
|
34
|
+
html: parsed.html,
|
|
35
|
+
open: parsed.open,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const report = await runVrt(options);
|
|
39
|
+
process.exit(report.summary.overallStatus === "pass" ? 0 : 1);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof Error) {
|
|
42
|
+
console.error(`Error: ${error.message}`);
|
|
43
|
+
} else {
|
|
44
|
+
console.error("An unexpected error occurred");
|
|
45
|
+
}
|
|
46
|
+
process.exit(2);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command("init")
|
|
52
|
+
.description(
|
|
53
|
+
"Generate .claude/commands/vrt.md skill file for this repository",
|
|
54
|
+
)
|
|
55
|
+
.requiredOption("--before <url>", "Baseline URL (production)")
|
|
56
|
+
.requiredOption("--after <url>", "Comparison URL (local/staging)")
|
|
57
|
+
.requiredOption("--paths <paths>", "Page paths to compare (comma-separated)")
|
|
58
|
+
.option("--threshold <n>", "Diff tolerance percentage", "0.1")
|
|
59
|
+
.option("--hide <selectors>", "CSS selectors to hide (comma-separated)")
|
|
60
|
+
.action(async (options) => {
|
|
61
|
+
try {
|
|
62
|
+
await runInit({
|
|
63
|
+
before: options.before,
|
|
64
|
+
after: options.after,
|
|
65
|
+
paths: options.paths,
|
|
66
|
+
threshold: parseFloat(options.threshold),
|
|
67
|
+
hide: options.hide,
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (error instanceof Error) {
|
|
71
|
+
console.error(`Error: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
program.parse();
|