openspec-playwright 0.3.47 → 0.3.48
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 +3 -0
- package/dist/commands/audit.js +5 -3
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/coverage.d.ts +41 -0
- package/dist/commands/coverage.js +368 -0
- package/dist/commands/coverage.js.map +1 -0
- package/dist/commands/flake.d.ts +23 -0
- package/dist/commands/flake.js +311 -0
- package/dist/commands/flake.js.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/visionCheck.d.ts +0 -35
- package/dist/commands/visionCheck.js +0 -351
- package/dist/commands/visionCheck.js.map +0 -1
- package/dist/utils/ollama.d.ts +0 -73
- package/dist/utils/ollama.js +0 -619
- package/dist/utils/ollama.js.map +0 -1
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vision check command: Analyze screenshots for layout anomalies using Ollama VLM.
|
|
3
|
-
*
|
|
4
|
-
* Modes:
|
|
5
|
-
* --screenshots "..." Analyze existing files (single mode)
|
|
6
|
-
* --url ... --viewport ... Capture from URL at multiple viewports
|
|
7
|
-
* --baseline Save as baseline (with --screenshots or --url+viewport)
|
|
8
|
-
* --diff Compare against baseline
|
|
9
|
-
* --report <path> Generate HTML report
|
|
10
|
-
*
|
|
11
|
-
* Exit codes:
|
|
12
|
-
* 0 = Check completed (with or without anomalies)
|
|
13
|
-
* 1 = Ollama not available (skipped)
|
|
14
|
-
* 2 = Configuration missing or invalid (skipped)
|
|
15
|
-
*/
|
|
16
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
17
|
-
import { join, basename } from "path";
|
|
18
|
-
import { glob } from "glob";
|
|
19
|
-
import chalk from "chalk";
|
|
20
|
-
import { chromium } from "playwright";
|
|
21
|
-
import { loadOllamaConfig, checkOllamaHealth, batchAnalyzeScreenshots, compareScreenshotDiff, generateHtmlReport, } from "../utils/ollama.js";
|
|
22
|
-
/**
|
|
23
|
-
* Extract route name from screenshot path.
|
|
24
|
-
* e.g., "__screenshots__/dashboard.png" → "/dashboard"
|
|
25
|
-
* "__screenshots__/settings-profile.png" → "/settings/profile"
|
|
26
|
-
*/
|
|
27
|
-
function extractRouteFromPath(screenshotPath) {
|
|
28
|
-
const name = basename(screenshotPath, ".png");
|
|
29
|
-
// Convert dashes back to slashes, handle root
|
|
30
|
-
if (name === "index" || name === "home" || name === "root") {
|
|
31
|
-
return "/";
|
|
32
|
-
}
|
|
33
|
-
return "/" + name.replace(/-/g, "/");
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Resolve screenshot paths from glob or comma-separated list.
|
|
37
|
-
*/
|
|
38
|
-
async function resolveScreenshots(pattern) {
|
|
39
|
-
// Check if comma-separated list
|
|
40
|
-
if (pattern.includes(",") && !pattern.includes("*")) {
|
|
41
|
-
return pattern.split(",").map((p) => ({
|
|
42
|
-
path: p.trim(),
|
|
43
|
-
route: extractRouteFromPath(p.trim()),
|
|
44
|
-
}));
|
|
45
|
-
}
|
|
46
|
-
// Glob pattern
|
|
47
|
-
const paths = await glob(pattern, { absolute: true });
|
|
48
|
-
return paths.map((p) => ({
|
|
49
|
-
path: p,
|
|
50
|
-
route: extractRouteFromPath(p),
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Filter anomalies by severity level.
|
|
55
|
-
*/
|
|
56
|
-
function filterBySeverity(anomalies, severityFilter) {
|
|
57
|
-
const levels = severityFilter.toLowerCase().split(",").map((s) => s.trim());
|
|
58
|
-
return anomalies.filter((a) => levels.includes(a.severity));
|
|
59
|
-
}
|
|
60
|
-
// ── Viewport presets ───────────────────────────────────────────────────────────
|
|
61
|
-
const VIEWPORT_PRESETS = {
|
|
62
|
-
mobile: { width: 375, height: 667 },
|
|
63
|
-
tablet: { width: 768, height: 1024 },
|
|
64
|
-
desktop: { width: 1280, height: 720 },
|
|
65
|
-
wide: { width: 1920, height: 1080 },
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Parse viewport string: "mobile,desktop" or "375x667,1280x720"
|
|
69
|
-
*/
|
|
70
|
-
function parseViewports(input) {
|
|
71
|
-
return input.split(",").map((v) => {
|
|
72
|
-
const name = v.trim().toLowerCase();
|
|
73
|
-
if (VIEWPORT_PRESETS[name]) {
|
|
74
|
-
return { name, ...VIEWPORT_PRESETS[name] };
|
|
75
|
-
}
|
|
76
|
-
const parts = name.split("x");
|
|
77
|
-
if (parts.length === 2) {
|
|
78
|
-
const w = parseInt(parts[0], 10);
|
|
79
|
-
const h = parseInt(parts[1], 10);
|
|
80
|
-
if (w > 0 && h > 0) {
|
|
81
|
-
return { name: `${w}x${h}`, width: w, height: h };
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
throw new Error(`Invalid viewport: "${v}". Use presets (mobile/tablet/desktop/wide) or WxH (e.g. 375x667)`);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
// ── Baseline paths ───────────────────────────────────────────────────────────
|
|
88
|
-
const BASELINE_DIR = ".openspec-pw/vision-baseline";
|
|
89
|
-
const DIFF_DIR = ".openspec-pw/vision-diff";
|
|
90
|
-
/**
|
|
91
|
-
* Capture screenshots from a URL at multiple viewports using Playwright.
|
|
92
|
-
*/
|
|
93
|
-
async function captureFromUrl(url, viewports, outputDir, concurrency = 2) {
|
|
94
|
-
const results = [];
|
|
95
|
-
mkdirSync(outputDir, { recursive: true });
|
|
96
|
-
let browser = null;
|
|
97
|
-
try {
|
|
98
|
-
browser = await chromium.launch({ headless: true });
|
|
99
|
-
for (let i = 0; i < viewports.length; i += concurrency) {
|
|
100
|
-
const batch = viewports.slice(i, i + concurrency);
|
|
101
|
-
const batchPromises = batch.map(async (vp) => {
|
|
102
|
-
// Each viewport gets its own context so viewport size doesn't affect other captures
|
|
103
|
-
const context = await browser.newContext({
|
|
104
|
-
viewport: { width: vp.width, height: vp.height },
|
|
105
|
-
});
|
|
106
|
-
const page = await context.newPage();
|
|
107
|
-
try {
|
|
108
|
-
await page.goto(url, { waitUntil: "networkidle", timeout: 30000 });
|
|
109
|
-
const filename = `${vp.name}.png`;
|
|
110
|
-
const filepath = join(outputDir, filename);
|
|
111
|
-
await page.screenshot({ path: filepath, fullPage: true });
|
|
112
|
-
return { path: filepath, route: `${vp.name}:${url}`, viewport: vp.name };
|
|
113
|
-
}
|
|
114
|
-
finally {
|
|
115
|
-
await context.close();
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
const batchResults = await Promise.all(batchPromises);
|
|
119
|
-
results.push(...batchResults);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
if (browser)
|
|
124
|
-
await browser.close();
|
|
125
|
-
}
|
|
126
|
-
return results;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Copy screenshots to baseline directory.
|
|
130
|
-
*/
|
|
131
|
-
function saveBaseline(screenshots, projectRoot) {
|
|
132
|
-
const baselineDir = join(projectRoot, BASELINE_DIR);
|
|
133
|
-
mkdirSync(baselineDir, { recursive: true });
|
|
134
|
-
for (const s of screenshots) {
|
|
135
|
-
const base = basename(s.path, ".png");
|
|
136
|
-
const name = s.viewport
|
|
137
|
-
? `${base}-${s.viewport}-baseline.png`
|
|
138
|
-
: `${base}-baseline.png`;
|
|
139
|
-
const dest = join(baselineDir, name);
|
|
140
|
-
writeFileSync(dest, readFileSync(s.path));
|
|
141
|
-
console.log(chalk.green(` ✓ Baseline saved: ${dest}`));
|
|
142
|
-
}
|
|
143
|
-
return baselineDir;
|
|
144
|
-
}
|
|
145
|
-
// ── Main command ─────────────────────────────────────────────────────────────
|
|
146
|
-
/**
|
|
147
|
-
* Main vision check command.
|
|
148
|
-
*/
|
|
149
|
-
export async function visionCheck(options) {
|
|
150
|
-
const projectRoot = process.cwd();
|
|
151
|
-
// 0. Validate required arguments
|
|
152
|
-
if (!options.screenshots && !(options.viewport && options.url)) {
|
|
153
|
-
console.log(chalk.yellow("Error: Provide --screenshots <pattern> or --url <url> --viewport <views>"));
|
|
154
|
-
process.exit(2);
|
|
155
|
-
}
|
|
156
|
-
// 1. Validate threshold
|
|
157
|
-
if (options.threshold !== undefined && (options.threshold < 0 || options.threshold > 1)) {
|
|
158
|
-
console.log(chalk.yellow("Error: --threshold must be between 0 and 1"));
|
|
159
|
-
process.exit(2);
|
|
160
|
-
}
|
|
161
|
-
// 2. Load configuration
|
|
162
|
-
const config = loadOllamaConfig(projectRoot);
|
|
163
|
-
if (!config.enabled) {
|
|
164
|
-
const result = {
|
|
165
|
-
processed: 0,
|
|
166
|
-
anomalies: [],
|
|
167
|
-
skipped: [],
|
|
168
|
-
skipReason: "disabled",
|
|
169
|
-
ollamaUrl: config.url,
|
|
170
|
-
model: config.model,
|
|
171
|
-
};
|
|
172
|
-
if (options.json) {
|
|
173
|
-
console.log(JSON.stringify(result, null, 2));
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
console.log(chalk.yellow("Vision check disabled in config"));
|
|
177
|
-
}
|
|
178
|
-
process.exit(2);
|
|
179
|
-
}
|
|
180
|
-
// 3. Parse viewports
|
|
181
|
-
let viewports = null;
|
|
182
|
-
if (options.viewport) {
|
|
183
|
-
viewports = parseViewports(options.viewport);
|
|
184
|
-
}
|
|
185
|
-
// 4. Gather screenshots
|
|
186
|
-
let screenshots = [];
|
|
187
|
-
if (options.viewport && options.url) {
|
|
188
|
-
// Multi-viewport capture mode
|
|
189
|
-
if (!options.json) {
|
|
190
|
-
console.log(chalk.blue(`\n📷 Capturing at ${viewports.length} viewport(s) from ${options.url}...\n`));
|
|
191
|
-
}
|
|
192
|
-
screenshots = await captureFromUrl(options.url, viewports, join(projectRoot, ".openspec-pw/vision-current"));
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
// File-based mode
|
|
196
|
-
screenshots = await resolveScreenshots(options.screenshots);
|
|
197
|
-
}
|
|
198
|
-
if (screenshots.length === 0) {
|
|
199
|
-
console.log(chalk.yellow("No screenshots found matching the provided pattern"));
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
// 5. Baseline mode: save and exit
|
|
203
|
-
if (options.baseline) {
|
|
204
|
-
const baselineDir = saveBaseline(screenshots, projectRoot);
|
|
205
|
-
if (!options.json) {
|
|
206
|
-
console.log(chalk.green(`\n✓ Baseline saved (${screenshots.length} screenshots) in ${baselineDir}`));
|
|
207
|
-
}
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
// 6. Dry run
|
|
211
|
-
if (options.dryRun) {
|
|
212
|
-
console.log(chalk.blue("\n📷 Screenshots (dry run):\n"));
|
|
213
|
-
for (const s of screenshots) {
|
|
214
|
-
const vp = s.viewport ? ` [${s.viewport}]` : "";
|
|
215
|
-
console.log(` ${s.route}${vp} → ${s.path}`);
|
|
216
|
-
}
|
|
217
|
-
console.log(chalk.gray(`\nTotal: ${screenshots.length} files`));
|
|
218
|
-
console.log(chalk.gray(`Ollama: ${config.url} (${config.model})`));
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
// 7. Health check
|
|
222
|
-
const health = await checkOllamaHealth(config);
|
|
223
|
-
if (!health.ok) {
|
|
224
|
-
const result = {
|
|
225
|
-
processed: 0,
|
|
226
|
-
anomalies: [],
|
|
227
|
-
skipped: [],
|
|
228
|
-
skipReason: health.message,
|
|
229
|
-
ollamaUrl: config.url,
|
|
230
|
-
model: config.model,
|
|
231
|
-
};
|
|
232
|
-
if (options.json) {
|
|
233
|
-
console.log(JSON.stringify(result, null, 2));
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
console.log(chalk.yellow(`Vision check skipped: ${health.message}`));
|
|
237
|
-
}
|
|
238
|
-
process.exit(1);
|
|
239
|
-
}
|
|
240
|
-
if (!options.json) {
|
|
241
|
-
const mode = options.diff ? "diff" : "analyze";
|
|
242
|
-
console.log(chalk.blue(`\n🔍 ${mode === "diff" ? "Pixel diff" : "Analyzing"} ${screenshots.length} screenshot(s)...\n`));
|
|
243
|
-
}
|
|
244
|
-
// 8. Diff mode: compare with baseline
|
|
245
|
-
const result = {
|
|
246
|
-
processed: 0,
|
|
247
|
-
anomalies: [],
|
|
248
|
-
skipped: [],
|
|
249
|
-
ollamaUrl: config.url,
|
|
250
|
-
model: config.model,
|
|
251
|
-
baselineDir: join(projectRoot, BASELINE_DIR),
|
|
252
|
-
};
|
|
253
|
-
if (options.diff) {
|
|
254
|
-
const baselineDir = join(projectRoot, BASELINE_DIR);
|
|
255
|
-
const diffDir = join(projectRoot, DIFF_DIR);
|
|
256
|
-
mkdirSync(diffDir, { recursive: true });
|
|
257
|
-
for (const s of screenshots) {
|
|
258
|
-
const baseName = basename(s.path, ".png");
|
|
259
|
-
const baselineSuffix = s.viewport ? `-${s.viewport}-baseline` : "-baseline";
|
|
260
|
-
const baselinePath = join(baselineDir, `${baseName}${baselineSuffix}.png`);
|
|
261
|
-
const diffPath = join(diffDir, `${baseName}-diff.png`);
|
|
262
|
-
if (!existsSync(baselinePath)) {
|
|
263
|
-
result.skipped.push(s.path);
|
|
264
|
-
if (!options.json) {
|
|
265
|
-
console.log(chalk.yellow(` ⚠ No baseline for ${s.route}, skipping diff`));
|
|
266
|
-
}
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
const { changed, anomalies } = await compareScreenshotDiff(config, baselinePath, s.path, diffPath, s.route, options.threshold ?? 0.1);
|
|
271
|
-
result.processed++;
|
|
272
|
-
result.anomalies.push(...anomalies.map((a) => ({ ...a, viewport: s.viewport })));
|
|
273
|
-
if (!options.json) {
|
|
274
|
-
if (changed) {
|
|
275
|
-
console.log(chalk.yellow(` ~ ${s.route}${s.viewport ? ` [${s.viewport}]` : ""}: ${anomalies.length} anomaly(ies)`));
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
console.log(chalk.gray(` ✓ ${s.route}${s.viewport ? ` [${s.viewport}]` : ""}: no changes`));
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
catch (err) {
|
|
283
|
-
const error = err;
|
|
284
|
-
result.skipped.push(s.path);
|
|
285
|
-
if (!options.json) {
|
|
286
|
-
console.error(chalk.red(` ✗ ${s.route}: ${error.message}`));
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
// Analyze mode: batch analyze screenshots
|
|
293
|
-
const concurrency = options.parallel || 4;
|
|
294
|
-
const batchResult = await batchAnalyzeScreenshots(config, screenshots.map((s) => ({ path: s.path, route: s.route })), concurrency, options.noCache);
|
|
295
|
-
result.processed = batchResult.processed;
|
|
296
|
-
result.anomalies = batchResult.anomalies.map((a) => ({
|
|
297
|
-
...a,
|
|
298
|
-
viewport: screenshots.find((s) => s.path === a.screenshot)?.viewport,
|
|
299
|
-
}));
|
|
300
|
-
result.skipped = batchResult.skipped;
|
|
301
|
-
}
|
|
302
|
-
// 9. Filter by severity
|
|
303
|
-
if (options.severity) {
|
|
304
|
-
result.anomalies = filterBySeverity(result.anomalies, options.severity);
|
|
305
|
-
}
|
|
306
|
-
// 10. Output
|
|
307
|
-
if (options.json) {
|
|
308
|
-
console.log(JSON.stringify(result, null, 2));
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
console.log(chalk.blue("─── Results ───\n"));
|
|
312
|
-
console.log(` Processed: ${result.processed}/${screenshots.length}`);
|
|
313
|
-
console.log(` Anomalies: ${result.anomalies.length}`);
|
|
314
|
-
if (result.skipped.length > 0) {
|
|
315
|
-
console.log(chalk.yellow(` Skipped: ${result.skipped.length}`));
|
|
316
|
-
}
|
|
317
|
-
if (result.anomalies.length > 0) {
|
|
318
|
-
console.log(chalk.blue("\n─── Anomalies ───\n"));
|
|
319
|
-
for (const a of result.anomalies) {
|
|
320
|
-
const severityColor = a.severity === "blocking"
|
|
321
|
-
? chalk.red
|
|
322
|
-
: a.severity === "warning"
|
|
323
|
-
? chalk.yellow
|
|
324
|
-
: chalk.gray;
|
|
325
|
-
const vp = a.viewport ? ` [${a.viewport}]` : "";
|
|
326
|
-
console.log(` ${severityColor(`[${a.severity}]`)} ${a.route}${vp}`);
|
|
327
|
-
console.log(` Element: ${a.element}`);
|
|
328
|
-
console.log(` Type: ${a.type} (${a.position})`);
|
|
329
|
-
console.log(` ${a.description}\n`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
console.log(chalk.green("\n ✓ No layout anomalies detected\n"));
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
// 11. HTML report
|
|
337
|
-
if (options.report) {
|
|
338
|
-
generateHtmlReport(result, screenshots.map((s) => ({ path: s.path, route: s.route })), options.report, options.diff ? join(projectRoot, DIFF_DIR) : undefined);
|
|
339
|
-
if (!options.json) {
|
|
340
|
-
console.log(chalk.green(` ✓ HTML report: ${options.report}`));
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
// 12. JSON output file
|
|
344
|
-
if (options.output) {
|
|
345
|
-
writeFileSync(options.output, JSON.stringify(result, null, 2), "utf-8");
|
|
346
|
-
if (!options.json) {
|
|
347
|
-
console.log(chalk.green(` ✓ Results written to ${options.output}`));
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
//# sourceMappingURL=visionCheck.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visionCheck.js","sourceRoot":"","sources":["../../src/commands/visionCheck.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/ollama.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ollama API utilities for vision model integration.
|
|
3
|
-
*
|
|
4
|
-
* Configuration: reads from `.env` in `tests/playwright/` (highest priority),
|
|
5
|
-
* then falls back to environment variables. If no URL or model is found,
|
|
6
|
-
* vision check is disabled.
|
|
7
|
-
*/
|
|
8
|
-
export interface OllamaConfig {
|
|
9
|
-
url: string;
|
|
10
|
-
model: string;
|
|
11
|
-
enabled: boolean;
|
|
12
|
-
}
|
|
13
|
-
export interface VisionAnomaly {
|
|
14
|
-
route: string;
|
|
15
|
-
screenshot: string;
|
|
16
|
-
element: string;
|
|
17
|
-
type: "obscured" | "crowded" | "overflowed" | "missing" | "incorrect";
|
|
18
|
-
position: string;
|
|
19
|
-
severity: "blocking" | "warning" | "minor";
|
|
20
|
-
description: string;
|
|
21
|
-
viewport?: string;
|
|
22
|
-
changed?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export interface VisionCheckResult {
|
|
25
|
-
processed: number;
|
|
26
|
-
anomalies: VisionAnomaly[];
|
|
27
|
-
skipped: string[];
|
|
28
|
-
skipReason?: string;
|
|
29
|
-
ollamaUrl: string;
|
|
30
|
-
model: string;
|
|
31
|
-
baselineDir?: string;
|
|
32
|
-
currentDir?: string;
|
|
33
|
-
}
|
|
34
|
-
export interface OllamaGenerateResponse {
|
|
35
|
-
response: string;
|
|
36
|
-
done: boolean;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Load Ollama config from `.env` in `tests/playwright/` and environment variables.
|
|
40
|
-
* If no URL or model is configured, vision check is disabled.
|
|
41
|
-
*/
|
|
42
|
-
export declare function loadOllamaConfig(projectRoot?: string): OllamaConfig;
|
|
43
|
-
/**
|
|
44
|
-
* Check if Ollama is running and the vision model is available.
|
|
45
|
-
* Returns { ok, message } for doctor output.
|
|
46
|
-
*/
|
|
47
|
-
export declare function checkOllamaHealth(config: OllamaConfig): Promise<{
|
|
48
|
-
ok: boolean;
|
|
49
|
-
message: string;
|
|
50
|
-
}>;
|
|
51
|
-
/**
|
|
52
|
-
* Analyze a single screenshot with the vision model.
|
|
53
|
-
*/
|
|
54
|
-
export declare function analyzeScreenshot(config: OllamaConfig, screenshotPath: string, route: string, prompt?: string, noCache?: boolean): Promise<VisionAnomaly[]>;
|
|
55
|
-
/**
|
|
56
|
-
* Batch analyze multiple screenshots with concurrency control.
|
|
57
|
-
*/
|
|
58
|
-
export declare function batchAnalyzeScreenshots(config: OllamaConfig, screenshots: Array<{
|
|
59
|
-
path: string;
|
|
60
|
-
route: string;
|
|
61
|
-
}>, concurrency?: number, noCache?: boolean): Promise<VisionCheckResult>;
|
|
62
|
-
/**
|
|
63
|
-
* Compare two screenshots with pixel diff.
|
|
64
|
-
* Returns changed regions and optionally saves a diff image.
|
|
65
|
-
*/
|
|
66
|
-
export declare function compareScreenshotDiff(config: OllamaConfig, baselinePath: string, currentPath: string, diffPath: string, route: string, threshold?: number): Promise<{
|
|
67
|
-
changed: boolean;
|
|
68
|
-
anomalies: VisionAnomaly[];
|
|
69
|
-
}>;
|
|
70
|
-
export declare function generateHtmlReport(result: VisionCheckResult, screenshots: Array<{
|
|
71
|
-
path: string;
|
|
72
|
-
route: string;
|
|
73
|
-
}>, outputPath: string, diffDir?: string): void;
|