@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { existsSync as defaultExistsSync, readFileSync } from 'node:fs';
|
|
2
3
|
import { basename, isAbsolute, join } from 'node:path';
|
|
3
4
|
import { pathToFileURL } from 'node:url';
|
|
@@ -140,17 +141,28 @@ function buildComparisonLinks(snapshot, comparisonId) {
|
|
|
140
141
|
comparison_url: `http://127.0.0.1:${snapshot.serverInfo.port}/comparison/${encodeURIComponent(comparisonId)}`
|
|
141
142
|
};
|
|
142
143
|
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Describe the local evidence set without borrowing cloud run identity.
|
|
147
|
+
*
|
|
148
|
+
* A cloud `session.json` can coexist with older file-backed TDD evidence. Using
|
|
149
|
+
* that session here makes stale local comparisons look like the current cloud
|
|
150
|
+
* build, so local identity comes only from the active local server.
|
|
151
|
+
*
|
|
152
|
+
* @param {Object} snapshot - Persisted local workspace evidence.
|
|
153
|
+
* @returns {Object} Build-shaped identity for the local context payload.
|
|
154
|
+
*/
|
|
143
155
|
function buildBuildSnapshot(snapshot) {
|
|
144
|
-
let buildId = snapshot.
|
|
156
|
+
let buildId = snapshot.serverInfo?.buildId || 'local-workspace';
|
|
145
157
|
return {
|
|
146
158
|
id: buildId,
|
|
147
159
|
name: buildId,
|
|
148
|
-
branch:
|
|
149
|
-
commit_sha:
|
|
160
|
+
branch: 'local',
|
|
161
|
+
commit_sha: null,
|
|
150
162
|
commit_message: null,
|
|
151
163
|
approval_status: snapshot.serverInfo ? 'pending' : 'approved',
|
|
152
164
|
status: snapshot.serverInfo ? 'running' : 'completed',
|
|
153
|
-
created_at:
|
|
165
|
+
created_at: null
|
|
154
166
|
};
|
|
155
167
|
}
|
|
156
168
|
function buildBaselineSnapshot(snapshot) {
|
|
@@ -193,31 +205,6 @@ function buildReviewState(build, reviewSummary) {
|
|
|
193
205
|
unresolved_comments: 0
|
|
194
206
|
};
|
|
195
207
|
}
|
|
196
|
-
function mapLocalScreenshot(snapshot, comparison) {
|
|
197
|
-
let mapped = mapLocalComparison(snapshot, comparison);
|
|
198
|
-
let baselineBuildId = snapshot.baselineMetadata?.buildId || null;
|
|
199
|
-
return {
|
|
200
|
-
id: mapped.screenshot.id,
|
|
201
|
-
name: mapped.screenshot.name,
|
|
202
|
-
browser: mapped.screenshot.browser,
|
|
203
|
-
viewport: {
|
|
204
|
-
width: mapped.screenshot.viewport_width,
|
|
205
|
-
height: mapped.screenshot.viewport_height
|
|
206
|
-
},
|
|
207
|
-
url: mapped.screenshot.original_url,
|
|
208
|
-
baseline: mapped.baseline ? {
|
|
209
|
-
id: mapped.baseline.id,
|
|
210
|
-
build_id: baselineBuildId,
|
|
211
|
-
name: mapped.baseline.name,
|
|
212
|
-
browser: mapped.baseline.browser,
|
|
213
|
-
viewport: {
|
|
214
|
-
width: mapped.baseline.viewport_width,
|
|
215
|
-
height: mapped.baseline.viewport_height
|
|
216
|
-
},
|
|
217
|
-
url: mapped.baseline.original_url
|
|
218
|
-
} : null
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
208
|
function mapLocalComparison(snapshot, comparison) {
|
|
222
209
|
let details = snapshot.comparisonDetails[comparison.id] || {};
|
|
223
210
|
let comparisonName = comparison.originalName || comparison.name;
|
|
@@ -295,6 +282,141 @@ function mapLocalComparison(snapshot, comparison) {
|
|
|
295
282
|
}
|
|
296
283
|
};
|
|
297
284
|
}
|
|
285
|
+
function projectLocalScreenshot(screenshot, baseline) {
|
|
286
|
+
if (!screenshot) return null;
|
|
287
|
+
return {
|
|
288
|
+
id: screenshot.id,
|
|
289
|
+
name: screenshot.name,
|
|
290
|
+
browser: screenshot.browser,
|
|
291
|
+
viewport: {
|
|
292
|
+
width: screenshot.viewport_width,
|
|
293
|
+
height: screenshot.viewport_height
|
|
294
|
+
},
|
|
295
|
+
url: screenshot.original_url,
|
|
296
|
+
baseline: baseline ? {
|
|
297
|
+
id: baseline.id,
|
|
298
|
+
build_id: baseline.build_id,
|
|
299
|
+
name: baseline.name,
|
|
300
|
+
browser: baseline.browser,
|
|
301
|
+
viewport: {
|
|
302
|
+
width: baseline.viewport_width,
|
|
303
|
+
height: baseline.viewport_height
|
|
304
|
+
},
|
|
305
|
+
url: baseline.original_url
|
|
306
|
+
} : null
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function projectLocalDiff(diff, includeDiffs) {
|
|
310
|
+
let projected = {
|
|
311
|
+
percentage: diff?.percentage ?? null,
|
|
312
|
+
changed_pixels: diff?.changed_pixels ?? null,
|
|
313
|
+
total_pixels: diff?.total_pixels ?? null,
|
|
314
|
+
threshold: diff?.threshold ?? null,
|
|
315
|
+
image_url: diff?.image_url ?? null,
|
|
316
|
+
fingerprint_hash: diff?.fingerprint_hash ?? null,
|
|
317
|
+
region_count: Array.isArray(diff?.regions) ? diff.regions.length : null
|
|
318
|
+
};
|
|
319
|
+
if (includeDiffs) {
|
|
320
|
+
projected.regions = diff?.regions || [];
|
|
321
|
+
projected.cluster_metadata = diff?.cluster_metadata ?? null;
|
|
322
|
+
projected.fingerprint_data = diff?.fingerprint_data ?? null;
|
|
323
|
+
projected.diff_lines = diff?.diff_lines ?? [];
|
|
324
|
+
}
|
|
325
|
+
return projected;
|
|
326
|
+
}
|
|
327
|
+
function projectLocalEvidence(comparison, includeDiffs) {
|
|
328
|
+
return {
|
|
329
|
+
type: 'comparison',
|
|
330
|
+
id: comparison.id,
|
|
331
|
+
screenshot_name: comparison.screenshot_name,
|
|
332
|
+
status: comparison.status,
|
|
333
|
+
result: comparison.result,
|
|
334
|
+
approval_status: comparison.approval_status,
|
|
335
|
+
needs_review: comparison.needs_review,
|
|
336
|
+
build_id: comparison.build_id,
|
|
337
|
+
build_name: comparison.build_name,
|
|
338
|
+
build_branch: comparison.build_branch,
|
|
339
|
+
build_commit_sha: comparison.build_commit_sha,
|
|
340
|
+
build_created_at: comparison.build_created_at,
|
|
341
|
+
screenshot: projectLocalScreenshot(comparison.screenshot, comparison.baseline),
|
|
342
|
+
diff: projectLocalDiff(comparison.diff, includeDiffs)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function projectLocalFocusedComparison(comparison, includeDiffs) {
|
|
346
|
+
if (includeDiffs) return comparison;
|
|
347
|
+
let analysis = comparison.analysis || {};
|
|
348
|
+
let {
|
|
349
|
+
diff_regions: _diffRegions,
|
|
350
|
+
cluster_metadata: _clusterMetadata,
|
|
351
|
+
fingerprint_data: _fingerprintData,
|
|
352
|
+
diff_lines: _diffLines,
|
|
353
|
+
...summaryAnalysis
|
|
354
|
+
} = analysis;
|
|
355
|
+
return {
|
|
356
|
+
...comparison,
|
|
357
|
+
diff: projectLocalDiff(comparison.diff, false),
|
|
358
|
+
analysis: summaryAnalysis
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function projectLocalHistoryItem(comparison) {
|
|
362
|
+
return {
|
|
363
|
+
id: comparison.id,
|
|
364
|
+
screenshot_name: comparison.screenshot_name,
|
|
365
|
+
result: comparison.result,
|
|
366
|
+
status: comparison.status,
|
|
367
|
+
needs_review: comparison.needs_review,
|
|
368
|
+
build_id: comparison.build_id,
|
|
369
|
+
build_name: comparison.build_name,
|
|
370
|
+
build_branch: comparison.build_branch,
|
|
371
|
+
build_created_at: comparison.build_created_at,
|
|
372
|
+
screenshot: projectLocalScreenshot(comparison.screenshot, comparison.baseline),
|
|
373
|
+
diff: {
|
|
374
|
+
percentage: comparison.diff?.percentage ?? null,
|
|
375
|
+
fingerprint_hash: comparison.diff?.fingerprint_hash ?? null,
|
|
376
|
+
region_count: Array.isArray(comparison.diff?.regions) ? comparison.diff.regions.length : null
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function compactLocalCollection(items) {
|
|
381
|
+
return {
|
|
382
|
+
total: Array.isArray(items) ? items.length : null,
|
|
383
|
+
included: false,
|
|
384
|
+
details_available: Array.isArray(items) && items.length > 0
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function createLocalDynamicRegions(comparison = null) {
|
|
388
|
+
let confirmedRegions = comparison?.analysis?.confirmed_regions;
|
|
389
|
+
let hotspotAnalysis = comparison?.analysis?.hotspot_analysis;
|
|
390
|
+
return {
|
|
391
|
+
decision: null,
|
|
392
|
+
patterns: compactLocalCollection([]),
|
|
393
|
+
confirmed_regions: compactLocalCollection(confirmedRegions),
|
|
394
|
+
exclusions: {
|
|
395
|
+
total: null,
|
|
396
|
+
included: false,
|
|
397
|
+
details_available: false
|
|
398
|
+
},
|
|
399
|
+
hotspot_analysis: hotspotAnalysis ? {
|
|
400
|
+
total_builds_analyzed: hotspotAnalysis.total_builds_analyzed ?? null,
|
|
401
|
+
confidence: hotspotAnalysis.confidence ?? null,
|
|
402
|
+
confidence_score: hotspotAnalysis.confidence_score ?? null,
|
|
403
|
+
data_source: hotspotAnalysis.data_source ?? null,
|
|
404
|
+
coverage: hotspotAnalysis.coverage ?? null,
|
|
405
|
+
confirmed_region_coverage: hotspotAnalysis.confirmed_region_coverage ?? null
|
|
406
|
+
} : null
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function createLocalSnapshotRevision(snapshot) {
|
|
410
|
+
let revisionInput = {
|
|
411
|
+
serverInfo: snapshot.serverInfo,
|
|
412
|
+
reportData: snapshot.reportData,
|
|
413
|
+
comparisonDetails: snapshot.comparisonDetails,
|
|
414
|
+
baselineMetadata: snapshot.baselineMetadata,
|
|
415
|
+
hotspotFile: snapshot.hotspotFile,
|
|
416
|
+
regionFile: snapshot.regionFile
|
|
417
|
+
};
|
|
418
|
+
return createHash('sha256').update(JSON.stringify(revisionInput)).digest('base64url');
|
|
419
|
+
}
|
|
298
420
|
function buildReviewSummary(comparisons = []) {
|
|
299
421
|
let approved = comparisons.filter(comparison => mapApprovalStatus(comparison.status) === 'approved').length;
|
|
300
422
|
let rejected = comparisons.filter(comparison => mapApprovalStatus(comparison.status) === 'rejected').length;
|
|
@@ -333,7 +455,6 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
333
455
|
vizzlyDir,
|
|
334
456
|
existsSync,
|
|
335
457
|
serverInfo: readJson(join(vizzlyDir, 'server.json')),
|
|
336
|
-
session: readJson(join(vizzlyDir, 'session.json')),
|
|
337
458
|
reportData: normalizeReportData(readJson(join(vizzlyDir, 'report-data.json')) || createEmptyReportData()),
|
|
338
459
|
comparisonDetails: readJson(join(vizzlyDir, 'comparison-details.json')) || {},
|
|
339
460
|
baselineMetadata: readJson(join(vizzlyDir, 'baselines', 'metadata.json')),
|
|
@@ -345,7 +466,7 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
345
466
|
return snapshotCache;
|
|
346
467
|
}
|
|
347
468
|
function isAvailable(snapshot = loadSnapshot()) {
|
|
348
|
-
return Boolean(snapshot.serverInfo || snapshot.
|
|
469
|
+
return Boolean(snapshot.serverInfo || snapshot.reportData.comparisons.length > 0 || snapshot.baselineMetadata);
|
|
349
470
|
}
|
|
350
471
|
function findComparison(snapshot, target) {
|
|
351
472
|
if (!target) {
|
|
@@ -395,17 +516,66 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
395
516
|
} : {})
|
|
396
517
|
};
|
|
397
518
|
}
|
|
398
|
-
function
|
|
519
|
+
function createLocalCursor(resource, target, query, stream, offset, revision) {
|
|
520
|
+
return Buffer.from(JSON.stringify({
|
|
521
|
+
version: 1,
|
|
522
|
+
resource,
|
|
523
|
+
target,
|
|
524
|
+
query,
|
|
525
|
+
stream,
|
|
526
|
+
offset,
|
|
527
|
+
revision
|
|
528
|
+
})).toString('base64url');
|
|
529
|
+
}
|
|
530
|
+
function readLocalCursor(cursor, resource, target, query, revision, streams) {
|
|
531
|
+
if (!cursor) return null;
|
|
532
|
+
try {
|
|
533
|
+
let parsed = JSON.parse(Buffer.from(cursor, 'base64url').toString());
|
|
534
|
+
if (parsed.version !== 1 || parsed.resource !== resource || parsed.target !== target || parsed.query !== query || parsed.revision !== revision || !streams.includes(parsed.stream) || !Number.isInteger(parsed.offset) || parsed.offset < 0) {
|
|
535
|
+
throw new Error('mismatch');
|
|
536
|
+
}
|
|
537
|
+
return parsed;
|
|
538
|
+
} catch {
|
|
539
|
+
throw createLocalWorkspaceError('The local context cursor is invalid or the local results changed. Start again without --cursor.');
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function createLocalPage(items, {
|
|
543
|
+
limit,
|
|
544
|
+
offset,
|
|
545
|
+
resource,
|
|
546
|
+
target,
|
|
547
|
+
query,
|
|
548
|
+
stream,
|
|
549
|
+
revision
|
|
550
|
+
}) {
|
|
551
|
+
if (offset > items.length) {
|
|
552
|
+
throw createLocalWorkspaceError('The local context cursor is invalid or the local results changed. Start again without --cursor.');
|
|
553
|
+
}
|
|
554
|
+
let pageItems = items.slice(offset, offset + limit);
|
|
555
|
+
let nextOffset = offset + pageItems.length;
|
|
556
|
+
let hasMore = nextOffset < items.length;
|
|
557
|
+
return {
|
|
558
|
+
items: pageItems,
|
|
559
|
+
page: {
|
|
560
|
+
limit,
|
|
561
|
+
returned: pageItems.length,
|
|
562
|
+
total: items.length,
|
|
563
|
+
has_more: hasMore,
|
|
564
|
+
next_cursor: hasMore ? createLocalCursor(resource, target, query, stream, nextOffset, revision) : null
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function getBuildContext(buildId, query = {}) {
|
|
399
569
|
let snapshot = loadSnapshot();
|
|
400
570
|
let resolvedBuild = buildBuildSnapshot(snapshot);
|
|
401
571
|
if (!(buildId === 'current' || buildId === 'local' || buildId === resolvedBuild.id)) {
|
|
402
|
-
throw createLocalWorkspaceError(`Local workspace context is only available for the active
|
|
572
|
+
throw createLocalWorkspaceError(`Local workspace context is only available for the active local build (${resolvedBuild.id})`);
|
|
403
573
|
}
|
|
404
574
|
let mappedComparisons = snapshot.reportData.comparisons.map(comparison => mapLocalComparison(snapshot, comparison));
|
|
405
|
-
let mappedScreenshots =
|
|
575
|
+
let mappedScreenshots = mappedComparisons.map(comparison => projectLocalScreenshot(comparison.screenshot, comparison.baseline));
|
|
406
576
|
let reviewSummary = buildReviewSummary(snapshot.reportData.comparisons);
|
|
407
577
|
let reviewState = buildReviewState(resolvedBuild, reviewSummary);
|
|
408
|
-
|
|
578
|
+
let context = {
|
|
409
579
|
resource: 'build_context',
|
|
410
580
|
source: LOCAL_CONTEXT_SOURCE,
|
|
411
581
|
scope: createScope(),
|
|
@@ -436,8 +606,48 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
436
606
|
},
|
|
437
607
|
links: createBuildLinks(snapshot)
|
|
438
608
|
};
|
|
609
|
+
if (!query.details) return context;
|
|
610
|
+
let revision = createLocalSnapshotRevision(snapshot);
|
|
611
|
+
let limit = query.limit || 10;
|
|
612
|
+
let cursorQuery = `${query.details}:${limit}`;
|
|
613
|
+
let cursor = readLocalCursor(query.cursor, 'build_context', resolvedBuild.id, cursorQuery, revision, ['evidence']);
|
|
614
|
+
let includeDiffs = query.details === 'diffs';
|
|
615
|
+
let evidence = mappedComparisons.map(comparison => projectLocalEvidence(comparison, includeDiffs));
|
|
616
|
+
return {
|
|
617
|
+
resource: 'build_context',
|
|
618
|
+
source: LOCAL_CONTEXT_SOURCE,
|
|
619
|
+
scope: context.scope,
|
|
620
|
+
build: context.build,
|
|
621
|
+
baseline: context.baseline,
|
|
622
|
+
status: context.status,
|
|
623
|
+
summary: context.summary,
|
|
624
|
+
preview: null,
|
|
625
|
+
signature_properties: [],
|
|
626
|
+
dynamic_regions: {
|
|
627
|
+
exclusions: {
|
|
628
|
+
total: null,
|
|
629
|
+
included: false,
|
|
630
|
+
details_available: false
|
|
631
|
+
},
|
|
632
|
+
item_details_included: false
|
|
633
|
+
},
|
|
634
|
+
evidence: createLocalPage(evidence, {
|
|
635
|
+
limit,
|
|
636
|
+
offset: cursor?.offset || 0,
|
|
637
|
+
resource: 'build_context',
|
|
638
|
+
target: resolvedBuild.id,
|
|
639
|
+
query: cursorQuery,
|
|
640
|
+
stream: 'evidence',
|
|
641
|
+
revision
|
|
642
|
+
}),
|
|
643
|
+
comments: {
|
|
644
|
+
build: compactLocalCollection(context.comments.build),
|
|
645
|
+
screenshot_count: context.comments.screenshot_count
|
|
646
|
+
},
|
|
647
|
+
links: context.links
|
|
648
|
+
};
|
|
439
649
|
}
|
|
440
|
-
function getComparisonContext(comparisonId) {
|
|
650
|
+
function getComparisonContext(comparisonId, query = {}) {
|
|
441
651
|
let snapshot = loadSnapshot();
|
|
442
652
|
let comparison = findComparison(snapshot, comparisonId);
|
|
443
653
|
if (!comparison) {
|
|
@@ -446,7 +656,7 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
446
656
|
let mappedComparison = mapLocalComparison(snapshot, comparison);
|
|
447
657
|
let comparisonName = comparison.originalName || comparison.name;
|
|
448
658
|
let history = snapshot.reportData.comparisons.filter(candidate => candidate.id !== comparison.id && (candidate.originalName || candidate.name) === comparisonName).map(candidate => mapLocalComparison(snapshot, candidate));
|
|
449
|
-
|
|
659
|
+
let context = {
|
|
450
660
|
resource: 'comparison_context',
|
|
451
661
|
source: LOCAL_CONTEXT_SOURCE,
|
|
452
662
|
scope: createScope(),
|
|
@@ -475,6 +685,52 @@ export function createLocalWorkspaceContextProvider(options = {}, deps = {}) {
|
|
|
475
685
|
},
|
|
476
686
|
links: buildComparisonLinks(snapshot, comparison.id)
|
|
477
687
|
};
|
|
688
|
+
if (!query.details) return context;
|
|
689
|
+
let revision = createLocalSnapshotRevision(snapshot);
|
|
690
|
+
let limit = query.limit || 10;
|
|
691
|
+
let cursorQuery = `${query.details}:${limit}`;
|
|
692
|
+
let cursor = readLocalCursor(query.cursor, 'comparison_context', comparison.id, cursorQuery, revision, ['similar_by_fingerprint', 'recent_by_name']);
|
|
693
|
+
let activeStream = cursor?.stream;
|
|
694
|
+
let similarOffset = activeStream === 'similar_by_fingerprint' ? cursor.offset : 0;
|
|
695
|
+
let recentOffset = activeStream === 'recent_by_name' ? cursor.offset : 0;
|
|
696
|
+
return {
|
|
697
|
+
resource: 'comparison_context',
|
|
698
|
+
source: LOCAL_CONTEXT_SOURCE,
|
|
699
|
+
scope: context.scope,
|
|
700
|
+
build: context.build,
|
|
701
|
+
signature_properties: [],
|
|
702
|
+
comparison: projectLocalFocusedComparison(context.comparison, query.details === 'diffs'),
|
|
703
|
+
dynamic_regions: createLocalDynamicRegions(context.comparison),
|
|
704
|
+
history: {
|
|
705
|
+
active_stream: activeStream || null,
|
|
706
|
+
similar_by_fingerprint: createLocalPage([], {
|
|
707
|
+
limit,
|
|
708
|
+
offset: similarOffset,
|
|
709
|
+
resource: 'comparison_context',
|
|
710
|
+
target: comparison.id,
|
|
711
|
+
query: cursorQuery,
|
|
712
|
+
stream: 'similar_by_fingerprint',
|
|
713
|
+
revision
|
|
714
|
+
}),
|
|
715
|
+
recent_by_name: createLocalPage(history.map(projectLocalHistoryItem), {
|
|
716
|
+
limit,
|
|
717
|
+
offset: recentOffset,
|
|
718
|
+
resource: 'comparison_context',
|
|
719
|
+
target: comparison.id,
|
|
720
|
+
query: cursorQuery,
|
|
721
|
+
stream: 'recent_by_name',
|
|
722
|
+
revision
|
|
723
|
+
})
|
|
724
|
+
},
|
|
725
|
+
review: {
|
|
726
|
+
review_summary: context.review.review_summary,
|
|
727
|
+
assignments: compactLocalCollection(context.review.assignments),
|
|
728
|
+
build_comments: compactLocalCollection(context.review.build_comments),
|
|
729
|
+
screenshot_comments: compactLocalCollection(context.review.screenshot_comments)
|
|
730
|
+
},
|
|
731
|
+
links: context.links,
|
|
732
|
+
details: query.details
|
|
733
|
+
};
|
|
478
734
|
}
|
|
479
735
|
function getScreenshotContext(screenshotName) {
|
|
480
736
|
let snapshot = loadSnapshot();
|
package/dist/plugin-loader.js
CHANGED
|
@@ -55,7 +55,7 @@ export async function loadPlugins(configPath, config) {
|
|
|
55
55
|
* Discover installed plugins from node_modules/@vizzly-testing/*
|
|
56
56
|
* @returns {Promise<Array>} Array of plugin info objects
|
|
57
57
|
*/
|
|
58
|
-
|
|
58
|
+
async function discoverInstalledPlugins() {
|
|
59
59
|
let plugins = [];
|
|
60
60
|
try {
|
|
61
61
|
// Find all @vizzly-testing packages
|