snapdrift 0.2.0

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.
@@ -0,0 +1,222 @@
1
+ # Integration Guide
2
+
3
+ This guide covers integrating SnapDrift into a consumer repository from a public GitHub release.
4
+
5
+ Examples use the public release tag for readability. If your organization requires immutable pins, resolve the tag to a commit SHA and pin that instead.
6
+
7
+ ## Prerequisites
8
+
9
+ - SnapDrift provisions Node 22 internally.
10
+ - The consumer app can use any stack as long as it can be started and reached at `baseUrl`.
11
+ - The runner must be Ubuntu-compatible because Playwright Chromium is installed with system dependencies.
12
+ - The runner must have outbound network access to fetch Playwright Chromium.
13
+
14
+ Your repository still owns:
15
+
16
+ - Checkout
17
+ - Dependency installation
18
+ - App build
19
+ - App startup and readiness
20
+ - App shutdown
21
+
22
+ SnapDrift owns route selection, capture, comparison, skipped-report generation, artifact staging, artifact upload, PR reporting, and drift enforcement.
23
+
24
+ ## Step 1: Add `.github/snapdrift.json`
25
+
26
+ ```json
27
+ {
28
+ "baselineArtifactName": "my-app-snapdrift-baseline",
29
+ "workingDirectory": ".",
30
+ "baseUrl": "http://127.0.0.1:8080",
31
+ "resultsFile": "qa-artifacts/snapdrift/baseline/current/results.json",
32
+ "manifestFile": "qa-artifacts/snapdrift/baseline/current/manifest.json",
33
+ "screenshotsRoot": "qa-artifacts/snapdrift/baseline/current",
34
+ "routes": [
35
+ { "id": "home-desktop", "path": "/", "viewport": "desktop" },
36
+ { "id": "home-mobile", "path": "/", "viewport": "mobile" }
37
+ ],
38
+ "diff": {
39
+ "threshold": 0.01,
40
+ "mode": "report-only"
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Step 2: Publish a baseline on `main`
46
+
47
+ ```yaml
48
+ - name: SnapDrift Baseline
49
+ uses: ranacseruet/snapdrift/actions/baseline@v0.1.0
50
+ with:
51
+ repo-config-path: .github/snapdrift.json
52
+ artifact-retention-days: '30'
53
+ ```
54
+
55
+ If you want only part of the route set, pass `route-ids`.
56
+
57
+ ## Step 3: Run the pull request report
58
+
59
+ The PR workflow needs permission to download baselines and upsert the report comment:
60
+
61
+ ```yaml
62
+ permissions:
63
+ contents: read
64
+ actions: read
65
+ issues: write
66
+ pull-requests: write
67
+ ```
68
+
69
+ Then add SnapDrift after the app is running:
70
+
71
+ ```yaml
72
+ - name: SnapDrift Report
73
+ uses: ranacseruet/snapdrift/actions/pr-diff@v0.1.0
74
+ with:
75
+ github-token: ${{ secrets.GITHUB_TOKEN }}
76
+ repo-config-path: .github/snapdrift.json
77
+ ```
78
+
79
+ ## Example workflow (Node app)
80
+
81
+ ```yaml
82
+ name: SnapDrift Pull Request
83
+
84
+ on:
85
+ pull_request:
86
+ branches: [main]
87
+
88
+ permissions:
89
+ contents: read
90
+ actions: read
91
+ issues: write
92
+ pull-requests: write
93
+
94
+ jobs:
95
+ snapdrift:
96
+ runs-on: ubuntu-latest
97
+ steps:
98
+ - uses: actions/checkout@v4
99
+ - uses: actions/setup-node@v4
100
+ with:
101
+ node-version: '22'
102
+ cache: npm
103
+ - run: npm ci
104
+ - run: npm run build
105
+
106
+ - name: Start app
107
+ run: |
108
+ npm start &
109
+ for i in $(seq 1 45); do
110
+ curl -sf http://127.0.0.1:8080 && break || sleep 1
111
+ done
112
+
113
+ - name: SnapDrift Report
114
+ uses: ranacseruet/snapdrift/actions/pr-diff@v0.1.0
115
+ with:
116
+ github-token: ${{ secrets.GITHUB_TOKEN }}
117
+ repo-config-path: .github/snapdrift.json
118
+ ```
119
+
120
+ ## Example workflow (Python app)
121
+
122
+ ```yaml
123
+ name: SnapDrift Pull Request
124
+
125
+ on:
126
+ pull_request:
127
+ branches: [main]
128
+
129
+ permissions:
130
+ contents: read
131
+ actions: read
132
+ issues: write
133
+ pull-requests: write
134
+
135
+ jobs:
136
+ snapdrift:
137
+ runs-on: ubuntu-latest
138
+ steps:
139
+ - uses: actions/checkout@v4
140
+ - uses: actions/setup-python@v5
141
+ with:
142
+ python-version: '3.12'
143
+ - run: pip install -r requirements.txt
144
+
145
+ - name: Start app
146
+ run: |
147
+ gunicorn myapp:app --bind 127.0.0.1:8080 &
148
+ for i in $(seq 1 45); do
149
+ curl -sf http://127.0.0.1:8080 && break || sleep 1
150
+ done
151
+
152
+ - name: SnapDrift Report
153
+ uses: ranacseruet/snapdrift/actions/pr-diff@v0.1.0
154
+ with:
155
+ github-token: ${{ secrets.GITHUB_TOKEN }}
156
+ repo-config-path: .github/snapdrift.json
157
+ ```
158
+
159
+ ## What the wrapper does
160
+
161
+ - Resolves route scope unless `route-ids` is passed explicitly
162
+ - Downloads the latest successful `main` baseline
163
+ - Captures current frames
164
+ - Writes a skipped report when scope is irrelevant or the baseline is missing
165
+ - Stages and uploads the drift artifact
166
+ - Publishes the workflow summary
167
+ - Upserts the PR report
168
+ - Enforces `diff.mode` after publication completes
169
+
170
+ ## Useful overrides
171
+
172
+ | Input | Purpose |
173
+ |-------|---------|
174
+ | `pr-number` | Explicit PR number override |
175
+ | `route-ids` | Bypass scope detection and capture named routes |
176
+ | `force-run` | Run the full route set |
177
+ | `baseline-repository` | Read baselines from another repo |
178
+ | `baseline-workflow-id` | Override the baseline workflow id |
179
+ | `baseline-branch` | Override the baseline branch |
180
+ | `comment-on-pr` | Set to `false` to suppress the PR report |
181
+
182
+ ## Low-level actions
183
+
184
+ For custom orchestration:
185
+
186
+ - `actions/capture`
187
+ - `actions/compare`
188
+ - `actions/scope`
189
+ - `actions/enforce`
190
+ - `actions/comment`
191
+ - `actions/resolve-baseline`
192
+ - `actions/stage`
193
+
194
+ ## Local development
195
+
196
+ The `snapdrift` CLI lets you run captures and diffs locally against a running app. Use it to validate UI changes on your machine before pushing — the same capture and comparison engine is used in both contexts.
197
+
198
+ ```bash
199
+ # Establish a baseline before making UI changes
200
+ snapdrift capture
201
+
202
+ # After making changes, compare and open the HTML report
203
+ snapdrift diff --open
204
+ ```
205
+
206
+ The CLI reads the same `.github/snapdrift.json` config used by the Actions workflow. Local outputs land in `.snapdrift/` by default and can be overridden with `--baseline-dir`, `--current-dir`, and `--diff-dir`.
207
+
208
+ See the [Local CLI guide](local-cli.md) for full command reference, flags, directory layout, and examples.
209
+
210
+ ## Troubleshooting
211
+
212
+ **"No non-expired SnapDrift baseline artifact was found"**
213
+ The baseline workflow has not completed successfully on `main`, or the artifact expired.
214
+
215
+ **403 when posting the PR report**
216
+ Grant `issues: write` and `pull-requests: write` to the job.
217
+
218
+ **Screenshots have different dimensions**
219
+ SnapDrift reports this as a dimension shift and skips pixel comparison for that route. Refresh the baseline after the change lands.
220
+
221
+ **A route appears in `errors[]`**
222
+ Capture failed before comparison. Confirm the app is fully ready and reachable before SnapDrift runs.
@@ -0,0 +1,174 @@
1
+ # Local CLI
2
+
3
+ The `snapdrift` CLI lets you run visual captures and diffs locally against a running app — no GitHub Actions required. Use it during development to validate UI changes before pushing.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node >= 22
8
+ - A running app reachable at the `baseUrl` in your config
9
+ - A `.github/snapdrift.json` config file (or pass `--config` to point to another path)
10
+
11
+ ## Installation
12
+
13
+ The CLI ships with the `snapdrift` package. Install it globally or use `npx`:
14
+
15
+ ```bash
16
+ # global
17
+ npm install -g snapdrift
18
+
19
+ # or without installing
20
+ npx snapdrift <command>
21
+ ```
22
+
23
+ ## Commands
24
+
25
+ ### `snapdrift capture`
26
+
27
+ Captures full-page screenshots of all configured routes and saves them as a local baseline.
28
+
29
+ ```
30
+ snapdrift capture [options]
31
+ ```
32
+
33
+ Run this once to establish the baseline before making UI changes.
34
+
35
+ **Options**
36
+
37
+ | Flag | Default | Description |
38
+ |:-----|:--------|:------------|
39
+ | `--config <path>` | `.github/snapdrift.json` | Path to the config file |
40
+ | `--routes <ids>` | all routes | Comma-separated route IDs to capture |
41
+ | `--baseline-dir <path>` | `.snapdrift/baseline` | Directory to write baseline screenshots and metadata |
42
+
43
+ **Example**
44
+
45
+ ```bash
46
+ snapdrift capture
47
+ snapdrift capture --routes home-desktop,home-mobile
48
+ snapdrift capture --baseline-dir snapshots/baseline
49
+ ```
50
+
51
+ ---
52
+
53
+ ### `snapdrift diff`
54
+
55
+ Captures current screenshots, compares them against the local baseline, and writes a JSON summary, a markdown report, and a self-contained HTML report.
56
+
57
+ ```
58
+ snapdrift diff [options]
59
+ ```
60
+
61
+ **Options**
62
+
63
+ | Flag | Default | Description |
64
+ |:-----|:--------|:------------|
65
+ | `--config <path>` | `.github/snapdrift.json` | Path to the config file |
66
+ | `--routes <ids>` | all routes | Comma-separated route IDs to compare |
67
+ | `--baseline-dir <path>` | `.snapdrift/baseline` | Directory containing the baseline |
68
+ | `--current-dir <path>` | `.snapdrift/current` | Directory to write current screenshots |
69
+ | `--diff-dir <path>` | `.snapdrift/diff` | Directory to write the diff report |
70
+ | `--open` | off | Open the HTML report automatically after the diff |
71
+
72
+ **Example**
73
+
74
+ ```bash
75
+ snapdrift diff
76
+ snapdrift diff --open
77
+ snapdrift diff --routes home-desktop --open
78
+ snapdrift diff --baseline-dir snapshots/baseline --diff-dir snapshots/diff
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Typical local workflow
84
+
85
+ ```bash
86
+ # 1. Start your app
87
+ npm start
88
+
89
+ # 2. Capture a baseline (once, before making changes)
90
+ snapdrift capture
91
+
92
+ # 3. Make your UI changes
93
+
94
+ # 4. Run a diff to see what changed
95
+ snapdrift diff --open
96
+ ```
97
+
98
+ The `--open` flag opens the HTML report in your default browser when the diff is complete.
99
+
100
+ ---
101
+
102
+ ## Local directory layout
103
+
104
+ After running `capture` and `diff` with default paths:
105
+
106
+ ```
107
+ .snapdrift/
108
+ baseline/
109
+ results.json # capture metadata (status, dimensions, timing)
110
+ manifest.json # screenshot manifest (ids, paths, dimensions)
111
+ screenshots/
112
+ home-desktop.png
113
+ home-mobile.png
114
+ current/
115
+ results.json
116
+ manifest.json
117
+ screenshots/
118
+ home-desktop.png
119
+ home-mobile.png
120
+ diff/
121
+ summary.json # structured drift summary
122
+ summary.md # human-readable markdown report
123
+ report.html # self-contained HTML report with side-by-side images
124
+ ```
125
+
126
+ Add `.snapdrift/` to your `.gitignore` to keep local run output out of version control.
127
+
128
+ ---
129
+
130
+ ## Exit codes
131
+
132
+ | Code | Meaning |
133
+ |:-----|:--------|
134
+ | `0` | Clean — no drift above threshold, or `diff.mode` is `report-only` |
135
+ | `1` | Drift enforced — `diff.mode` caused the run to fail (see [Drift modes](../README.md#drift-modes)) |
136
+
137
+ Enforcement follows the same `diff.mode` rules as the GitHub Actions workflow. Set `"mode": "report-only"` during local development to always get a report without a failing exit code.
138
+
139
+ ---
140
+
141
+ ## Console output
142
+
143
+ `snapdrift diff` prints a summary to stdout:
144
+
145
+ ```
146
+ Capturing current screenshots to .snapdrift/current ...
147
+ Comparing against baseline ...
148
+
149
+ ✅ SnapDrift — Clean
150
+ Routes: 2
151
+ Matched: 2
152
+ ```
153
+
154
+ When drift is detected:
155
+
156
+ ```
157
+ 🟡 SnapDrift — Drift detected
158
+ Routes: 3
159
+ Matched: 2
160
+ Changed: 1
161
+
162
+ Changed routes:
163
+ • home-desktop (2.47% diff)
164
+
165
+ Report: .snapdrift/diff/report.html
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Tips
171
+
172
+ - **Partial runs**: use `--routes` to capture or compare only the routes you are actively changing.
173
+ - **Multiple baselines**: use `--baseline-dir` to maintain separate baselines per branch or feature.
174
+ - **CI parity**: the CLI uses the same capture and comparison engine as the GitHub Actions workflow, so results are comparable.