@vizzly-testing/cli 0.35.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 +31 -7
- package/dist/api/core.js +16 -3
- package/dist/api/endpoints.js +38 -15
- package/dist/api/index.js +1 -1
- package/dist/cli.js +252 -189
- package/dist/commands/preview.js +19 -17
- package/dist/commands/run.js +7 -4
- package/dist/commands/status.js +14 -1
- package/dist/commands/tdd-daemon-process.js +5 -1
- package/dist/commands/tdd-daemon.js +217 -144
- package/dist/commands/tdd.js +2 -1
- package/dist/reporter/reporter-bundle.iife.js +5 -5
- package/dist/tdd/tdd-service.js +6 -2
- package/dist/test-runner/core.js +4 -2
- package/dist/test-runner/operations.js +17 -2
- package/dist/utils/config-loader.js +1 -0
- package/dist/utils/output.js +3 -0
- 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
|
@@ -40,17 +40,31 @@ Use `vizzly init --agent-skill` to install only the local skill, or
|
|
|
40
40
|
|
|
41
41
|
### Start Local TDD
|
|
42
42
|
|
|
43
|
-
Start the TDD server, run your tests, and open the dashboard at
|
|
44
|
-
`
|
|
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`.
|
|
45
47
|
|
|
46
48
|
```bash
|
|
47
|
-
vizzly tdd start
|
|
49
|
+
vizzly tdd start --open
|
|
48
50
|
pnpm test -- --watch
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
The dashboard shows screenshots, baselines, and diffs as they arrive. Accept or
|
|
52
54
|
reject changes right from the UI.
|
|
53
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
|
+
|
|
54
68
|
### Run With Cloud Review
|
|
55
69
|
|
|
56
70
|
Use cloud builds when you want shared baselines, team review, and CI status:
|
|
@@ -162,9 +176,11 @@ vizzly upload ./screenshots --threshold 2 --min-cluster-size 4 --batch-size 10 -
|
|
|
162
176
|
`--upload-timeout` controls the upload client's timeout, including how long
|
|
163
177
|
`--wait` polls for build processing.
|
|
164
178
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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:
|
|
168
184
|
|
|
169
185
|
```bash
|
|
170
186
|
vizzly run "pnpm test" --upload-all --parallel-id "$GITHUB_RUN_ID"
|
|
@@ -206,10 +222,18 @@ export default {
|
|
|
206
222
|
| Command | What it does |
|
|
207
223
|
| --- | --- |
|
|
208
224
|
| `vizzly tdd start` | Start the local TDD server and dashboard. |
|
|
209
|
-
| `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/`. |
|
|
210
229
|
| `vizzly run "cmd"` | Run tests with cloud build and review integration. |
|
|
211
230
|
| `vizzly context ...` | Fetch visual context for builds, comparisons, screenshots, and review queues. |
|
|
212
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. |
|
|
213
237
|
| `vizzly login` | Authenticate through the browser. |
|
|
214
238
|
| `vizzly doctor` | Validate your local setup. |
|
|
215
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
|
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';
|