@vizzly-testing/cli 0.34.0 → 0.35.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/README.md +67 -7
- package/dist/api/core.js +18 -4
- package/dist/api/endpoints.js +38 -15
- package/dist/api/index.js +1 -1
- package/dist/cli.js +270 -194
- package/dist/client/index.js +62 -21
- package/dist/commands/api.js +9 -3
- package/dist/commands/preview.js +30 -26
- package/dist/commands/project.js +1 -1
- package/dist/commands/run.js +25 -10
- package/dist/commands/status.js +14 -1
- package/dist/commands/tdd-daemon-process.js +5 -1
- package/dist/commands/tdd-daemon.js +217 -139
- package/dist/commands/tdd.js +26 -5
- package/dist/commands/upload.js +31 -13
- package/dist/reporter/reporter-bundle.iife.js +6 -6
- package/dist/sdk/index.js +23 -9
- package/dist/server/handlers/api-handler.js +3 -2
- package/dist/server/handlers/tdd-handler.js +5 -1
- package/dist/server/routers/screenshot.js +11 -4
- package/dist/services/build-manager.js +6 -1
- package/dist/tdd/tdd-service.js +6 -2
- package/dist/test-runner/core.js +8 -3
- package/dist/test-runner/operations.js +19 -3
- package/dist/types/client.d.ts +32 -5
- package/dist/types/index.d.ts +33 -5
- package/dist/uploader/core.js +41 -9
- package/dist/uploader/operations.js +19 -17
- package/dist/utils/config-loader.js +13 -6
- package/dist/utils/context.js +46 -76
- package/dist/utils/environment-config.js +20 -0
- package/dist/utils/output.js +8 -5
- package/dist/utils/screenshot-options.js +60 -10
- package/package.json +1 -1
- package/skills/vizzly/SKILL.md +12 -4
- package/skills/vizzly/references/cli-context.md +8 -2
- package/skills/vizzly/references/setup-ci.md +3 -1
package/README.md
CHANGED
|
@@ -35,28 +35,50 @@ For agent-friendly repos, install the Vizzly skill and add a short project
|
|
|
35
35
|
vizzly init --agent-guidance
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
Use `vizzly init --agent-skill` to install only the local skill, or
|
|
39
|
+
`vizzly init --skip-agent-skill` when you want config without the agent prompt.
|
|
40
|
+
|
|
38
41
|
### Start Local TDD
|
|
39
42
|
|
|
40
|
-
Start the TDD server, run your tests, and open the dashboard at
|
|
41
|
-
`
|
|
43
|
+
Start the TDD server, run your tests, and open the dashboard at the URL the
|
|
44
|
+
command prints. Add `--open` when you want Vizzly to open the dashboard for
|
|
45
|
+
you. If the default port is busy, Vizzly picks the next available port; use the
|
|
46
|
+
printed `--port` value with `vizzly tdd status` or `vizzly tdd stop`.
|
|
42
47
|
|
|
43
48
|
```bash
|
|
44
|
-
vizzly tdd start
|
|
49
|
+
vizzly tdd start --open
|
|
45
50
|
pnpm test -- --watch
|
|
46
51
|
```
|
|
47
52
|
|
|
48
53
|
The dashboard shows screenshots, baselines, and diffs as they arrive. Accept or
|
|
49
54
|
reject changes right from the UI.
|
|
50
55
|
|
|
56
|
+
For a one-off local check, wrap the test command with `tdd run`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
vizzly tdd run "pnpm test" --no-open
|
|
60
|
+
vizzly context build current --source local --agent
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
That run writes review data under `.vizzly/` and prints a context command you
|
|
64
|
+
can use for follow-up inspection. If screenshots were captured, Vizzly also
|
|
65
|
+
generates `.vizzly/report/index.html`; omit `--no-open` when you want that
|
|
66
|
+
report opened automatically.
|
|
67
|
+
|
|
51
68
|
### Run With Cloud Review
|
|
52
69
|
|
|
53
70
|
Use cloud builds when you want shared baselines, team review, and CI status:
|
|
54
71
|
|
|
55
72
|
```bash
|
|
56
73
|
vizzly login
|
|
74
|
+
vizzly project link your-org/your-project
|
|
57
75
|
vizzly run "pnpm test" --wait
|
|
58
76
|
```
|
|
59
77
|
|
|
78
|
+
`vizzly login` authenticates your user account. `vizzly project link` creates a
|
|
79
|
+
project-scoped upload credential for this checkout, which `vizzly run` uses for
|
|
80
|
+
cloud uploads.
|
|
81
|
+
|
|
60
82
|
`--wait` blocks until Vizzly finishes processing the build. It exits with code
|
|
61
83
|
`1` when visual differences need review.
|
|
62
84
|
|
|
@@ -111,12 +133,23 @@ test('homepage looks correct', async ({ page }) => {
|
|
|
111
133
|
|
|
112
134
|
let screenshot = await page.screenshot();
|
|
113
135
|
await vizzlyScreenshot('homepage', screenshot, {
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
fullPage: true,
|
|
137
|
+
requestTimeout: 5000,
|
|
138
|
+
properties: {
|
|
139
|
+
browser: 'chrome',
|
|
140
|
+
viewport: { width: 1920, height: 1080 },
|
|
141
|
+
},
|
|
116
142
|
});
|
|
117
143
|
});
|
|
118
144
|
```
|
|
119
145
|
|
|
146
|
+
`properties` is your metadata bag for baseline grouping, filtering, and
|
|
147
|
+
debugging. SDK options such as `threshold`, `minClusterSize`, `fullPage`,
|
|
148
|
+
`requestTimeout`, and `buildId` stay at the top level. If one of those reserved
|
|
149
|
+
SDK options is accidentally placed inside `properties`, Vizzly removes it from
|
|
150
|
+
metadata, applies it as an option when possible, and warns so the call site can
|
|
151
|
+
be cleaned up.
|
|
152
|
+
|
|
120
153
|
The client SDK is lightweight. It posts screenshots to the local Vizzly server
|
|
121
154
|
or the cloud build wrapper. It works with any test runner.
|
|
122
155
|
|
|
@@ -136,9 +169,28 @@ await vizzlyScreenshot('homepage', './screenshots/homepage.png');
|
|
|
136
169
|
Or upload an existing folder of screenshots:
|
|
137
170
|
|
|
138
171
|
```bash
|
|
139
|
-
vizzly upload ./screenshots
|
|
172
|
+
vizzly upload ./screenshots --threshold 2 --min-cluster-size 4 --batch-size 10 --upload-timeout 60000
|
|
140
173
|
```
|
|
141
174
|
|
|
175
|
+
`--batch-size` controls how many screenshots are uploaded per request.
|
|
176
|
+
`--upload-timeout` controls the upload client's timeout, including how long
|
|
177
|
+
`--wait` polls for build processing.
|
|
178
|
+
|
|
179
|
+
When `vizzly run` sends screenshots to Vizzly, the CLI first asks the API to
|
|
180
|
+
resolve each screenshot by SHA. If Vizzly already has the image bytes, the CLI
|
|
181
|
+
creates the screenshot record without re-uploading the image. CI workflows can
|
|
182
|
+
force every screenshot through with `--upload-all`. Parallel jobs should use the
|
|
183
|
+
same stable ID, then finalize that ID after every shard completes:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
vizzly run "pnpm test" --upload-all --parallel-id "$GITHUB_RUN_ID"
|
|
187
|
+
vizzly finalize "$GITHUB_RUN_ID"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
For smoke jobs where cloud credentials are intentionally unavailable, add
|
|
191
|
+
`--allow-no-token` to `vizzly run` and Vizzly will keep the local screenshot
|
|
192
|
+
server path working without creating a cloud build.
|
|
193
|
+
|
|
142
194
|
## Configuration
|
|
143
195
|
|
|
144
196
|
Generate a config file:
|
|
@@ -170,10 +222,18 @@ export default {
|
|
|
170
222
|
| Command | What it does |
|
|
171
223
|
| --- | --- |
|
|
172
224
|
| `vizzly tdd start` | Start the local TDD server and dashboard. |
|
|
173
|
-
| `vizzly tdd
|
|
225
|
+
| `vizzly tdd status` | Check the local TDD server for this project. |
|
|
226
|
+
| `vizzly tdd list` | List running local TDD servers. |
|
|
227
|
+
| `vizzly tdd stop` | Stop the local TDD server for this project. |
|
|
228
|
+
| `vizzly tdd run "cmd"` | Run tests once and write local review data under `.vizzly/`. |
|
|
174
229
|
| `vizzly run "cmd"` | Run tests with cloud build and review integration. |
|
|
175
230
|
| `vizzly context ...` | Fetch visual context for builds, comparisons, screenshots, and review queues. |
|
|
176
231
|
| `vizzly upload <dir>` | Upload an existing folder of screenshots. |
|
|
232
|
+
| `vizzly preview <dir>` | Upload static build output for in-context review. |
|
|
233
|
+
| `vizzly approve <comparison-id>` | Approve a visual comparison. |
|
|
234
|
+
| `vizzly reject <comparison-id>` | Reject a visual comparison with a reason. |
|
|
235
|
+
| `vizzly comment <build-id>` | Add a build comment. |
|
|
236
|
+
| `vizzly config [key]` | Inspect resolved configuration values. |
|
|
177
237
|
| `vizzly login` | Authenticate through the browser. |
|
|
178
238
|
| `vizzly doctor` | Validate your local setup. |
|
|
179
239
|
|
package/dist/api/core.js
CHANGED
|
@@ -70,9 +70,9 @@ export function buildRequestHeaders({
|
|
|
70
70
|
// ============================================================================
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* Build payload for screenshot upload
|
|
73
|
+
* Build payload for screenshot upload or SHA resolution
|
|
74
74
|
* @param {string} name - Screenshot name
|
|
75
|
-
* @param {Buffer} buffer - Image data
|
|
75
|
+
* @param {Buffer|null} buffer - Image data, or null when resolving by SHA
|
|
76
76
|
* @param {Object} metadata - Screenshot metadata (viewport, browser, etc.)
|
|
77
77
|
* @param {string|null} sha256 - Pre-computed SHA256 hash (optional)
|
|
78
78
|
* @returns {Object} Screenshot upload payload
|
|
@@ -80,15 +80,28 @@ export function buildRequestHeaders({
|
|
|
80
80
|
export function buildScreenshotPayload(name, buffer, metadata = {}, sha256 = null) {
|
|
81
81
|
let payload = {
|
|
82
82
|
name,
|
|
83
|
-
image_data: buffer.toString('base64'),
|
|
84
83
|
properties: metadata ?? {}
|
|
85
84
|
};
|
|
85
|
+
if (buffer) {
|
|
86
|
+
payload.image_data = buffer.toString('base64');
|
|
87
|
+
}
|
|
86
88
|
if (sha256) {
|
|
87
89
|
payload.sha256 = sha256;
|
|
88
90
|
}
|
|
89
91
|
return payload;
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Build payload for server-side screenshot resolution without sending image bytes
|
|
96
|
+
* @param {string} name - Screenshot name
|
|
97
|
+
* @param {Object} metadata - Screenshot metadata (viewport, browser, etc.)
|
|
98
|
+
* @param {string} sha256 - Pre-computed SHA256 hash
|
|
99
|
+
* @returns {Object} Screenshot resolution payload
|
|
100
|
+
*/
|
|
101
|
+
export function buildScreenshotResolvePayload(name, metadata = {}, sha256) {
|
|
102
|
+
return buildScreenshotPayload(name, null, metadata, sha256);
|
|
103
|
+
}
|
|
104
|
+
|
|
92
105
|
/**
|
|
93
106
|
* Build payload for build creation
|
|
94
107
|
* @param {Object} options - Build options
|
|
@@ -172,7 +185,8 @@ export function buildScreenshotCheckObject(sha256, name, metadata = {}) {
|
|
|
172
185
|
name,
|
|
173
186
|
browser: meta.browser || 'chrome',
|
|
174
187
|
viewport_width: meta.viewport?.width || meta.viewport_width || 1920,
|
|
175
|
-
viewport_height: meta.viewport?.height || meta.viewport_height || 1080
|
|
188
|
+
viewport_height: meta.viewport?.height || meta.viewport_height || 1080,
|
|
189
|
+
properties: meta
|
|
176
190
|
};
|
|
177
191
|
}
|
|
178
192
|
|
package/dist/api/endpoints.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
9
9
|
import * as output from '../utils/output.js';
|
|
10
|
-
import { buildBuildPayload, buildEndpointWithParams, buildQueryParams,
|
|
10
|
+
import { buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildScreenshotPayload, buildScreenshotResolvePayload, buildShaCheckPayload, computeSha256 } from './core.js';
|
|
11
11
|
|
|
12
12
|
// ============================================================================
|
|
13
13
|
// Build Endpoints
|
|
@@ -144,6 +144,16 @@ export async function checkShas(client, screenshots, buildId) {
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
+
function canUploadBytesAfterShaResolveError(error) {
|
|
148
|
+
let status = error?.context?.status;
|
|
149
|
+
|
|
150
|
+
// Network failures, older servers, and server errors should degrade to the
|
|
151
|
+
// slower byte upload path. Auth and ownership errors must still surface.
|
|
152
|
+
if (!status) return true;
|
|
153
|
+
if (status >= 500) return true;
|
|
154
|
+
if (status === 400 && error.message?.includes('image_data')) return true;
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
147
157
|
|
|
148
158
|
/**
|
|
149
159
|
* Upload a screenshot with SHA deduplication
|
|
@@ -168,23 +178,36 @@ export async function uploadScreenshot(client, buildId, name, buffer, metadata =
|
|
|
168
178
|
});
|
|
169
179
|
}
|
|
170
180
|
|
|
171
|
-
// Normal flow with SHA
|
|
181
|
+
// Normal flow with server-side SHA resolution.
|
|
172
182
|
let sha256 = computeSha256(buffer);
|
|
173
|
-
let
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
let resolvePayload = buildScreenshotResolvePayload(name, metadata, sha256);
|
|
184
|
+
try {
|
|
185
|
+
let resolveResult = await client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: {
|
|
188
|
+
'Content-Type': 'application/json'
|
|
189
|
+
},
|
|
190
|
+
body: JSON.stringify(resolvePayload)
|
|
191
|
+
});
|
|
192
|
+
if (resolveResult?.upload_required === false) {
|
|
193
|
+
return {
|
|
194
|
+
message: 'Screenshot already exists, skipped upload',
|
|
195
|
+
sha256,
|
|
196
|
+
skipped: true,
|
|
197
|
+
screenshot: resolveResult,
|
|
198
|
+
fromExisting: true
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (!canUploadBytesAfterShaResolveError(error)) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
output.debug('sha-resolve', 'failed, uploading screenshot bytes', {
|
|
206
|
+
error: error.message
|
|
207
|
+
});
|
|
185
208
|
}
|
|
186
209
|
|
|
187
|
-
// File doesn't exist, proceed with upload
|
|
210
|
+
// File doesn't exist, or resolve failed; proceed with upload.
|
|
188
211
|
let payload = buildScreenshotPayload(name, buffer, metadata, sha256);
|
|
189
212
|
return client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
190
213
|
method: 'POST',
|
package/dist/api/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// Client factory
|
|
14
14
|
export { createApiClient, DEFAULT_API_URL } from './client.js';
|
|
15
15
|
// Core pure functions
|
|
16
|
-
export { buildApiUrl, buildAuthHeader, buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildRequestHeaders, buildScreenshotCheckObject, buildScreenshotPayload, buildShaCheckPayload, buildUserAgent, computeSha256, extractErrorBody, findScreenshotBySha, isAuthError, isRateLimited, parseApiError, partitionByShaExistence, shaExists, shouldRetryWithRefresh } from './core.js';
|
|
16
|
+
export { buildApiUrl, buildAuthHeader, buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildRequestHeaders, buildScreenshotCheckObject, buildScreenshotPayload, buildScreenshotResolvePayload, buildShaCheckPayload, buildUserAgent, computeSha256, extractErrorBody, findScreenshotBySha, isAuthError, isRateLimited, parseApiError, partitionByShaExistence, shaExists, shouldRetryWithRefresh } from './core.js';
|
|
17
17
|
|
|
18
18
|
// Endpoint functions
|
|
19
19
|
export { checkShas, createBuild, finalizeBuild, finalizeParallelBuild, getBatchHotspots, getBuild, getBuildContext, getBuilds, getComparison, getComparisonContext, getPreviewInfo, getReviewQueueContext, getScreenshotContext, getScreenshotHotspots, getSimilarFingerprintContext, getTddBaselines, getTokenContext, searchComparisons, updateBuildStatus, uploadPreviewZip, uploadScreenshot } from './endpoints.js';
|