@vizzly-testing/cli 0.35.3-beta.4 → 0.37.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.
@@ -1,5 +1,10 @@
1
1
  /**
2
- * Run command implementation
2
+ * Run tests and report their visual results in terminal or JSON output.
3
+ *
4
+ * Incomplete uploads preserve the test exit code and skip comparison waiting.
5
+ * After successful uploads, --wait can still fail for visual comparison results.
6
+ * The returned success flag describes command success, not upload completeness.
7
+ *
3
8
  * Uses functional operations directly - no class wrappers needed
4
9
  */
5
10
 
@@ -16,6 +21,14 @@ import { loadConfig as defaultLoadConfig } from '../utils/config-loader.js';
16
21
  import { detectBranch as defaultDetectBranch, detectCommit as defaultDetectCommit, detectCommitMessage as defaultDetectCommitMessage, detectPullRequestNumber as defaultDetectPullRequestNumber, generateBuildNameWithGit as defaultGenerateBuildNameWithGit } from '../utils/git.js';
17
22
  import * as defaultOutput from '../utils/output.js';
18
23
  import { writeSession as defaultWriteSession } from '../utils/session.js';
24
+ function formatUploadCounts({
25
+ total,
26
+ uploaded,
27
+ reused,
28
+ failed
29
+ }) {
30
+ return `${total} captured, ${uploaded} uploaded, ${reused} reused, ${failed} failed`;
31
+ }
19
32
  export async function resolveBuildDisplayUrl({
20
33
  result,
21
34
  config,
@@ -48,19 +61,19 @@ export async function resolveBuildDisplayUrl({
48
61
  /**
49
62
  * Build the follow-up command for a cloud run.
50
63
  *
51
- * JSON consumers need a self-contained command that returns structured
52
- * evidence when executed. Human output keeps the existing readable summary.
64
+ * JSON consumers start with the public schema so they can discover the current
65
+ * request shape. Human output keeps the readable context summary.
53
66
  *
54
67
  * @param {string} buildId - Cloud build ID to inspect.
55
68
  * @param {Object} options - Command output options.
56
69
  * @param {boolean} [options.structured=false] - Include machine-readable JSON.
57
- * @returns {string} Executable build context command.
70
+ * @returns {string} Cloud context or schema discovery command.
58
71
  */
59
72
  function buildContextCommand(buildId, {
60
73
  structured = false
61
74
  } = {}) {
62
- let jsonFlag = structured ? ' --json' : '';
63
- return `vizzly context build ${buildId} --agent${jsonFlag} --source cloud`;
75
+ if (structured) return 'vizzly api schema sdk.getBuildContext --json';
76
+ return `vizzly context build ${buildId} --source cloud`;
64
77
  }
65
78
 
66
79
  /**
@@ -68,7 +81,9 @@ function buildContextCommand(buildId, {
68
81
  * @param {string} testCommand - Test command to execute
69
82
  * @param {Object} options - Command options
70
83
  * @param {Object} globalOptions - Global CLI options
71
- * @param {Object} deps - Dependencies for testing
84
+ * @param {Object} deps - Command services and process hooks.
85
+ * @returns {Promise<Object>} Command outcome with success, an optional exitCode,
86
+ * and run results when available.
72
87
  */
73
88
  export async function runCommand(testCommand, options = {}, globalOptions = {}, deps = {}) {
74
89
  let {
@@ -321,6 +336,33 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
321
336
  if (result.buildId) {
322
337
  buildId = result.buildId;
323
338
  }
339
+ if (result.uploads?.failed > 0) {
340
+ let message = `${result.uploads.failed} screenshot(s) failed to upload. Visual testing is incomplete.`;
341
+ if (globalOptions.json) {
342
+ output.data({
343
+ buildId: result.buildId,
344
+ status: 'incomplete',
345
+ screenshotsCaptured: result.screenshotsCaptured,
346
+ uploads: result.uploads,
347
+ error: {
348
+ code: 'SCREENSHOT_UPLOAD_FAILED',
349
+ message
350
+ },
351
+ url: result.url,
352
+ exitCode: 0
353
+ });
354
+ } else {
355
+ output.warn(message);
356
+ output.print(`Screenshots: ${formatUploadCounts(result.uploads)}`);
357
+ if (result.url) output.info(`Results: ${result.url}`);
358
+ }
359
+ output.cleanup();
360
+ return {
361
+ success: true,
362
+ exitCode: 0,
363
+ result
364
+ };
365
+ }
324
366
 
325
367
  // JSON output mode - output structured data and exit
326
368
  if (globalOptions.json && !runOptions.wait) {
@@ -336,6 +378,9 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
336
378
  status: 'completed',
337
379
  url: displayUrl,
338
380
  screenshotsCaptured: result.screenshotsCaptured || 0,
381
+ ...(result.uploads ? {
382
+ uploads: result.uploads
383
+ } : {}),
339
384
  executionTimeMs,
340
385
  git: {
341
386
  branch,
@@ -362,7 +407,8 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
362
407
  if (result.buildId && !globalOptions.json) {
363
408
  output.blank();
364
409
  let colors = output.getColors();
365
- output.print(` ${colors.brand.textTertiary('Screenshots')} ${colors.white(result.screenshotsCaptured)}`);
410
+ let screenshotSummary = result.uploads ? formatUploadCounts(result.uploads) : result.screenshotsCaptured;
411
+ output.print(` ${colors.brand.textTertiary('Screenshots')} ${colors.white(screenshotSummary)}`);
366
412
  let displayUrl = await resolveBuildDisplayUrl({
367
413
  result,
368
414
  config,
@@ -392,6 +438,9 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
392
438
  output.data({
393
439
  buildId: buildId || null,
394
440
  status: 'failed',
441
+ ...(error.uploads ? {
442
+ uploads: error.uploads
443
+ } : {}),
395
444
  error: {
396
445
  code: error.code,
397
446
  message: error.message
@@ -479,6 +528,9 @@ export async function runCommand(testCommand, options = {}, globalOptions = {},
479
528
  status: buildResult.status,
480
529
  url: displayUrl,
481
530
  screenshotsCaptured: result.screenshotsCaptured || 0,
531
+ ...(result.uploads ? {
532
+ uploads: result.uploads
533
+ } : {}),
482
534
  executionTimeMs,
483
535
  git: {
484
536
  branch,
@@ -94,8 +94,8 @@ export function createStatusSuggestedCommands(build = {}) {
94
94
  return [];
95
95
  }
96
96
  return [{
97
- label: 'Inspect build context',
98
- command: `vizzly --json context build ${build.id} --agent --source cloud`
97
+ label: 'Discover build context API',
98
+ command: 'vizzly api schema sdk.getBuildContext --json'
99
99
  }, {
100
100
  label: 'List comparisons',
101
101
  command: `vizzly --json comparisons --build ${build.id}`
@@ -31,7 +31,7 @@ function buildLocalContextCommand({
31
31
  structured = false
32
32
  } = {}) {
33
33
  let jsonFlag = structured ? ' --json' : '';
34
- return `vizzly context build current --source local --agent${jsonFlag}`;
34
+ return `vizzly context build current --source local${jsonFlag}`;
35
35
  }
36
36
 
37
37
  /**