@testivai/witness-selenium 0.3.11 → 0.3.12

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
@@ -27,6 +27,12 @@ export interface WitnessDriver {
27
27
  * Safari drivers, which fall back to the viewport screenshot.
28
28
  */
29
29
  sendAndGetDevToolsCommand?<T = unknown>(cmd: string, params?: object): Promise<T>;
30
+ /**
31
+ * selenium-webdriver's `driver.getCapabilities()`. Optional: when present,
32
+ * the browser, its version and the driver are recorded as capture
33
+ * provenance in the capture's metadata.json.
34
+ */
35
+ getCapabilities?(): Promise<unknown>;
30
36
  }
31
37
  /**
32
38
  * Options for a single witness() call. All optional.
package/dist/witness.js CHANGED
@@ -59,6 +59,8 @@ const witness_1 = require("@testivai/witness");
59
59
  const fs = __importStar(require("fs"));
60
60
  const path = __importStar(require("path"));
61
61
  const full_page_1 = require("./capture/full-page");
62
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
63
+ const ADAPTER_VERSION = require('../package.json').version;
62
64
  /** id of the style element injected for the duration of a capture */
63
65
  const STYLE_ID = '__testivai_capture_css__';
64
66
  /**
@@ -154,7 +156,7 @@ async function waitForFonts(driver) {
154
156
  }
155
157
  /**
156
158
  * Full-page screenshot where the driver supports it, viewport otherwise.
157
- * Returns a PNG Buffer.
159
+ * Returns the PNG and the capture method it came from.
158
160
  */
159
161
  async function captureScreenshot(driver) {
160
162
  // Chromium drivers expose raw CDP; captureBeyondViewport gives a true
@@ -168,7 +170,8 @@ async function captureScreenshot(driver) {
168
170
  ? (message) => console.log(`[TestivAI] Full-page capture: ${message}`)
169
171
  : undefined;
170
172
  try {
171
- return await (0, full_page_1.captureFullPageScreenshot)(driver, captureLog);
173
+ const png = await (0, full_page_1.captureFullPageScreenshot)(driver, captureLog);
174
+ return { png, method: witness_1.CAPTURE_METHODS.CDP_FULL_PAGE };
172
175
  }
173
176
  catch {
174
177
  // fall through to the viewport screenshot
@@ -178,7 +181,7 @@ async function captureScreenshot(driver) {
178
181
  if (typeof base64 !== 'string' || base64.length === 0) {
179
182
  throw new Error('testivai.witness: driver.takeScreenshot() returned an empty value');
180
183
  }
181
- return Buffer.from(base64, 'base64');
184
+ return { png: Buffer.from(base64, 'base64'), method: witness_1.CAPTURE_METHODS.WEBDRIVER_VIEWPORT };
182
185
  }
183
186
  /**
184
187
  * Capture a screenshot + DOM and write them as a temp snapshot.
@@ -202,10 +205,35 @@ async function witness(driver, name, options = {}) {
202
205
  if (options.variant) {
203
206
  name = `${name}__${options.variant.replace(/[^a-z0-9_-]+/gi, '_').toLowerCase()}`;
204
207
  }
208
+ const localConfig = (0, witness_1.loadLocalConfig)(process.cwd());
209
+ // Capture provenance: what the page is rendered with, measured before
210
+ // anything is injected, plus the session's capabilities. Best-effort.
211
+ let renderProbe = null;
212
+ let capabilities = null;
213
+ if (typeof driver.executeScript === 'function') {
214
+ try {
215
+ renderProbe = await driver.executeScript(`return ${witness_1.RENDER_PROBE_EXPRESSION}`);
216
+ }
217
+ catch {
218
+ // no probe: no render settings recorded
219
+ }
220
+ }
221
+ if (typeof driver.getCapabilities === 'function') {
222
+ try {
223
+ capabilities = await driver.getCapabilities();
224
+ }
225
+ catch {
226
+ // no capabilities: the probe's user agent is the fallback
227
+ }
228
+ }
229
+ const browserName = (0, witness_1.browserFromCapabilities)(capabilities)?.browser.name ?? (() => {
230
+ const ua = (0, witness_1.parseRenderProbe)(renderProbe)?.userAgent;
231
+ return (ua ? (0, witness_1.browserFromUserAgent)(ua)?.name : undefined) ?? 'unknown';
232
+ })();
233
+ name = (0, witness_1.applyEnvironmentPolicyToName)(name, { browser: { name: browserName }, os: { platform: process.platform } }, localConfig.environmentPolicy);
205
234
  // 0. Prepare the page: stabilization CSS (animations/caret/fonts — the
206
235
  // flake killers) + ignoreSelectors from config.json and this call,
207
236
  // injected as one style tag and removed after the capture.
208
- const localConfig = (0, witness_1.loadLocalConfig)(process.cwd());
209
237
  const stabilize = options.stabilize ?? localConfig.stabilize;
210
238
  const ignoreSelectors = [
211
239
  ...new Set([...(localConfig.ignoreSelectors ?? []), ...(options.ignoreSelectors ?? [])]),
@@ -225,8 +253,9 @@ async function witness(driver, name, options = {}) {
225
253
  }
226
254
  // 1. Capture screenshot (full-page on Chromium, viewport elsewhere)
227
255
  let screenshot;
256
+ let captureMethod;
228
257
  try {
229
- screenshot = await captureScreenshot(driver);
258
+ ({ png: screenshot, method: captureMethod } = await captureScreenshot(driver));
230
259
  }
231
260
  finally {
232
261
  if (injected)
@@ -279,6 +308,20 @@ async function witness(driver, name, options = {}) {
279
308
  // 4. Write to .testivai/temp/<name>/
280
309
  const store = new witness_1.BaselineStore(process.cwd());
281
310
  store.writeTemp(name, screenshot, dom);
311
+ const environment = (0, witness_1.webDriverEnvironment)({
312
+ capabilities,
313
+ probe: renderProbe,
314
+ adapter: { name: '@testivai/witness-selenium', version: ADAPTER_VERSION, captureMethod },
315
+ framework: { name: 'selenium-webdriver', version: (0, witness_1.installedPackageVersion)('selenium-webdriver') },
316
+ });
317
+ if (environment) {
318
+ try {
319
+ store.writeTempMetadata(name, { name, environment });
320
+ }
321
+ catch {
322
+ // without it the compare cannot tell rendering drift from noise for this capture
323
+ }
324
+ }
282
325
  // 5. Shard manifest. A Selenium script has no end-of-run hook to attach to,
283
326
  // so it is refreshed on every capture — which is exactly what lets a
284
327
  // Selenium suite join the same sharded CI flow as Playwright. `complete`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testivai/witness-selenium",
3
- "version": "0.3.11",
3
+ "version": "0.3.12",
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": "2.4.0"
52
+ "@testivai/witness": "2.5.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/jest": "^30.0.0",