doc-detective 4.30.0 → 4.31.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/index.cjs CHANGED
@@ -634107,6 +634107,49 @@ function logLevelEnabled(config, level) {
634107
634107
  return true;
634108
634108
  return false;
634109
634109
  }
634110
+ function viewportMismatchWarning(requested, actual, tolerance = 0) {
634111
+ const parts = [];
634112
+ for (const dim of ["width", "height"]) {
634113
+ const req = Number(requested?.[dim]);
634114
+ if (!(req > 0))
634115
+ continue;
634116
+ const act = Number(actual?.[dim]);
634117
+ if (!Number.isFinite(act)) {
634118
+ parts.push(`${dim} requested ${req}px, rendered unknown`);
634119
+ } else if (Math.abs(act - req) > tolerance) {
634120
+ parts.push(`${dim} requested ${req}px, rendered ${act}px`);
634121
+ }
634122
+ }
634123
+ if (parts.length === 0)
634124
+ return null;
634125
+ return `Requested viewport not fully realized \u2014 the browser or OS enforces a minimum window size: ${parts.join("; ")}. Screenshots and measurements reflect the rendered size, not the requested size.`;
634126
+ }
634127
+ function resolveViewportTarget(requested, current) {
634128
+ const w = Number(requested?.width);
634129
+ const h = Number(requested?.height);
634130
+ return {
634131
+ width: w > 0 ? w : Number(current?.width),
634132
+ height: h > 0 ? h : Number(current?.height)
634133
+ };
634134
+ }
634135
+ async function readViewport(driver) {
634136
+ const v = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
634137
+ return { width: Number(v?.width), height: Number(v?.height) };
634138
+ }
634139
+ async function realizeViewport(driver, requested, config = {}, label) {
634140
+ const current = await readViewport(driver);
634141
+ const target = resolveViewportTarget(requested, current);
634142
+ const windowSize = await driver.getWindowSize();
634143
+ const deltaWidth = Number.isFinite(current.width) && Number.isFinite(target.width) ? target.width - current.width : 0;
634144
+ const deltaHeight = Number.isFinite(current.height) && Number.isFinite(target.height) ? target.height - current.height : 0;
634145
+ await driver.setWindowSize(Math.round(windowSize.width + deltaWidth), Math.round(windowSize.height + deltaHeight));
634146
+ const actual = await readViewport(driver);
634147
+ const warning = viewportMismatchWarning(requested, actual, VIEWPORT_TOLERANCE_PX);
634148
+ if (warning) {
634149
+ await log(config, "warning", label ? `${label}: ${warning}` : warning);
634150
+ }
634151
+ return actual;
634152
+ }
634110
634153
  async function log(config, level, message) {
634111
634154
  if (message === void 0) {
634112
634155
  message = config;
@@ -634441,7 +634484,7 @@ function llevenshteinDistance(s, t) {
634441
634484
  }
634442
634485
  return arr[t.length][s.length];
634443
634486
  }
634444
- var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, ENV_VAR_REGEX, posixBashProbe;
634487
+ var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, VIEWPORT_TOLERANCE_PX, ENV_VAR_REGEX, posixBashProbe;
634445
634488
  var init_utils = __esm({
634446
634489
  "dist/core/utils.js"() {
634447
634490
  "use strict";
@@ -634483,6 +634526,7 @@ var init_utils = __esm({
634483
634526
  maxBodyLength: 50 * 1024 * 1024,
634484
634527
  maxRedirects: 5
634485
634528
  };
634529
+ VIEWPORT_TOLERANCE_PX = 16;
634486
634530
  ENV_VAR_REGEX = /\$[a-zA-Z0-9_]+(?![a-zA-Z0-9_$])/g;
634487
634531
  }
634488
634532
  });
@@ -646563,6 +646607,14 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646563
646607
  return result;
646564
646608
  }
646565
646609
  }
646610
+ try {
646611
+ const savedMeta = await sharp(finalBuffer).metadata();
646612
+ if (savedMeta.width && savedMeta.height) {
646613
+ result.outputs.width = savedMeta.width;
646614
+ result.outputs.height = savedMeta.height;
646615
+ }
646616
+ } catch {
646617
+ }
646566
646618
  const writeFinalPng = (destination) => {
646567
646619
  try {
646568
646620
  import_node_fs20.default.writeFileSync(destination, finalBuffer);
@@ -648764,20 +648816,31 @@ async function startSurfaceStep({ config, step, platform, driver, processRegistr
648764
648816
  }
648765
648817
  const vw = Number(d.viewport?.width);
648766
648818
  const vh = Number(d.viewport?.height);
648819
+ let viewportOutput;
648767
648820
  if (vw > 0 || vh > 0) {
648821
+ const requested = {
648822
+ ...vw > 0 ? { width: vw } : {},
648823
+ ...vh > 0 ? { height: vh } : {}
648824
+ };
648825
+ let rendered;
648768
648826
  try {
648769
- await applyViewport(opened.driver, d.viewport);
648827
+ rendered = await realizeViewport(opened.driver, requested, config, `startSurface "${opened.name}"`);
648770
648828
  } catch (error) {
648771
648829
  return {
648772
648830
  status: "FAIL",
648773
648831
  description: `Opened browser surface "${opened.name}" but couldn't apply the viewport: ${error?.message ?? error}`
648774
648832
  };
648775
648833
  }
648834
+ viewportOutput = { requested, actual: rendered };
648776
648835
  }
648777
648836
  return {
648778
648837
  status: "PASS",
648779
648838
  description: `Opened browser surface "${opened.name}" (${engine}).`,
648780
- outputs: { name: opened.name, engine }
648839
+ outputs: {
648840
+ name: opened.name,
648841
+ engine,
648842
+ ...viewportOutput ? { viewport: viewportOutput } : {}
648843
+ }
648781
648844
  };
648782
648845
  };
648783
648846
  const runProcessDescriptor = async (d) => {
@@ -648892,13 +648955,6 @@ async function startSurfaceStep({ config, step, platform, driver, processRegistr
648892
648955
  outputs: { surfaces: results }
648893
648956
  };
648894
648957
  }
648895
- async function applyViewport(driver, viewport) {
648896
- const viewportSize = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
648897
- const windowSize = await driver.getWindowSize();
648898
- const deltaWidth = (viewport.width || viewportSize.width) - viewportSize.width;
648899
- const deltaHeight = (viewport.height || viewportSize.height) - viewportSize.height;
648900
- await driver.setWindowSize(windowSize.width + deltaWidth, windowSize.height + deltaHeight);
648901
- }
648902
648958
 
648903
648959
  // dist/core/tests/mobileBrowser.js
648904
648960
  var import_node_path24 = __toESM(require("node:path"), 1);
@@ -650108,6 +650164,10 @@ function getDriverCapabilities({ runnerDetails, name, options }) {
650108
650164
  // 10 minutes
650109
650165
  "appium:executable": chromium.driver,
650110
650166
  browserName: "chrome",
650167
+ // Classic WebDriver, no BiDi socket. Enabling `webSocketUrl` for
650168
+ // viewport emulation (driver.setViewport) crashed headed recording
650169
+ // contexts with a stack overflow and can't be gated off recording
650170
+ // (viewport+recording is a supported combo) — see ADR 01072 (rejected).
650111
650171
  "wdio:enforceWebDriverClassic": true,
650112
650172
  // Disable BiDi, use classic mode
650113
650173
  "goog:chromeOptions": {
@@ -650465,14 +650525,18 @@ function driverSkipDiagnostic({ requestedName, platform, platformMatches, attemp
650465
650525
  msg += ` A present-but-broken driver (for example a partially downloaded ${driverHint}) can cause this; reinstall the driver or its browser.`;
650466
650526
  return msg;
650467
650527
  }
650468
- async function setViewportSize(context, driver) {
650469
- if (context.browser?.viewport?.width || context.browser?.viewport?.height) {
650470
- const viewportSize = await driver.execute("return { width: window.innerWidth, height: window.innerHeight }", []);
650471
- const windowSize = await driver.getWindowSize();
650472
- const deltaWidth = (context.browser?.viewport?.width || viewportSize.width) - viewportSize.width;
650473
- const deltaHeight = (context.browser?.viewport?.height || viewportSize.height) - viewportSize.height;
650474
- await driver.setWindowSize(windowSize.width + deltaWidth, windowSize.height + deltaHeight);
650528
+ async function setViewportSize(context, driver, config = {}) {
650529
+ const vw = Number(context.browser?.viewport?.width);
650530
+ const vh = Number(context.browser?.viewport?.height);
650531
+ if (vw > 0 || vh > 0) {
650532
+ const requested = {
650533
+ ...vw > 0 ? { width: vw } : {},
650534
+ ...vh > 0 ? { height: vh } : {}
650535
+ };
650536
+ const label = `viewport for ${context.browser?.name ?? "browser"} on ${context.platform ?? "host"}`;
650537
+ return realizeViewport(driver, requested, config, label);
650475
650538
  }
650539
+ return void 0;
650476
650540
  }
650477
650541
  async function allowUnsafeSteps({ config }) {
650478
650542
  if (config.allowUnsafeSteps === true)
@@ -652191,8 +652255,10 @@ ${JSON.stringify(context, null, 2)}`);
652191
652255
  driver
652192
652256
  });
652193
652257
  }
652194
- if (context.browser?.viewport?.width || context.browser?.viewport?.height) {
652195
- await setViewportSize(context, driver);
652258
+ const viewportW = Number(context.browser?.viewport?.width);
652259
+ const viewportH = Number(context.browser?.viewport?.height);
652260
+ if (viewportW > 0 || viewportH > 0) {
652261
+ await setViewportSize(context, driver, config);
652196
652262
  } else if (context.browser?.window?.width || context.browser?.window?.height) {
652197
652263
  const windowSize = await driver.getWindowSize();
652198
652264
  await driver.setWindowSize(context.browser?.window?.width || windowSize.width, context.browser?.window?.height || windowSize.height);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc-detective",
3
- "version": "4.30.0",
3
+ "version": "4.31.0",
4
4
  "description": "Treat doc content as testable assertions to validate doc accuracy and product UX.",
5
5
  "bin": {
6
6
  "doc-detective": "bin/doc-detective.js",