@vizzly-testing/cli 0.35.2 → 0.35.3-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/README.md +8 -5
- package/dist/api/client.js +20 -5
- package/dist/api/core.js +17 -3
- package/dist/api/endpoints.js +24 -3
- package/dist/api/index.js +1 -1
- package/dist/cli.js +25 -65
- package/dist/commands/baselines.js +0 -7
- package/dist/commands/comparisons.js +52 -45
- package/dist/commands/config-cmd.js +0 -7
- package/dist/commands/context.js +444 -238
- package/dist/commands/doctor.js +0 -8
- package/dist/commands/init.js +7 -12
- package/dist/commands/login.js +0 -13
- package/dist/commands/logout.js +0 -12
- package/dist/commands/orgs.js +0 -9
- package/dist/commands/run.js +84 -29
- package/dist/commands/status.js +276 -59
- package/dist/commands/tdd.js +19 -3
- package/dist/commands/whoami.js +0 -12
- package/dist/context/local-workspace-provider.js +293 -37
- package/dist/plugin-loader.js +1 -1
- package/dist/reporter/reporter-bundle.css +1 -1
- package/dist/reporter/reporter-bundle.iife.js +17 -17
- package/dist/server/routers/events.js +4 -4
- package/dist/test-runner/operations.js +70 -28
- package/dist/types/index.d.ts +4 -2
- package/dist/uploader/core.js +6 -6
- package/dist/uploader/operations.js +4 -1
- package/dist/utils/visual-context-normalizers.js +455 -0
- package/package.json +13 -13
- package/skills/vizzly/SKILL.md +68 -101
- package/skills/vizzly/agents/openai.yaml +2 -2
- package/skills/vizzly/references/cli-context.md +79 -27
- package/skills/vizzly/references/dynamic-content.md +28 -33
- package/skills/vizzly/references/sdks.md +26 -39
- package/skills/vizzly/references/setup-ci.md +44 -20
- package/dist/config/index.js +0 -13
- package/dist/project/index.js +0 -13
- package/dist/tdd/index.js +0 -19
- package/dist/tdd/services/baseline-downloader.js +0 -151
- package/dist/tdd/services/hotspot-service.js +0 -58
- package/dist/utils/environment.js +0 -109
- package/skills/vizzly/references/public-screenshots.md +0 -44
package/dist/commands/doctor.js
CHANGED
|
@@ -264,12 +264,4 @@ export async function doctorCommand(options = {}, globalOptions = {}, deps = {})
|
|
|
264
264
|
output.cleanup();
|
|
265
265
|
if (hasErrors) exit(1);
|
|
266
266
|
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Validate doctor options (no specific validation needed)
|
|
271
|
-
* @param {Object} options - Command options
|
|
272
|
-
*/
|
|
273
|
-
export function validateDoctorOptions() {
|
|
274
|
-
return []; // No specific validation for now
|
|
275
267
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -37,7 +37,7 @@ function configureOutput(output, options) {
|
|
|
37
37
|
export function getInitConfigPath(cwd = process.cwd()) {
|
|
38
38
|
return path.join(cwd, 'vizzly.config.js');
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
function getPackagedAgentSkillPath(baseDir = commandDir) {
|
|
41
41
|
return path.resolve(baseDir, '..', '..', 'skills', 'vizzly');
|
|
42
42
|
}
|
|
43
43
|
export function getProjectAgentSkillPath(cwd = process.cwd()) {
|
|
@@ -54,10 +54,10 @@ export async function fileExists(filePath, access = fs.access) {
|
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
function getPluginsWithConfig(plugins = []) {
|
|
58
58
|
return plugins.filter(plugin => plugin.configSchema);
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
function getPluginConfigNames(plugins = []) {
|
|
61
61
|
return getPluginsWithConfig(plugins).map(plugin => plugin.name);
|
|
62
62
|
}
|
|
63
63
|
function formatObjectKey(key) {
|
|
@@ -115,7 +115,7 @@ export function formatPluginConfig(plugin, output = null) {
|
|
|
115
115
|
return '';
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
|
|
118
|
+
function generatePluginConfigs(plugins = [], output = null) {
|
|
119
119
|
let sections = [];
|
|
120
120
|
for (let plugin of plugins) {
|
|
121
121
|
if (plugin.configSchema) {
|
|
@@ -212,7 +212,7 @@ async function shouldInstallAgentSkill(options, deps) {
|
|
|
212
212
|
}
|
|
213
213
|
let agentGuidanceStart = '<!-- vizzly-agent-guidance -->';
|
|
214
214
|
let agentGuidanceEnd = '<!-- /vizzly-agent-guidance -->';
|
|
215
|
-
|
|
215
|
+
function createAgentGuidanceContent() {
|
|
216
216
|
return `${agentGuidanceStart}
|
|
217
217
|
## Visual Testing With Vizzly
|
|
218
218
|
|
|
@@ -232,7 +232,7 @@ function appendSection(content, section) {
|
|
|
232
232
|
}
|
|
233
233
|
return `${content.replace(/\s*$/, '')}\n\n${section}`;
|
|
234
234
|
}
|
|
235
|
-
|
|
235
|
+
async function upsertProjectAgentGuidance({
|
|
236
236
|
cwd,
|
|
237
237
|
access = fs.access,
|
|
238
238
|
readFile = fs.readFile,
|
|
@@ -362,16 +362,11 @@ async function loadInitPlugins(options, deps) {
|
|
|
362
362
|
}
|
|
363
363
|
try {
|
|
364
364
|
let config = await deps.loadConfig(options.config, {});
|
|
365
|
-
return await deps.loadPlugins(options.config, config
|
|
365
|
+
return await deps.loadPlugins(options.config, config);
|
|
366
366
|
} catch {
|
|
367
367
|
return [];
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
|
-
|
|
371
|
-
// Export factory function for CLI
|
|
372
|
-
export function createInitCommand(options) {
|
|
373
|
-
return () => init(options);
|
|
374
|
-
}
|
|
375
370
|
export async function init(options = {}, deps = {}) {
|
|
376
371
|
let resolvedDeps = createInitDeps(deps);
|
|
377
372
|
configureOutput(resolvedDeps.output, options);
|
package/dist/commands/login.js
CHANGED
|
@@ -236,17 +236,4 @@ export async function loginCommand(options = {}, globalOptions = {}, deps = {})
|
|
|
236
236
|
exit(1);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Validate login options
|
|
243
|
-
* @param {Object} options - Command options
|
|
244
|
-
*/
|
|
245
|
-
export function validateLoginOptions() {
|
|
246
|
-
let errors = [];
|
|
247
|
-
|
|
248
|
-
// No specific validation needed for login command
|
|
249
|
-
// OAuth device flow handles everything via browser
|
|
250
|
-
|
|
251
|
-
return errors;
|
|
252
239
|
}
|
package/dist/commands/logout.js
CHANGED
|
@@ -70,16 +70,4 @@ export async function logoutCommand(options = {}, globalOptions = {}, deps = {})
|
|
|
70
70
|
output.cleanup();
|
|
71
71
|
exit(1);
|
|
72
72
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Validate logout options
|
|
77
|
-
* @param {Object} options - Command options
|
|
78
|
-
*/
|
|
79
|
-
export function validateLogoutOptions() {
|
|
80
|
-
let errors = [];
|
|
81
|
-
|
|
82
|
-
// No specific validation needed for logout command
|
|
83
|
-
|
|
84
|
-
return errors;
|
|
85
73
|
}
|
package/dist/commands/orgs.js
CHANGED
|
@@ -82,13 +82,4 @@ export async function orgsCommand(_options = {}, globalOptions = {}, deps = {})
|
|
|
82
82
|
output.cleanup();
|
|
83
83
|
exit(1);
|
|
84
84
|
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Validate orgs options
|
|
89
|
-
* @param {Object} _options - Command options
|
|
90
|
-
* @returns {string[]} Validation errors
|
|
91
|
-
*/
|
|
92
|
-
export function validateOrgsOptions(_options = {}) {
|
|
93
|
-
return [];
|
|
94
85
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -44,8 +44,23 @@ export async function resolveBuildDisplayUrl({
|
|
|
44
44
|
}
|
|
45
45
|
return undefined;
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Build the follow-up command for a cloud run.
|
|
50
|
+
*
|
|
51
|
+
* JSON consumers need a self-contained command that returns structured
|
|
52
|
+
* evidence when executed. Human output keeps the existing readable summary.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} buildId - Cloud build ID to inspect.
|
|
55
|
+
* @param {Object} options - Command output options.
|
|
56
|
+
* @param {boolean} [options.structured=false] - Include machine-readable JSON.
|
|
57
|
+
* @returns {string} Executable build context command.
|
|
58
|
+
*/
|
|
59
|
+
function buildContextCommand(buildId, {
|
|
60
|
+
structured = false
|
|
61
|
+
} = {}) {
|
|
62
|
+
let jsonFlag = structured ? ' --json' : '';
|
|
63
|
+
return `vizzly context build ${buildId} --agent${jsonFlag} --source cloud`;
|
|
49
64
|
}
|
|
50
65
|
|
|
51
66
|
/**
|
|
@@ -91,6 +106,7 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
91
106
|
let startTime = null;
|
|
92
107
|
let isTddMode = false;
|
|
93
108
|
let config = null;
|
|
109
|
+
let result = null;
|
|
94
110
|
|
|
95
111
|
// Ensure cleanup on exit
|
|
96
112
|
let cleanup = async () => {
|
|
@@ -254,7 +270,6 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
254
270
|
output.info('Starting test execution...');
|
|
255
271
|
startTime = Date.now();
|
|
256
272
|
isTddMode = runOptions.tdd || false;
|
|
257
|
-
let result;
|
|
258
273
|
try {
|
|
259
274
|
result = await runTests({
|
|
260
275
|
runOptions,
|
|
@@ -327,7 +342,9 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
327
342
|
commit,
|
|
328
343
|
message
|
|
329
344
|
},
|
|
330
|
-
contextCommand: result.buildId ? buildContextCommand(result.buildId
|
|
345
|
+
contextCommand: result.buildId ? buildContextCommand(result.buildId, {
|
|
346
|
+
structured: true
|
|
347
|
+
}) : null,
|
|
331
348
|
exitCode: 0
|
|
332
349
|
};
|
|
333
350
|
output.data(jsonResult);
|
|
@@ -396,7 +413,8 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
396
413
|
exitCode
|
|
397
414
|
};
|
|
398
415
|
} else {
|
|
399
|
-
//
|
|
416
|
+
// This should only be reached for failures outside the SDK paths that
|
|
417
|
+
// runTests handles by disabling Vizzly and running the child command.
|
|
400
418
|
if (globalOptions.json) {
|
|
401
419
|
let executionTimeMs = Date.now() - (startTime || Date.now());
|
|
402
420
|
output.data({
|
|
@@ -443,9 +461,22 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
443
461
|
getTokenContext
|
|
444
462
|
});
|
|
445
463
|
let exitCode = buildResult.failedComparisons > 0 ? 1 : 0;
|
|
464
|
+
let comparisons = {};
|
|
465
|
+
if (buildResult.totalComparisons !== undefined) {
|
|
466
|
+
comparisons.total = buildResult.totalComparisons;
|
|
467
|
+
}
|
|
468
|
+
if (buildResult.newComparisons !== undefined) {
|
|
469
|
+
comparisons.new = buildResult.newComparisons;
|
|
470
|
+
}
|
|
471
|
+
if (buildResult.failedComparisons !== undefined) {
|
|
472
|
+
comparisons.changed = buildResult.failedComparisons;
|
|
473
|
+
}
|
|
474
|
+
if (buildResult.identicalComparisons !== undefined) {
|
|
475
|
+
comparisons.identical = buildResult.identicalComparisons;
|
|
476
|
+
}
|
|
446
477
|
let jsonResult = {
|
|
447
478
|
buildId: result.buildId,
|
|
448
|
-
status: buildResult.
|
|
479
|
+
status: buildResult.status,
|
|
449
480
|
url: displayUrl,
|
|
450
481
|
screenshotsCaptured: result.screenshotsCaptured || 0,
|
|
451
482
|
executionTimeMs,
|
|
@@ -454,16 +485,20 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
454
485
|
commit,
|
|
455
486
|
message
|
|
456
487
|
},
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
changed: buildResult.failedComparisons || 0,
|
|
461
|
-
identical: buildResult.identicalComparisons || 0
|
|
462
|
-
},
|
|
463
|
-
approvalStatus: buildResult.approvalStatus || 'pending',
|
|
464
|
-
contextCommand: buildContextCommand(result.buildId),
|
|
488
|
+
contextCommand: buildContextCommand(result.buildId, {
|
|
489
|
+
structured: true
|
|
490
|
+
}),
|
|
465
491
|
exitCode
|
|
466
492
|
};
|
|
493
|
+
if (Object.keys(comparisons).length > 0) {
|
|
494
|
+
jsonResult.comparisons = comparisons;
|
|
495
|
+
}
|
|
496
|
+
if (buildResult.approvalStatus !== undefined) {
|
|
497
|
+
jsonResult.approvalStatus = buildResult.approvalStatus;
|
|
498
|
+
}
|
|
499
|
+
if (buildResult.build?.conclusion !== undefined) {
|
|
500
|
+
jsonResult.conclusion = buildResult.build.conclusion;
|
|
501
|
+
}
|
|
467
502
|
output.data(jsonResult);
|
|
468
503
|
output.cleanup();
|
|
469
504
|
return {
|
|
@@ -492,28 +527,48 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
|
|
|
492
527
|
} catch (error) {
|
|
493
528
|
output.stopSpinner();
|
|
494
529
|
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
530
|
+
// Once the user's tests have passed, no Vizzly-side error can change the
|
|
531
|
+
// test result. Keep that outcome while reporting that the API-backed build
|
|
532
|
+
// status is unavailable instead of inventing a terminal build state.
|
|
533
|
+
if (result) {
|
|
534
|
+
let apiBuild = error.context?.build;
|
|
535
|
+
let buildStatus = apiBuild?.status ?? null;
|
|
536
|
+
let exitCode = buildStatus === 'failed' ? 1 : 0;
|
|
537
|
+
let errorDetails = {
|
|
538
|
+
code: error.code || 'VIZZLY_STATUS_UNAVAILABLE',
|
|
539
|
+
message: error.getUserMessage ? error.getUserMessage() : error.message
|
|
540
|
+
};
|
|
541
|
+
let unavailableResult = {
|
|
542
|
+
buildId: result.buildId || null,
|
|
543
|
+
status: buildStatus,
|
|
544
|
+
testsPassed: true,
|
|
545
|
+
error: errorDetails,
|
|
546
|
+
executionTimeMs: Date.now() - (startTime || Date.now()),
|
|
547
|
+
exitCode
|
|
548
|
+
};
|
|
549
|
+
if (apiBuild?.conclusion !== undefined) {
|
|
550
|
+
unavailableResult.conclusion = apiBuild.conclusion;
|
|
551
|
+
}
|
|
552
|
+
if (result.buildId) {
|
|
553
|
+
unavailableResult.contextCommand = buildContextCommand(result.buildId, {
|
|
554
|
+
structured: true
|
|
504
555
|
});
|
|
556
|
+
}
|
|
557
|
+
if (globalOptions.json) {
|
|
558
|
+
output.data(unavailableResult);
|
|
559
|
+
} else if (buildStatus === 'failed') {
|
|
560
|
+
output.error(errorDetails.message);
|
|
505
561
|
} else {
|
|
506
|
-
output.warn(
|
|
562
|
+
output.warn(`Tests passed, but Vizzly could not confirm the build status: ${errorDetails.message}`);
|
|
507
563
|
}
|
|
508
564
|
output.cleanup();
|
|
509
|
-
output.debug('
|
|
565
|
+
output.debug('run', 'Vizzly SDK error details', {
|
|
510
566
|
error: error.message
|
|
511
567
|
});
|
|
512
568
|
return {
|
|
513
|
-
success:
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
569
|
+
success: exitCode === 0,
|
|
570
|
+
exitCode,
|
|
571
|
+
result: unavailableResult
|
|
517
572
|
};
|
|
518
573
|
}
|
|
519
574
|
|