@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 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. Write to .testivai/temp/<name>/
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.1.10",
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.11.1"
52
+ "@testivai/witness": "1.12.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/jest": "^30.0.0",