@bughunters/vision 1.0.5 → 1.0.6
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/check.d.ts.map +1 -1
- package/dist/check.js +15 -3
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +24 -9
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/check.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAOhE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAoHD,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAOhE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAoHD,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqK/E"}
|
package/dist/check.js
CHANGED
|
@@ -161,11 +161,17 @@ async function runVisionCheck(opts) {
|
|
|
161
161
|
}
|
|
162
162
|
const resolvedDir = path.resolve(process.cwd(), snapshotsDir);
|
|
163
163
|
fs.mkdirSync(resolvedDir, { recursive: true });
|
|
164
|
-
// Build unique, collision-free filenames scoped to
|
|
165
|
-
// Format: <safe-test-title>--<safe-step-name>.baseline.png
|
|
164
|
+
// Build unique, collision-free filenames scoped to project + test title + step name.
|
|
165
|
+
// Format: [<safe-project>--]<safe-test-title>--<safe-step-name>.baseline.png
|
|
166
|
+
// Project prefix is required when multiple Playwright projects run the same test
|
|
167
|
+
// (e.g. widget-chromium, widget-firefox) — without it all projects share one file.
|
|
168
|
+
const projectName = testInfo?.project?.name || undefined;
|
|
169
|
+
const safeProject = projectName ? sanitize(projectName) : '';
|
|
166
170
|
const safeTitle = testInfo?.title ? sanitize(testInfo.title) : 'unknown';
|
|
167
171
|
const safeName = sanitize(name);
|
|
168
|
-
const filePrefix =
|
|
172
|
+
const filePrefix = safeProject
|
|
173
|
+
? `${safeProject}--${safeTitle}--${safeName}`
|
|
174
|
+
: `${safeTitle}--${safeName}`;
|
|
169
175
|
// Human-readable label used in the HTML report: "Test title › step name"
|
|
170
176
|
const testName = testInfo?.title ? `${testInfo.title} › ${name}` : name;
|
|
171
177
|
const baselinePath = path.join(resolvedDir, `${filePrefix}.baseline.png`);
|
|
@@ -176,6 +182,7 @@ async function runVisionCheck(opts) {
|
|
|
176
182
|
console.log(`📸 [BugHunters Vision] Baseline created: ${name}`);
|
|
177
183
|
(0, results_1.appendResult)(resolvedDir, {
|
|
178
184
|
testName,
|
|
185
|
+
projectName,
|
|
179
186
|
status: 'BASELINE_CREATED',
|
|
180
187
|
reason: 'First run detected — screenshot saved as the new baseline.',
|
|
181
188
|
method: null,
|
|
@@ -196,6 +203,7 @@ async function runVisionCheck(opts) {
|
|
|
196
203
|
console.log(`✅ [BugHunters Vision] FAST PIXEL MATCH: ${name}`);
|
|
197
204
|
(0, results_1.appendResult)(resolvedDir, {
|
|
198
205
|
testName,
|
|
206
|
+
projectName,
|
|
199
207
|
status: 'PASS',
|
|
200
208
|
reason: 'Identical (Fast Pixel Match) — pixel-perfect match, no AI evaluation needed.',
|
|
201
209
|
method: 'FAST_PIXEL_MATCH',
|
|
@@ -212,6 +220,7 @@ async function runVisionCheck(opts) {
|
|
|
212
220
|
// strict: fail immediately without calling AI
|
|
213
221
|
(0, results_1.appendResult)(resolvedDir, {
|
|
214
222
|
testName,
|
|
223
|
+
projectName,
|
|
215
224
|
status: 'FAIL',
|
|
216
225
|
reason: `Pixel mismatch detected (${diffLabel}). Strict mode — AI evaluation disabled.`,
|
|
217
226
|
method: 'FAST_PIXEL_MATCH',
|
|
@@ -233,6 +242,7 @@ async function runVisionCheck(opts) {
|
|
|
233
242
|
const reason = humanReadableApiError(err instanceof Error ? err.message : String(err));
|
|
234
243
|
(0, results_1.appendResult)(resolvedDir, {
|
|
235
244
|
testName,
|
|
245
|
+
projectName,
|
|
236
246
|
status: 'FAIL',
|
|
237
247
|
reason,
|
|
238
248
|
method: 'AI',
|
|
@@ -248,6 +258,7 @@ async function runVisionCheck(opts) {
|
|
|
248
258
|
console.log(`⚠️ [BugHunters Vision] AI error: ${name} — ${result.reason}`);
|
|
249
259
|
(0, results_1.appendResult)(resolvedDir, {
|
|
250
260
|
testName,
|
|
261
|
+
projectName,
|
|
251
262
|
status: 'ERROR',
|
|
252
263
|
reason: result.reason,
|
|
253
264
|
method: 'AI',
|
|
@@ -260,6 +271,7 @@ async function runVisionCheck(opts) {
|
|
|
260
271
|
}
|
|
261
272
|
(0, results_1.appendResult)(resolvedDir, {
|
|
262
273
|
testName,
|
|
274
|
+
projectName,
|
|
263
275
|
status: result.status,
|
|
264
276
|
reason: result.reason,
|
|
265
277
|
method: 'AI',
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAI1D,MAAM,WAAW,+BAA+B;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAI1D,MAAM,WAAW,+BAA+B;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA4iCD,cAAM,wBAAyB,YAAW,QAAQ;IAChD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,CAAC,EAAE,+BAA+B;IAKrD,aAAa,IAAI,OAAO;IAIxB,OAAO,IAAI,IAAI;IAKf,KAAK,IAAI,IAAI;CAkDd;AAED,eAAe,wBAAwB,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
|
package/dist/reporter.js
CHANGED
|
@@ -37,27 +37,37 @@ exports.BugHuntersVisionReporter = void 0;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const check_1 = require("./check");
|
|
40
|
-
// ─── Group flat step results by Playwright test title
|
|
40
|
+
// ─── Group flat step results by Playwright project + test title ───────────────
|
|
41
|
+
// The grouping key is "projectName||testTitle" so that the same test running
|
|
42
|
+
// on different browser projects (chromium, firefox, android…) produces separate
|
|
43
|
+
// groups — each with its own baseline files and its own row in the report.
|
|
41
44
|
function groupResults(results) {
|
|
42
45
|
const order = [];
|
|
43
46
|
const map = new Map();
|
|
44
47
|
for (const r of results) {
|
|
45
48
|
const sep = r.testName.indexOf(' › ');
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
const testTitle = sep >= 0 ? r.testName.slice(0, sep) : r.testName;
|
|
50
|
+
// Composite key keeps project-variants separate while remaining stable
|
|
51
|
+
const key = r.projectName ? `${r.projectName}||${testTitle}` : testTitle;
|
|
52
|
+
if (!map.has(key)) {
|
|
53
|
+
map.set(key, []);
|
|
54
|
+
order.push(key);
|
|
50
55
|
}
|
|
51
|
-
map.get(
|
|
56
|
+
map.get(key).push(r);
|
|
52
57
|
}
|
|
53
|
-
return order.map(
|
|
54
|
-
const steps = map.get(
|
|
58
|
+
return order.map(key => {
|
|
59
|
+
const steps = map.get(key);
|
|
60
|
+
const firstResult = steps[0];
|
|
61
|
+
const sep = firstResult.testName.indexOf(' › ');
|
|
62
|
+
const testTitle = sep >= 0 ? firstResult.testName.slice(0, sep) : firstResult.testName;
|
|
63
|
+
const projectName = firstResult.projectName;
|
|
55
64
|
const hasFail = steps.some(s => s.status === 'FAIL');
|
|
56
65
|
const hasError = steps.some(s => s.status === 'ERROR');
|
|
57
66
|
const allBase = steps.every(s => s.status === 'BASELINE_CREATED');
|
|
58
67
|
const status = hasFail ? 'FAIL' : hasError ? 'ERROR' : allBase ? 'BASELINE_CREATED' : 'PASS';
|
|
59
68
|
return {
|
|
60
69
|
testTitle,
|
|
70
|
+
projectName,
|
|
61
71
|
status,
|
|
62
72
|
passedSteps: steps.filter(s => s.status === 'PASS').length,
|
|
63
73
|
failedSteps: steps.filter(s => s.status === 'FAIL').length,
|
|
@@ -270,6 +280,7 @@ body {
|
|
|
270
280
|
letter-spacing: .4px; font-family: ui-monospace, monospace; white-space: nowrap;
|
|
271
281
|
}
|
|
272
282
|
.badge.m-method { background: var(--surface-2); color: var(--text-3); border: 1px solid var(--border); }
|
|
283
|
+
.badge.m-proj { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border); font-family: inherit; letter-spacing: 0; }
|
|
273
284
|
.badge.m-ai { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-border); }
|
|
274
285
|
.badge.m-warn { background: var(--pixel-soft); color: var(--pixel); border: 1px solid var(--pixel-border); }
|
|
275
286
|
.badge.m-pixel { background: var(--pixel-soft); color: var(--pixel); border: 1px solid var(--pixel-border); }
|
|
@@ -845,7 +856,10 @@ function getJs() {
|
|
|
845
856
|
var snip = n + ' ' + checkWord
|
|
846
857
|
+ (parts.length > 0 ? ' \u00b7 ' + parts.join(' \u00b7 ') : ' \u00b7 all passed');
|
|
847
858
|
|
|
848
|
-
var stepsHtml
|
|
859
|
+
var stepsHtml = g.steps.map(buildStep).join('');
|
|
860
|
+
var projBadge = g.projectName
|
|
861
|
+
? '<span class="badge m-proj">' + esc(g.projectName) + '</span>'
|
|
862
|
+
: '';
|
|
849
863
|
|
|
850
864
|
return '<div class="test-group ' + s.cls + '" data-gst="' + g.status + '">'
|
|
851
865
|
+ '<div class="group-row" data-g="' + gIdx + '">'
|
|
@@ -855,6 +869,7 @@ function getJs() {
|
|
|
855
869
|
+ '<div class="test-snip">' + esc(snip) + '</div>'
|
|
856
870
|
+ '</div>'
|
|
857
871
|
+ '<div class="badges">'
|
|
872
|
+
+ projBadge
|
|
858
873
|
+ '<span class="badge ' + s.badge + '">' + s.label + '</span>'
|
|
859
874
|
+ '</div>'
|
|
860
875
|
+ '<span class="chev" id="gc' + gIdx + '">\u203a</span>'
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type VisionMode = 'ai' | 'strict' | 'off';
|
|
|
2
2
|
export interface TestResult {
|
|
3
3
|
index: number;
|
|
4
4
|
testName: string;
|
|
5
|
+
projectName?: string;
|
|
5
6
|
status: 'PASS' | 'FAIL' | 'BASELINE_CREATED' | 'ERROR';
|
|
6
7
|
reason: string;
|
|
7
8
|
method: 'AI' | 'FAST_PIXEL_MATCH' | null;
|
|
@@ -11,6 +12,7 @@ export interface TestResult {
|
|
|
11
12
|
}
|
|
12
13
|
export interface TestGroup {
|
|
13
14
|
testTitle: string;
|
|
15
|
+
projectName?: string;
|
|
14
16
|
status: 'PASS' | 'FAIL' | 'BASELINE_CREATED' | 'ERROR';
|
|
15
17
|
passedSteps: number;
|
|
16
18
|
failedSteps: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,GAAG,OAAO,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,GAAG,OAAO,CAAC;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,IAAI;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,GAAG,OAAO,CAAC;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,kBAAkB,GAAG,OAAO,CAAC;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,IAAI;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bughunters/vision",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "InfoSec-friendly AI Visual Testing plugin for Playwright.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"reporter.d.ts",
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
|
-
"homepage": "https://bughunters.
|
|
27
|
+
"homepage": "https://bughunters.dev",
|
|
28
28
|
"repository": {
|
|
29
29
|
"type": "git",
|
|
30
30
|
"url": "git+https://github.com/bughunters/vision.git"
|