@vizzly-testing/cli 0.20.0 → 0.20.1-beta.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/dist/api/client.js +134 -0
- package/dist/api/core.js +341 -0
- package/dist/api/endpoints.js +314 -0
- package/dist/api/index.js +19 -0
- package/dist/auth/client.js +91 -0
- package/dist/auth/core.js +176 -0
- package/dist/auth/index.js +30 -0
- package/dist/auth/operations.js +148 -0
- package/dist/cli.js +178 -3
- package/dist/client/index.js +144 -77
- package/dist/commands/doctor.js +121 -36
- package/dist/commands/finalize.js +49 -18
- package/dist/commands/init.js +13 -18
- package/dist/commands/login.js +49 -55
- package/dist/commands/logout.js +17 -9
- package/dist/commands/project.js +100 -71
- package/dist/commands/run.js +189 -95
- package/dist/commands/status.js +101 -66
- package/dist/commands/tdd-daemon.js +61 -32
- package/dist/commands/tdd.js +104 -98
- package/dist/commands/upload.js +78 -34
- package/dist/commands/whoami.js +44 -42
- package/dist/config/core.js +438 -0
- package/dist/config/index.js +13 -0
- package/dist/config/operations.js +327 -0
- package/dist/index.js +1 -1
- package/dist/project/core.js +295 -0
- package/dist/project/index.js +13 -0
- package/dist/project/operations.js +393 -0
- package/dist/reporter/reporter-bundle.css +1 -1
- package/dist/reporter/reporter-bundle.iife.js +16 -16
- package/dist/screenshot-server/core.js +157 -0
- package/dist/screenshot-server/index.js +11 -0
- package/dist/screenshot-server/operations.js +183 -0
- package/dist/sdk/index.js +3 -2
- package/dist/server/handlers/api-handler.js +14 -5
- package/dist/server/handlers/tdd-handler.js +191 -53
- package/dist/server/http-server.js +9 -3
- package/dist/server/routers/baseline.js +58 -0
- package/dist/server/routers/dashboard.js +10 -6
- package/dist/server/routers/screenshot.js +32 -0
- package/dist/server-manager/core.js +186 -0
- package/dist/server-manager/index.js +81 -0
- package/dist/server-manager/operations.js +209 -0
- package/dist/services/build-manager.js +2 -69
- package/dist/services/index.js +21 -48
- package/dist/services/screenshot-server.js +40 -74
- package/dist/services/server-manager.js +45 -80
- package/dist/services/test-runner.js +90 -250
- package/dist/services/uploader.js +56 -358
- package/dist/tdd/core/hotspot-coverage.js +112 -0
- package/dist/tdd/core/signature.js +101 -0
- package/dist/tdd/index.js +19 -0
- package/dist/tdd/metadata/baseline-metadata.js +103 -0
- package/dist/tdd/metadata/hotspot-metadata.js +93 -0
- package/dist/tdd/services/baseline-downloader.js +151 -0
- package/dist/tdd/services/baseline-manager.js +166 -0
- package/dist/tdd/services/comparison-service.js +230 -0
- package/dist/tdd/services/hotspot-service.js +71 -0
- package/dist/tdd/services/result-service.js +123 -0
- package/dist/tdd/tdd-service.js +1145 -0
- package/dist/test-runner/core.js +255 -0
- package/dist/test-runner/index.js +13 -0
- package/dist/test-runner/operations.js +483 -0
- package/dist/types/client.d.ts +25 -2
- package/dist/uploader/core.js +396 -0
- package/dist/uploader/index.js +11 -0
- package/dist/uploader/operations.js +412 -0
- package/dist/utils/colors.js +187 -39
- package/dist/utils/config-loader.js +3 -6
- package/dist/utils/context.js +228 -0
- package/dist/utils/output.js +449 -14
- package/docs/api-reference.md +173 -8
- package/docs/tui-elements.md +560 -0
- package/package.json +13 -13
- package/dist/services/api-service.js +0 -412
- package/dist/services/auth-service.js +0 -226
- package/dist/services/config-service.js +0 -369
- package/dist/services/html-report-generator.js +0 -455
- package/dist/services/project-service.js +0 -326
- package/dist/services/report-generator/report.css +0 -411
- package/dist/services/report-generator/viewer.js +0 -102
- package/dist/services/static-report-generator.js +0 -207
- package/dist/services/tdd-service.js +0 -1437
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
# TUI Elements Reference
|
|
2
|
+
|
|
3
|
+
The Vizzly CLI includes a comprehensive terminal UI toolkit for consistent, beautiful output across all commands. This guide documents the available helpers and how to use them.
|
|
4
|
+
|
|
5
|
+
## Design System
|
|
6
|
+
|
|
7
|
+
The TUI elements follow the **Observatory Design System** - Vizzly's visual language. Key characteristics:
|
|
8
|
+
|
|
9
|
+
- **Amber** (`#F59E0B`) is the signature brand color used for primary actions and highlights
|
|
10
|
+
- **Semantic colors** communicate meaning consistently (green=success, red=error, amber=warning, blue=info)
|
|
11
|
+
- **Text hierarchy** uses four levels for clear information architecture
|
|
12
|
+
- **Dark theme first** - colors are optimized for dark terminal backgrounds
|
|
13
|
+
|
|
14
|
+
## Quick Reference
|
|
15
|
+
|
|
16
|
+
| Helper | Purpose | Example |
|
|
17
|
+
|--------|---------|---------|
|
|
18
|
+
| `header()` | Command branding | `header('tdd', 'local')` |
|
|
19
|
+
| `success()` | Success message with checkmark | `success('Build uploaded')` |
|
|
20
|
+
| `result()` | Final result with timing | `result('5 screenshots')` |
|
|
21
|
+
| `complete()` | Completion message | `complete('Ready', { detail: 'port 47392' })` |
|
|
22
|
+
| `error()` | Error message | `error('Failed', err)` |
|
|
23
|
+
| `warn()` | Warning message | `warn('Token expires soon')` |
|
|
24
|
+
| `info()` | Info message | `info('Processing started')` |
|
|
25
|
+
| `debug()` | Debug with component | `debug('server', 'listening', { port: 47392 })` |
|
|
26
|
+
| `list()` | Bullet point list | `list(['Item 1', 'Item 2'])` |
|
|
27
|
+
| `keyValue()` | Key-value table | `keyValue({ Name: 'build-123' })` |
|
|
28
|
+
| `labelValue()` | Single key-value | `labelValue('Status', 'ready')` |
|
|
29
|
+
| `hint()` | Muted tip/hint | `hint('Use --verbose for details')` |
|
|
30
|
+
| `divider()` | Separator line | `divider({ width: 40 })` |
|
|
31
|
+
| `box()` | Bordered box | `box('Dashboard ready')` |
|
|
32
|
+
| `printBox()` | Print box to stderr | `printBox('Content', { title: 'Info' })` |
|
|
33
|
+
| `diffBar()` | Visual diff bar | `diffBar(4.2)` |
|
|
34
|
+
| `progressBar()` | Gradient progress | `progressBar(75, 100)` |
|
|
35
|
+
| `badge()` | Status badge | `badge('READY', 'success')` |
|
|
36
|
+
| `statusDot()` | Colored dot | `statusDot('success')` |
|
|
37
|
+
| `link()` | Styled URL | `link('Dashboard', 'http://...')` |
|
|
38
|
+
| `startSpinner()` | Animated spinner | `startSpinner('Loading...')` |
|
|
39
|
+
| `progress()` | Progress update | `progress('Uploading', 5, 10)` |
|
|
40
|
+
|
|
41
|
+
## Import
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import * as output from '../utils/output.js';
|
|
45
|
+
|
|
46
|
+
// Or import specific functions
|
|
47
|
+
import {
|
|
48
|
+
header,
|
|
49
|
+
success,
|
|
50
|
+
error,
|
|
51
|
+
keyValue,
|
|
52
|
+
startSpinner
|
|
53
|
+
} from '../utils/output.js';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Call `configure()` at the start of your command to set output options:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
output.configure({
|
|
62
|
+
json: globalOptions.json, // Enable JSON output mode
|
|
63
|
+
verbose: globalOptions.verbose, // Enable debug logging
|
|
64
|
+
color: !globalOptions.noColor, // Enable/disable colors
|
|
65
|
+
silent: false, // Suppress all output
|
|
66
|
+
logFile: null, // Path to log file
|
|
67
|
+
resetTimer: true // Reset elapsed timer (default: true)
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Visual Elements
|
|
72
|
+
|
|
73
|
+
### Header
|
|
74
|
+
|
|
75
|
+
Show command branding at the start of output. Uses amber for "vizzly", info blue for command name, and muted text for mode.
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
output.header('tdd', 'local');
|
|
79
|
+
// Output:
|
|
80
|
+
//
|
|
81
|
+
// vizzly · tdd · local
|
|
82
|
+
//
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The header automatically:
|
|
86
|
+
- Only shows once per command execution
|
|
87
|
+
- Skips in JSON or silent mode
|
|
88
|
+
- Uses brand colors from Observatory
|
|
89
|
+
|
|
90
|
+
### Box
|
|
91
|
+
|
|
92
|
+
Create bordered boxes for important information:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Simple box
|
|
96
|
+
output.printBox('Dashboard: http://localhost:47392');
|
|
97
|
+
// ╭───────────────────────────────────────╮
|
|
98
|
+
// │ Dashboard: http://localhost:47392 │
|
|
99
|
+
// ╰───────────────────────────────────────╯
|
|
100
|
+
|
|
101
|
+
// Box with title
|
|
102
|
+
output.printBox('Server started successfully', {
|
|
103
|
+
title: 'Ready',
|
|
104
|
+
style: 'branded' // Uses amber border
|
|
105
|
+
});
|
|
106
|
+
// ╭─ Ready ────────────────────────────────╮
|
|
107
|
+
// │ Server started successfully │
|
|
108
|
+
// ╰────────────────────────────────────────╯
|
|
109
|
+
|
|
110
|
+
// Multi-line content
|
|
111
|
+
output.printBox([
|
|
112
|
+
'Dashboard: http://localhost:47392',
|
|
113
|
+
'API: http://localhost:47392/api'
|
|
114
|
+
]);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Options:
|
|
118
|
+
- `title` - Optional title in border
|
|
119
|
+
- `padding` - Horizontal padding (default: 1)
|
|
120
|
+
- `borderColor` - Color function for border
|
|
121
|
+
- `style` - `'default'` or `'branded'` (amber border)
|
|
122
|
+
|
|
123
|
+
### Diff Bar
|
|
124
|
+
|
|
125
|
+
Color-coded visual representation of diff percentages:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
output.diffBar(0.5); // ████░░░░░░ (green - minimal)
|
|
129
|
+
output.diffBar(4.2); // ████░░░░░░ (amber - attention)
|
|
130
|
+
output.diffBar(15.0); // ██████░░░░ (red - significant)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Color thresholds:
|
|
134
|
+
- `< 1%` - Success green (minimal change)
|
|
135
|
+
- `1-5%` - Warning amber (attention needed)
|
|
136
|
+
- `> 5%` - Danger red (significant change)
|
|
137
|
+
|
|
138
|
+
### Progress Bar
|
|
139
|
+
|
|
140
|
+
Gradient progress indicator using amber brand colors:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
let bar = output.progressBar(75, 100);
|
|
144
|
+
// ███████████████░░░░░ (amber gradient)
|
|
145
|
+
|
|
146
|
+
// Custom colors
|
|
147
|
+
let bar = output.progressBar(50, 100, 20, {
|
|
148
|
+
from: '#10B981', // Start color
|
|
149
|
+
to: '#34D399' // End color
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Badge
|
|
154
|
+
|
|
155
|
+
Status badges with background colors:
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
output.badge('READY', 'success'); // Green background
|
|
159
|
+
output.badge('PENDING', 'warning'); // Amber background
|
|
160
|
+
output.badge('FAILED', 'error'); // Red background
|
|
161
|
+
output.badge('SYNC', 'info'); // Blue background
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Status Dot
|
|
165
|
+
|
|
166
|
+
Simple colored status indicators:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
output.statusDot('success'); // ● (green)
|
|
170
|
+
output.statusDot('warning'); // ● (amber)
|
|
171
|
+
output.statusDot('error'); // ● (red)
|
|
172
|
+
output.statusDot('info'); // ● (blue)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Divider
|
|
176
|
+
|
|
177
|
+
Visual separator line:
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
output.divider();
|
|
181
|
+
// ────────────────────────────────────────
|
|
182
|
+
|
|
183
|
+
output.divider({ width: 20, char: '═' });
|
|
184
|
+
// ════════════════════
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Text Formatting
|
|
188
|
+
|
|
189
|
+
### List
|
|
190
|
+
|
|
191
|
+
Bullet point lists with style variants:
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
// Default style (muted bullets)
|
|
195
|
+
output.list(['Item one', 'Item two', 'Item three']);
|
|
196
|
+
// • Item one
|
|
197
|
+
// • Item two
|
|
198
|
+
// • Item three
|
|
199
|
+
|
|
200
|
+
// Success style (green checkmarks)
|
|
201
|
+
output.list(['Config loaded', 'Server started'], { style: 'success' });
|
|
202
|
+
// ✓ Config loaded
|
|
203
|
+
// ✓ Server started
|
|
204
|
+
|
|
205
|
+
// Warning style (amber exclamation)
|
|
206
|
+
output.list(['Missing token', 'Outdated config'], { style: 'warning' });
|
|
207
|
+
// ! Missing token
|
|
208
|
+
// ! Outdated config
|
|
209
|
+
|
|
210
|
+
// Error style (red X)
|
|
211
|
+
output.list(['Connection failed', 'Upload timeout'], { style: 'error' });
|
|
212
|
+
// ✗ Connection failed
|
|
213
|
+
// ✗ Upload timeout
|
|
214
|
+
|
|
215
|
+
// Custom indent
|
|
216
|
+
output.list(['Item 1', 'Item 2'], { indent: 4 });
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Key-Value Table
|
|
220
|
+
|
|
221
|
+
Display structured data as aligned key-value pairs:
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
output.keyValue({
|
|
225
|
+
Project: 'my-app',
|
|
226
|
+
Branch: 'feature/login',
|
|
227
|
+
Commit: 'abc1234',
|
|
228
|
+
Environment: 'staging'
|
|
229
|
+
});
|
|
230
|
+
// Project my-app
|
|
231
|
+
// Branch feature/login
|
|
232
|
+
// Commit abc1234
|
|
233
|
+
// Environment staging
|
|
234
|
+
|
|
235
|
+
// Custom key width
|
|
236
|
+
output.keyValue({ Name: 'value' }, { keyWidth: 20 });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Label-Value
|
|
240
|
+
|
|
241
|
+
Single key-value pair (inline):
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
output.labelValue('Status', 'ready');
|
|
245
|
+
// Status: ready
|
|
246
|
+
|
|
247
|
+
output.labelValue('Screenshots', '15');
|
|
248
|
+
// Screenshots: 15
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Hint
|
|
252
|
+
|
|
253
|
+
Muted tips and additional information:
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
output.hint('Use --verbose for more details');
|
|
257
|
+
// Use --verbose for more details
|
|
258
|
+
|
|
259
|
+
output.hint('Dashboard: http://localhost:47392', { indent: 4 });
|
|
260
|
+
// Dashboard: http://localhost:47392
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Link
|
|
264
|
+
|
|
265
|
+
Styled URLs with underline and info blue color:
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
let url = output.link('Dashboard', 'http://localhost:47392');
|
|
269
|
+
// Returns: underlined blue URL
|
|
270
|
+
|
|
271
|
+
// Usage in output
|
|
272
|
+
output.labelValue('View', output.link('Dashboard', 'http://localhost:47392'));
|
|
273
|
+
// View: http://localhost:47392 (underlined, blue)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Complete
|
|
277
|
+
|
|
278
|
+
Success/completion message with checkmark:
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
output.complete('Build uploaded');
|
|
282
|
+
// ✓ Build uploaded
|
|
283
|
+
|
|
284
|
+
output.complete('Build uploaded', { detail: 'build-abc123' });
|
|
285
|
+
// ✓ Build uploaded build-abc123
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Logging
|
|
289
|
+
|
|
290
|
+
### Success, Result, Error, Warn, Info
|
|
291
|
+
|
|
292
|
+
Standard logging functions with appropriate icons and colors:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
output.success('Configuration saved');
|
|
296
|
+
// ✓ Configuration saved
|
|
297
|
+
|
|
298
|
+
output.result('5 screenshots uploaded'); // Includes elapsed time
|
|
299
|
+
// ✓ 5 screenshots uploaded · 234ms
|
|
300
|
+
|
|
301
|
+
output.error('Upload failed', err);
|
|
302
|
+
// ✖ Upload failed
|
|
303
|
+
// Connection timeout (if err.message differs from message)
|
|
304
|
+
|
|
305
|
+
output.warn('Token expires in 24 hours');
|
|
306
|
+
// ⚠ Token expires in 24 hours
|
|
307
|
+
|
|
308
|
+
output.info('Processing started');
|
|
309
|
+
// ℹ Processing started
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Debug
|
|
313
|
+
|
|
314
|
+
Component-based debug logging (only shown when verbose):
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
output.debug('server', 'listening on port', { port: 47392 });
|
|
318
|
+
// server listening on port port=47392
|
|
319
|
+
|
|
320
|
+
output.debug('config', 'loaded from file', { path: './vizzly.config.js' });
|
|
321
|
+
// config loaded from file path=./vizzly.config.js
|
|
322
|
+
|
|
323
|
+
output.debug('upload', 'batch complete', { uploaded: 5, total: 10 });
|
|
324
|
+
// upload batch complete uploaded=5 total=10
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Component colors are mapped semantically:
|
|
328
|
+
- `server`, `baseline` - Success green (infrastructure)
|
|
329
|
+
- `tdd`, `compare` - Info blue (processing)
|
|
330
|
+
- `config`, `build`, `auth` - Warning amber (configuration)
|
|
331
|
+
- `upload`, `api` - Info blue (processing)
|
|
332
|
+
- `run` - Amber (primary action)
|
|
333
|
+
|
|
334
|
+
### Spinner
|
|
335
|
+
|
|
336
|
+
Animated loading indicator (only in TTY):
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
output.startSpinner('Loading configuration...');
|
|
340
|
+
// ⠋ Loading configuration... (animated)
|
|
341
|
+
|
|
342
|
+
output.updateSpinner('Processing', 5, 10);
|
|
343
|
+
// ⠙ Processing (5/10)
|
|
344
|
+
|
|
345
|
+
output.stopSpinner();
|
|
346
|
+
// Clears the spinner line
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The spinner uses the amber brand color for the animation and plain text for the message.
|
|
350
|
+
|
|
351
|
+
### Progress
|
|
352
|
+
|
|
353
|
+
Progress updates that work with spinner or JSON mode:
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
output.progress('Uploading screenshots', 3, 10);
|
|
357
|
+
// In TTY: updates spinner with (3/10)
|
|
358
|
+
// In JSON: outputs {"status":"progress","message":"...","progress":{"current":3,"total":10}}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Colors
|
|
362
|
+
|
|
363
|
+
Access the colors object for custom formatting:
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
let colors = output.getColors();
|
|
367
|
+
|
|
368
|
+
// Basic colors
|
|
369
|
+
colors.red('error text');
|
|
370
|
+
colors.green('success text');
|
|
371
|
+
colors.yellow('warning text');
|
|
372
|
+
|
|
373
|
+
// Brand colors (Observatory Design System)
|
|
374
|
+
colors.brand.amber('primary brand'); // #F59E0B
|
|
375
|
+
colors.brand.success('approved'); // #10B981
|
|
376
|
+
colors.brand.warning('pending'); // #F59E0B
|
|
377
|
+
colors.brand.danger('rejected'); // #EF4444
|
|
378
|
+
colors.brand.info('processing'); // #3B82F6
|
|
379
|
+
|
|
380
|
+
// Text hierarchy
|
|
381
|
+
colors.brand.textPrimary('heading'); // #FFFFFF
|
|
382
|
+
colors.brand.textSecondary('body'); // #9CA3AF
|
|
383
|
+
colors.brand.textTertiary('caption'); // #6B7280
|
|
384
|
+
colors.brand.textMuted('disabled'); // #4B5563
|
|
385
|
+
|
|
386
|
+
// Modifiers
|
|
387
|
+
colors.bold('important');
|
|
388
|
+
colors.dim('muted');
|
|
389
|
+
colors.underline('link');
|
|
390
|
+
colors.italic('emphasis');
|
|
391
|
+
|
|
392
|
+
// Backgrounds
|
|
393
|
+
colors.brand.bgSuccess(' PASS ');
|
|
394
|
+
colors.brand.bgWarning(' WARN ');
|
|
395
|
+
colors.brand.bgDanger(' FAIL ');
|
|
396
|
+
colors.brand.bgInfo(' INFO ');
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## JSON Mode
|
|
400
|
+
|
|
401
|
+
All TUI helpers respect JSON mode. When `json: true`:
|
|
402
|
+
- Visual elements return empty strings or plain text
|
|
403
|
+
- Logging functions output structured JSON
|
|
404
|
+
- Spinners are disabled
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
output.configure({ json: true });
|
|
408
|
+
|
|
409
|
+
output.success('Done');
|
|
410
|
+
// {"status":"success","message":"Done"}
|
|
411
|
+
|
|
412
|
+
output.error('Failed', new Error('Connection timeout'));
|
|
413
|
+
// {"status":"error","message":"Failed","error":{"name":"Error","message":"Connection timeout"}}
|
|
414
|
+
|
|
415
|
+
output.progress('Uploading', 5, 10);
|
|
416
|
+
// {"status":"progress","message":"Uploading","progress":{"current":5,"total":10}}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Best Practices
|
|
420
|
+
|
|
421
|
+
### 1. Always configure at command start
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
export async function myCommand(options, globalOptions) {
|
|
425
|
+
output.configure({
|
|
426
|
+
json: globalOptions.json,
|
|
427
|
+
verbose: globalOptions.verbose,
|
|
428
|
+
color: !globalOptions.noColor,
|
|
429
|
+
});
|
|
430
|
+
// ... rest of command
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 2. Use header for command branding
|
|
435
|
+
|
|
436
|
+
```javascript
|
|
437
|
+
output.header('upload', 'cloud');
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### 3. Stop spinner before other output
|
|
441
|
+
|
|
442
|
+
```javascript
|
|
443
|
+
output.startSpinner('Processing...');
|
|
444
|
+
// ... async work ...
|
|
445
|
+
output.stopSpinner(); // Always stop before success/error
|
|
446
|
+
output.success('Done');
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Most output functions call `stopSpinner()` automatically, but explicit stopping is clearer.
|
|
450
|
+
|
|
451
|
+
### 4. Use semantic functions for their purpose
|
|
452
|
+
|
|
453
|
+
```javascript
|
|
454
|
+
// Good
|
|
455
|
+
output.complete('Build ready'); // Completion state
|
|
456
|
+
output.success('Upload successful'); // Success message
|
|
457
|
+
output.result('5 screenshots'); // Final result with timing
|
|
458
|
+
|
|
459
|
+
// Avoid mixing purposes
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### 5. Leverage debug for troubleshooting
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
output.debug('api', 'request sent', { url, method });
|
|
466
|
+
output.debug('api', 'response received', { status, duration: '234ms' });
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### 6. Clean up resources
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
try {
|
|
473
|
+
// ... command logic
|
|
474
|
+
} finally {
|
|
475
|
+
output.cleanup(); // Stops spinner, flushes logs
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Examples
|
|
480
|
+
|
|
481
|
+
### Diagnostic Command
|
|
482
|
+
|
|
483
|
+
```javascript
|
|
484
|
+
export async function doctorCommand(options, globalOptions) {
|
|
485
|
+
output.configure({ ... });
|
|
486
|
+
output.header('doctor', 'full');
|
|
487
|
+
|
|
488
|
+
let checks = [];
|
|
489
|
+
|
|
490
|
+
// Run checks...
|
|
491
|
+
checks.push({ name: 'Node.js', value: 'v20.10.0', ok: true });
|
|
492
|
+
checks.push({ name: 'API', value: 'connected', ok: true });
|
|
493
|
+
|
|
494
|
+
// Display results
|
|
495
|
+
let colors = output.getColors();
|
|
496
|
+
for (let check of checks) {
|
|
497
|
+
let icon = check.ok ? colors.brand.success('✓') : colors.brand.danger('✗');
|
|
498
|
+
let label = colors.brand.textTertiary(check.name.padEnd(12));
|
|
499
|
+
output.print(` ${icon} ${label} ${check.value}`);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
output.blank();
|
|
503
|
+
output.complete('Preflight passed');
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Upload Command
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
export async function uploadCommand(path, options, globalOptions) {
|
|
511
|
+
output.configure({ ... });
|
|
512
|
+
output.header('upload', 'cloud');
|
|
513
|
+
|
|
514
|
+
output.startSpinner('Uploading screenshots...');
|
|
515
|
+
|
|
516
|
+
for (let i = 0; i < screenshots.length; i++) {
|
|
517
|
+
output.progress('Uploading', i + 1, screenshots.length);
|
|
518
|
+
await upload(screenshots[i]);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
output.stopSpinner();
|
|
522
|
+
|
|
523
|
+
output.keyValue({
|
|
524
|
+
Build: buildId,
|
|
525
|
+
Screenshots: String(screenshots.length),
|
|
526
|
+
Branch: branch
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
output.blank();
|
|
530
|
+
output.labelValue('View', output.link('Build', buildUrl));
|
|
531
|
+
output.result(`${screenshots.length} screenshots uploaded`);
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### TDD Dashboard
|
|
536
|
+
|
|
537
|
+
```javascript
|
|
538
|
+
output.printBox([
|
|
539
|
+
`Dashboard: ${output.link('', dashboardUrl)}`,
|
|
540
|
+
`Baselines: ${baselineCount} screenshots`
|
|
541
|
+
], { title: 'Ready', style: 'branded' });
|
|
542
|
+
|
|
543
|
+
output.blank();
|
|
544
|
+
output.hint('Press Ctrl+C to stop the server');
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## Accessibility
|
|
548
|
+
|
|
549
|
+
The TUI toolkit is designed with accessibility in mind:
|
|
550
|
+
|
|
551
|
+
- **Color is not the only indicator** - Icons accompany colors (✓, ✗, ⚠, ℹ)
|
|
552
|
+
- **NO_COLOR support** - Respects `NO_COLOR` environment variable
|
|
553
|
+
- **Screen reader friendly** - Unicode characters are widely supported
|
|
554
|
+
- **High contrast** - Colors chosen for visibility on dark backgrounds
|
|
555
|
+
|
|
556
|
+
## Related Documentation
|
|
557
|
+
|
|
558
|
+
- [API Reference](./api-reference.md) - Complete CLI API documentation
|
|
559
|
+
- [Getting Started](./getting-started.md) - Quick start guide
|
|
560
|
+
- [Plugins](./plugins.md) - Creating plugins with TUI access
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizzly-testing/cli",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1-beta.1",
|
|
4
4
|
"description": "Visual review platform for UI developers and designers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"visual-testing",
|
|
@@ -58,25 +58,25 @@
|
|
|
58
58
|
],
|
|
59
59
|
"scripts": {
|
|
60
60
|
"start": "node src/index.js",
|
|
61
|
-
"build": "npm run clean && npm run compile && npm run
|
|
61
|
+
"build": "npm run clean && npm run compile && npm run build:reporter && npm run copy-types",
|
|
62
62
|
"clean": "rimraf dist",
|
|
63
63
|
"compile": "babel src --out-dir dist --ignore '**/*.test.js'",
|
|
64
|
-
"copy-assets": "cp src/services/report-generator/report.css dist/services/report-generator/",
|
|
65
64
|
"copy-types": "mkdir -p dist/types && cp src/types/*.d.ts dist/types/",
|
|
66
65
|
"build:reporter": "cd src/reporter && vite build",
|
|
67
66
|
"dev:reporter": "cd src/reporter && vite --config vite.dev.config.js",
|
|
68
67
|
"test:types": "tsd",
|
|
69
68
|
"prepublishOnly": "npm run build",
|
|
70
|
-
"test": "
|
|
71
|
-
"test:watch": "
|
|
69
|
+
"test": "node --experimental-test-coverage --test --test-concurrency=1 --test-reporter=spec $(find tests -name '*.test.js')",
|
|
70
|
+
"test:watch": "node --test --test-reporter=spec --watch $(find tests -name '*.test.js')",
|
|
72
71
|
"test:reporter": "playwright test --config=tests/reporter/playwright.config.js",
|
|
73
72
|
"test:reporter:visual": "node bin/vizzly.js run \"npm run test:reporter\"",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
73
|
+
"test:tui": "node --test --test-reporter=spec tests/tui/*.test.js",
|
|
74
|
+
"test:tui:docker": "./tests/tui/run-tui-tests.sh",
|
|
75
|
+
"lint": "biome check src tests",
|
|
76
|
+
"lint:fix": "biome check --write --unsafe src tests",
|
|
76
77
|
"format": "biome format --write src tests",
|
|
77
78
|
"format:check": "biome format src tests",
|
|
78
|
-
"
|
|
79
|
-
"check:fix": "biome check --write src tests"
|
|
79
|
+
"fix": "npm run format && npm run lint:fix"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=22.0.0"
|
|
@@ -86,7 +86,8 @@
|
|
|
86
86
|
"registry": "https://registry.npmjs.org/"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@vizzly-testing/honeydiff": "^0.
|
|
89
|
+
"@vizzly-testing/honeydiff": "^0.7.1",
|
|
90
|
+
"ansis": "^4.2.0",
|
|
90
91
|
"commander": "^14.0.0",
|
|
91
92
|
"cosmiconfig": "^9.0.0",
|
|
92
93
|
"dotenv": "^17.2.1",
|
|
@@ -116,9 +117,8 @@
|
|
|
116
117
|
"@playwright/test": "^1.55.1",
|
|
117
118
|
"@tailwindcss/postcss": "^4.1.13",
|
|
118
119
|
"@tanstack/react-query": "^5.90.11",
|
|
119
|
-
"@types/node": "^
|
|
120
|
+
"@types/node": "^25.0.2",
|
|
120
121
|
"@vitejs/plugin-react": "^5.0.3",
|
|
121
|
-
"@vitest/coverage-v8": "^4.0.3",
|
|
122
122
|
"autoprefixer": "^10.4.21",
|
|
123
123
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
|
124
124
|
"postcss": "^8.5.6",
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"rimraf": "^6.0.1",
|
|
128
128
|
"tailwindcss": "^4.1.13",
|
|
129
129
|
"tsd": "^0.33.0",
|
|
130
|
+
"tui-driver": "github:vizzly-testing/tui-driver",
|
|
130
131
|
"typescript": "^5.0.4",
|
|
131
132
|
"vite": "^7.1.7",
|
|
132
|
-
"vitest": "^4.0.3",
|
|
133
133
|
"wouter": "^3.7.1"
|
|
134
134
|
}
|
|
135
135
|
}
|