@testivai/witness-selenium 0.1.10 → 0.2.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.
- package/dist/types.d.ts +11 -0
- package/dist/witness.js +66 -1
- package/package.json +2 -2
package/dist/types.d.ts
CHANGED
|
@@ -38,6 +38,17 @@ export interface WitnessOptions {
|
|
|
38
38
|
* known to be expensive or unstable.
|
|
39
39
|
*/
|
|
40
40
|
skipDom?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Skip element-map capture. The map powers region→selector attribution,
|
|
43
|
+
* shift classification, and the computed-style fingerprint; skipping it
|
|
44
|
+
* leaves the pixel and DOM layers intact.
|
|
45
|
+
*/
|
|
46
|
+
skipElementMap?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Cap on elements walked for the map (default 3000). Lower it on very
|
|
49
|
+
* large pages where the single executeScript round trip is costly.
|
|
50
|
+
*/
|
|
51
|
+
maxElements?: number;
|
|
41
52
|
/**
|
|
42
53
|
* CSS selectors for elements to hide (`visibility: hidden`) for the
|
|
43
54
|
* duration of the capture, so dynamic content (timestamps, ads, live
|
package/dist/witness.js
CHANGED
|
@@ -20,9 +20,44 @@
|
|
|
20
20
|
* capture is viewport-only (keep the window sized to what you want
|
|
21
21
|
* compared; baselines are consistent run-to-run either way)
|
|
22
22
|
*/
|
|
23
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
26
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
27
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
28
|
+
}
|
|
29
|
+
Object.defineProperty(o, k2, desc);
|
|
30
|
+
}) : (function(o, m, k, k2) {
|
|
31
|
+
if (k2 === undefined) k2 = k;
|
|
32
|
+
o[k2] = m[k];
|
|
33
|
+
}));
|
|
34
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
35
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
36
|
+
}) : function(o, v) {
|
|
37
|
+
o["default"] = v;
|
|
38
|
+
});
|
|
39
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
40
|
+
var ownKeys = function(o) {
|
|
41
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
42
|
+
var ar = [];
|
|
43
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
44
|
+
return ar;
|
|
45
|
+
};
|
|
46
|
+
return ownKeys(o);
|
|
47
|
+
};
|
|
48
|
+
return function (mod) {
|
|
49
|
+
if (mod && mod.__esModule) return mod;
|
|
50
|
+
var result = {};
|
|
51
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
52
|
+
__setModuleDefault(result, mod);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
23
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
57
|
exports.witness = witness;
|
|
25
58
|
const witness_1 = require("@testivai/witness");
|
|
59
|
+
const fs = __importStar(require("fs"));
|
|
60
|
+
const path = __importStar(require("path"));
|
|
26
61
|
/** id of the style element injected for the duration of a capture */
|
|
27
62
|
const STYLE_ID = '__testivai_capture_css__';
|
|
28
63
|
/**
|
|
@@ -172,7 +207,37 @@ async function witness(driver, name, options = {}) {
|
|
|
172
207
|
// is unavailable for this snapshot; pixel diff still works.
|
|
173
208
|
}
|
|
174
209
|
}
|
|
175
|
-
// 3.
|
|
210
|
+
// 3. Capture the element map (best-effort — same contract as the DOM).
|
|
211
|
+
// This is what powers region→selector attribution, shift
|
|
212
|
+
// classification, and the computed-style fingerprint on the compare
|
|
213
|
+
// side. The injected function is the SAME one the Playwright adapter
|
|
214
|
+
// uses (`@testivai/witness`), so both lanes produce identical maps.
|
|
215
|
+
// Selenium's executeScript needs an explicit `return`.
|
|
216
|
+
let elementMap;
|
|
217
|
+
if (!options.skipElementMap && typeof driver.executeScript === 'function') {
|
|
218
|
+
try {
|
|
219
|
+
const expr = (0, witness_1.buildElementMapExpression)(options.maxElements ?? witness_1.DEFAULT_MAX_ELEMENTS, ignoreSelectors);
|
|
220
|
+
const result = await driver.executeScript(`return ${expr}`);
|
|
221
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
222
|
+
elementMap = result;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Suppressed by design, exactly like DOM capture: without a map the
|
|
227
|
+
// report falls back to pixel + DOM layers instead of failing.
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// 4. Write to .testivai/temp/<name>/
|
|
176
231
|
const store = new witness_1.BaselineStore(process.cwd());
|
|
177
232
|
store.writeTemp(name, screenshot, dom);
|
|
233
|
+
if (elementMap !== undefined) {
|
|
234
|
+
const tempDir = path.join(process.cwd(), '.testivai', 'temp', name);
|
|
235
|
+
try {
|
|
236
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
237
|
+
fs.writeFileSync(path.join(tempDir, 'elements.json'), JSON.stringify(elementMap));
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// A map we cannot persist is not worth failing a capture over.
|
|
241
|
+
}
|
|
242
|
+
}
|
|
178
243
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testivai/witness-selenium",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Selenium WebDriver adapter for TestivAI Witness — local-first visual regression with pixel + DOM comparison",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@testivai/witness": "1.
|
|
52
|
+
"@testivai/witness": "1.12.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/jest": "^30.0.0",
|