@bughunters/vision 1.0.0 → 1.0.2
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 +22 -11
- package/dist/check.d.ts +2 -9
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +15 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/package.json +5 -1
- package/dist/fixture.d.ts +0 -21
- package/dist/fixture.d.ts.map +0 -1
- package/dist/fixture.js +0 -25
package/README.md
CHANGED
|
@@ -42,17 +42,19 @@ BUGHUNTERS_VISION_TOKEN=bhv_your_token_here
|
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
44
|
import { defineConfig, devices } from '@playwright/test';
|
|
45
|
-
import type { VisionFixtureOptions } from '@bughunters/vision';
|
|
46
45
|
|
|
47
|
-
export default defineConfig
|
|
46
|
+
export default defineConfig({
|
|
48
47
|
testDir: './tests',
|
|
49
48
|
reporter: [
|
|
50
49
|
['list'],
|
|
51
50
|
['@bughunters/vision/reporter', { snapshotsDir: './bhv-snapshots', reportDir: './bhv-report' }],
|
|
52
51
|
],
|
|
53
52
|
use: {
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// BugHunters Vision options — can also be set via env variables
|
|
54
|
+
bvMode: 'ai', // 'ai' | 'strict' | 'off'
|
|
55
|
+
bvSnapshotsDir: './bhv-snapshots',
|
|
56
|
+
bvUpdateBaseline: false,
|
|
57
|
+
} as Record<string, unknown>,
|
|
56
58
|
projects: [
|
|
57
59
|
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
58
60
|
],
|
|
@@ -62,19 +64,26 @@ export default defineConfig<VisionFixtureOptions>({
|
|
|
62
64
|
### 4. Write a visual test
|
|
63
65
|
|
|
64
66
|
```typescript
|
|
65
|
-
import { test } from '@
|
|
67
|
+
import { test } from '@playwright/test';
|
|
68
|
+
import { vision } from '@bughunters/vision';
|
|
66
69
|
|
|
67
|
-
test('homepage looks correct', async ({ page
|
|
70
|
+
test('homepage looks correct', async ({ page }) => {
|
|
68
71
|
await page.goto('https://example.com');
|
|
69
72
|
await page.waitForLoadState('networkidle');
|
|
70
|
-
await
|
|
73
|
+
await vision.check(page, 'homepage');
|
|
71
74
|
});
|
|
72
75
|
```
|
|
73
76
|
|
|
74
|
-
You can pass an optional AI hint as the
|
|
77
|
+
You can pass an optional AI hint as the third argument:
|
|
75
78
|
|
|
76
79
|
```typescript
|
|
77
|
-
await
|
|
80
|
+
await vision.check(page, 'dashboard', 'Ignore the live timestamp in the top-right corner.');
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`vision.check()` accepts a `Page` or a `Locator` — useful for scoped element checks:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
await vision.check(page.locator('#sidebar'), 'sidebar');
|
|
78
87
|
```
|
|
79
88
|
|
|
80
89
|
### 5. Run your tests
|
|
@@ -104,16 +113,18 @@ The report includes side-by-side Baseline / Current / Diff views with full-scree
|
|
|
104
113
|
|
|
105
114
|
## Configuration reference
|
|
106
115
|
|
|
107
|
-
|
|
116
|
+
Options can be set in `playwright.config.ts` under `use:` **or** via environment variables. The `use:` block takes precedence; env vars are the fallback.
|
|
108
117
|
|
|
109
118
|
| Option in `use:` | Environment variable | Default | Description |
|
|
110
119
|
|---|---|---|---|
|
|
111
120
|
| `bvMode` | `BHV_MODE` | `'ai'` | Comparison mode: `ai` · `strict` · `off` |
|
|
112
121
|
| `bvSnapshotsDir` | `BHV_SNAPSHOTS_DIR` | `'./bhv-snapshots'` | Where to store PNG snapshots |
|
|
113
|
-
| `bvUpdateBaseline` | `BHV_UPDATE_BASELINE` | `false` |
|
|
122
|
+
| `bvUpdateBaseline` | `BHV_UPDATE_BASELINE` | `false` | Set to `true` to force-overwrite all baselines |
|
|
114
123
|
| `bvApiUrl` | `BUGHUNTERS_VISION_API_URL` | *(production)* | Override API endpoint (e.g. for self-hosted) |
|
|
115
124
|
| `bvToken` | `BUGHUNTERS_VISION_TOKEN` | — | Your API token — always use env var, never commit |
|
|
116
125
|
|
|
126
|
+
> **Note:** Because `vision` is a standalone object (not a Playwright fixture), the `use:` options are not TypeScript-typed. Add `as Record<string, unknown>` to the `use` block to suppress TS errors.
|
|
127
|
+
|
|
117
128
|
### Comparison modes
|
|
118
129
|
|
|
119
130
|
| Mode | Behaviour |
|
package/dist/check.d.ts
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import type { Page,
|
|
2
|
-
import type { VisionMode } from './types';
|
|
1
|
+
import type { Page, Locator } from '@playwright/test';
|
|
3
2
|
export interface RunVisionCheckOptions {
|
|
4
|
-
|
|
3
|
+
target: Page | Locator;
|
|
5
4
|
name: string;
|
|
6
5
|
prompt?: string;
|
|
7
|
-
apiUrl: string;
|
|
8
|
-
mode: VisionMode;
|
|
9
|
-
snapshotsDir: string;
|
|
10
|
-
updateBaseline: boolean;
|
|
11
|
-
token?: string;
|
|
12
|
-
testInfo?: TestInfo;
|
|
13
6
|
}
|
|
14
7
|
export declare function getLastRemainingBalance(): string | null;
|
|
15
8
|
export declare function runVisionCheck(opts: RunVisionCheckOptions): Promise<void>;
|
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,
|
|
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;AA+GD,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmJ/E"}
|
package/dist/check.js
CHANGED
|
@@ -40,6 +40,7 @@ const path = __importStar(require("path"));
|
|
|
40
40
|
const test_1 = require("@playwright/test");
|
|
41
41
|
const pixel_match_1 = require("./pixel-match");
|
|
42
42
|
const results_1 = require("./results");
|
|
43
|
+
const PRODUCTION_API_URL = 'https://bugvision-backend.vercel.app';
|
|
43
44
|
// Module-level balance tracker — updated after each AI call, read by reporter.onEnd()
|
|
44
45
|
let _lastRemainingBalance = null;
|
|
45
46
|
function getLastRemainingBalance() {
|
|
@@ -137,7 +138,19 @@ async function pushToPlaywright(testInfo, status, reason, resolvedDir, baselineF
|
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
async function runVisionCheck(opts) {
|
|
140
|
-
const {
|
|
141
|
+
const { target, name, prompt = 'Check for any visual regressions.' } = opts;
|
|
142
|
+
// Read config from testInfo.project.use (if available) or fall back to env vars
|
|
143
|
+
let testInfo;
|
|
144
|
+
try {
|
|
145
|
+
testInfo = test_1.test.info();
|
|
146
|
+
}
|
|
147
|
+
catch { /* called outside test context */ }
|
|
148
|
+
const projectUse = (testInfo?.project?.use ?? {});
|
|
149
|
+
const apiUrl = projectUse['bvApiUrl'] ?? process.env.BUGHUNTERS_VISION_API_URL ?? process.env.BHV_API_URL ?? PRODUCTION_API_URL;
|
|
150
|
+
const mode = (projectUse['bvMode'] ?? process.env.BHV_MODE ?? 'ai');
|
|
151
|
+
const snapshotsDir = projectUse['bvSnapshotsDir'] ?? process.env.BHV_SNAPSHOTS_DIR ?? './bhv-snapshots';
|
|
152
|
+
const updateBaseline = projectUse['bvUpdateBaseline'] ?? (process.env.BHV_UPDATE_BASELINE === 'true');
|
|
153
|
+
const token = projectUse['bvToken'] ?? process.env.BUGHUNTERS_VISION_TOKEN ?? undefined;
|
|
141
154
|
// Mode: off → skip all visual testing immediately
|
|
142
155
|
if (mode === 'off') {
|
|
143
156
|
console.log(`\n⏭ [BugHunters Vision] "${name}" — skipped (BHV_MODE=off)\n`);
|
|
@@ -146,7 +159,7 @@ async function runVisionCheck(opts) {
|
|
|
146
159
|
const resolvedDir = path.resolve(process.cwd(), snapshotsDir);
|
|
147
160
|
fs.mkdirSync(resolvedDir, { recursive: true });
|
|
148
161
|
const baselineFile = path.join(resolvedDir, `${name}.baseline.png`);
|
|
149
|
-
const currentBuffer = await
|
|
162
|
+
const currentBuffer = await target.screenshot();
|
|
150
163
|
if (!fs.existsSync(baselineFile) || updateBaseline) {
|
|
151
164
|
// First run — save as baseline
|
|
152
165
|
fs.writeFileSync(baselineFile, currentBuffer);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export type { VisionFixtureOptions } from './fixture';
|
|
1
|
+
import type { Page, Locator } from '@playwright/test';
|
|
3
2
|
export type { VisionMode, TestResult, Meta } from './types';
|
|
4
3
|
export { BugHuntersVisionReporter } from './reporter';
|
|
5
4
|
export type { BugHuntersVisionReporterOptions } from './reporter';
|
|
5
|
+
export { getLastRemainingBalance } from './check';
|
|
6
|
+
export declare const vision: {
|
|
7
|
+
check(target: Page | Locator, name: string, prompt?: string): Promise<void>;
|
|
8
|
+
};
|
|
6
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGtD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElD,eAAO,MAAM,MAAM;kBACG,IAAI,GAAG,OAAO,QAAQ,MAAM,WAAW,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlF,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "test", { enumerable: true, get: function () { return fixture_1.test; } });
|
|
6
|
-
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return fixture_1.expect; } });
|
|
3
|
+
exports.vision = exports.getLastRemainingBalance = exports.BugHuntersVisionReporter = void 0;
|
|
4
|
+
const check_1 = require("./check");
|
|
7
5
|
var reporter_1 = require("./reporter");
|
|
8
6
|
Object.defineProperty(exports, "BugHuntersVisionReporter", { enumerable: true, get: function () { return reporter_1.BugHuntersVisionReporter; } });
|
|
7
|
+
var check_2 = require("./check");
|
|
8
|
+
Object.defineProperty(exports, "getLastRemainingBalance", { enumerable: true, get: function () { return check_2.getLastRemainingBalance; } });
|
|
9
|
+
exports.vision = {
|
|
10
|
+
async check(target, name, prompt) {
|
|
11
|
+
return (0, check_1.runVisionCheck)({ target, name, prompt });
|
|
12
|
+
},
|
|
13
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bughunters/vision",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "InfoSec-friendly AI Visual Testing plugin for Playwright.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"require": "./dist/index.js",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js",
|
|
10
12
|
"types": "./dist/index.d.ts"
|
|
11
13
|
},
|
|
12
14
|
"./reporter": {
|
|
13
15
|
"require": "./dist/reporter.js",
|
|
16
|
+
"import": "./dist/reporter.js",
|
|
17
|
+
"default": "./dist/reporter.js",
|
|
14
18
|
"types": "./dist/reporter.d.ts"
|
|
15
19
|
}
|
|
16
20
|
},
|
package/dist/fixture.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { expect } from '@playwright/test';
|
|
2
|
-
import type { VisionMode } from './types';
|
|
3
|
-
export interface VisionFixtureOptions {
|
|
4
|
-
/** BugHunters Vision API URL (default: https://bugvision-backend.vercel.app) */
|
|
5
|
-
bvApiUrl: string;
|
|
6
|
-
/** Comparison mode: ai | strict | off (default: ai) */
|
|
7
|
-
bvMode: VisionMode;
|
|
8
|
-
/** Where to store baseline + current screenshots (default: ./bhv-snapshots) */
|
|
9
|
-
bvSnapshotsDir: string;
|
|
10
|
-
/** Force-overwrite all baselines on this run (default: false) */
|
|
11
|
-
bvUpdateBaseline: boolean;
|
|
12
|
-
/** BugHunters Vision API token (env: BUGHUNTERS_VISION_TOKEN) */
|
|
13
|
-
bvToken: string;
|
|
14
|
-
}
|
|
15
|
-
type VisionFixtures = {
|
|
16
|
-
/** Run a visual snapshot check for the current page state */
|
|
17
|
-
visionCheck: (name: string, prompt?: string) => Promise<void>;
|
|
18
|
-
};
|
|
19
|
-
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & VisionFixtures & VisionFixtureOptions, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
20
|
-
export { expect };
|
|
21
|
-
//# sourceMappingURL=fixture.d.ts.map
|
package/dist/fixture.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C,MAAM,WAAW,oBAAoB;IACnC,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,UAAU,CAAC;IACnB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,cAAc,GAAG;IACpB,6DAA6D;IAC7D,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D,CAAC;AAEF,eAAO,MAAM,IAAI,qRAoBf,CAAC;AAEH,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/fixture.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.expect = exports.test = void 0;
|
|
4
|
-
const test_1 = require("@playwright/test");
|
|
5
|
-
Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return test_1.expect; } });
|
|
6
|
-
const check_1 = require("./check");
|
|
7
|
-
const PRODUCTION_API_URL = 'https://bugvision-backend.vercel.app';
|
|
8
|
-
exports.test = test_1.test.extend({
|
|
9
|
-
bvApiUrl: [process.env.BUGHUNTERS_VISION_API_URL ?? process.env.BHV_API_URL ?? PRODUCTION_API_URL, { option: true }],
|
|
10
|
-
bvMode: [(process.env.BHV_MODE ?? 'ai'), { option: true }],
|
|
11
|
-
bvSnapshotsDir: [process.env.BHV_SNAPSHOTS_DIR ?? './bhv-snapshots', { option: true }],
|
|
12
|
-
bvUpdateBaseline: [process.env.BHV_UPDATE_BASELINE === 'true', { option: true }],
|
|
13
|
-
bvToken: [process.env.BUGHUNTERS_VISION_TOKEN ?? '', { option: true }],
|
|
14
|
-
visionCheck: async ({ page, bvApiUrl, bvMode, bvSnapshotsDir, bvUpdateBaseline, bvToken }, use, testInfo) => {
|
|
15
|
-
await use((name, prompt) => (0, check_1.runVisionCheck)({
|
|
16
|
-
page, name, prompt,
|
|
17
|
-
apiUrl: bvApiUrl,
|
|
18
|
-
mode: bvMode,
|
|
19
|
-
snapshotsDir: bvSnapshotsDir,
|
|
20
|
-
updateBaseline: bvUpdateBaseline,
|
|
21
|
-
token: bvToken || undefined,
|
|
22
|
-
testInfo,
|
|
23
|
-
}));
|
|
24
|
-
},
|
|
25
|
-
});
|