browser-debugger-cli 0.11.0 → 0.13.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/.claude/skills/bdg/SKILL.md +4 -4
- package/README.md +143 -79
- package/dist/commands/cdp.d.ts +22 -1
- package/dist/commands/cdp.js +100 -43
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/console.js +62 -12
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/DomElementResolver.d.ts +3 -1
- package/dist/commands/dom/DomElementResolver.js +10 -3
- package/dist/commands/dom/a11y.js +3 -2
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/eval.d.ts +3 -2
- package/dist/commands/dom/eval.js +11 -5
- package/dist/commands/dom/form.js +10 -9
- package/dist/commands/dom/formInteraction.js +42 -11
- package/dist/commands/dom/get.js +8 -8
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/query.d.ts +27 -3
- package/dist/commands/dom/helpers/query.js +152 -64
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +169 -49
- package/dist/commands/dom/index.js +7 -2
- package/dist/commands/dom/query.d.ts +19 -2
- package/dist/commands/dom/query.js +37 -6
- package/dist/commands/dom/screenshot.js +12 -7
- package/dist/commands/dom/semanticUtils.d.ts +3 -2
- package/dist/commands/dom/semanticUtils.js +40 -9
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.d.ts +82 -19
- package/dist/commands/helpJson.js +112 -41
- package/dist/commands/helpTopic.d.ts +16 -1
- package/dist/commands/helpTopic.js +59 -1
- package/dist/commands/installSkill.d.ts +15 -5
- package/dist/commands/installSkill.js +86 -16
- package/dist/commands/network/list.js +22 -12
- package/dist/commands/optionBehaviors.js +53 -16
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
- package/dist/commands/shared/daemonErrorHandler.js +20 -9
- package/dist/commands/shared/dataFetcher.d.ts +12 -4
- package/dist/commands/shared/dataFetcher.js +12 -4
- package/dist/commands/shared/followMode.d.ts +9 -1
- package/dist/commands/shared/followMode.js +22 -4
- package/dist/commands/shared/optionTypes.d.ts +9 -2
- package/dist/commands/shared/outputFile.js +6 -1
- package/dist/commands/start.d.ts +20 -5
- package/dist/commands/start.js +84 -23
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.js +24 -1
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +2 -0
- package/dist/connection/cdp.d.ts +7 -0
- package/dist/connection/cdp.js +9 -0
- package/dist/connection/launcher.js +3 -2
- package/dist/daemon/SessionController.js +6 -1
- package/dist/daemon/launcher.d.ts +3 -2
- package/dist/daemon/launcher.js +47 -3
- package/dist/daemon/session/Session.d.ts +4 -1
- package/dist/daemon/session/Session.js +33 -2
- package/dist/daemon/session/TelemetryStore.d.ts +8 -1
- package/dist/daemon/session/TelemetryStore.js +13 -1
- package/dist/daemon/session/commandRegistry.js +36 -14
- package/dist/daemon/session/interactions.d.ts +2 -1
- package/dist/daemon/session/interactions.js +13 -1
- package/dist/daemon/session/plugins.js +19 -53
- package/dist/daemon/session/teardown.js +1 -1
- package/dist/daemon.js +9234 -7222
- package/dist/errors/messages.d.ts +88 -15
- package/dist/errors/messages.js +177 -27
- package/dist/index.js +19322 -13961
- package/dist/ipc/client.d.ts +22 -2
- package/dist/ipc/client.js +34 -5
- package/dist/ipc/protocol/auditTypes.d.ts +135 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +35 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +16 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +73 -8
- package/dist/ipc/session/types.d.ts +2 -0
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +9 -2
- package/dist/runtime/dom/actionEffects.js +30 -14
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +37 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +220 -0
- package/dist/runtime/dom/auditScripts.d.ts +113 -0
- package/dist/runtime/dom/auditScripts.js +148 -0
- package/dist/runtime/dom/elementGeometry.d.ts +16 -3
- package/dist/runtime/dom/elementGeometry.js +49 -10
- package/dist/runtime/dom/elementInfo.d.ts +74 -17
- package/dist/runtime/dom/elementInfo.js +187 -34
- package/dist/runtime/dom/evalHelpers.d.ts +12 -2
- package/dist/runtime/dom/evalHelpers.js +67 -7
- package/dist/runtime/dom/formDiscovery.d.ts +6 -2
- package/dist/runtime/dom/formDiscovery.js +20 -3
- package/dist/runtime/dom/formFillHelpers/fill.js +8 -12
- package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
- package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
- package/dist/runtime/dom/formSubmitHelpers.js +4 -3
- package/dist/runtime/dom/frameLayout.js +1 -0
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +92 -28
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +90 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +5 -1
- package/dist/runtime/dom/inspectModel.js +37 -10
- package/dist/runtime/dom/inspectPaintModel.d.ts +50 -22
- package/dist/runtime/dom/inspectPaintModel.js +182 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +112 -12
- package/dist/runtime/dom/inspectScripts.js +357 -32
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +40 -16
- package/dist/runtime/dom/reactEventHelpers.d.ts +21 -4
- package/dist/runtime/dom/reactEventHelpers.js +90 -36
- package/dist/runtime/dom/targetNode.d.ts +18 -5
- package/dist/runtime/dom/targetNode.js +268 -8
- package/dist/runtime/dom/wait.js +2 -1
- package/dist/runtime/page/bdgWorld.d.ts +57 -0
- package/dist/runtime/page/bdgWorld.js +180 -0
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
- package/dist/runtime/page/replacedBuiltins.js +136 -0
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/session/QueryCacheManager.d.ts +4 -1
- package/dist/session/QueryCacheManager.js +5 -2
- package/dist/session/chrome.d.ts +4 -1
- package/dist/session/chrome.js +7 -1
- package/dist/session/cleanup/staleSession.d.ts +21 -4
- package/dist/session/cleanup/staleSession.js +79 -9
- package/dist/session/cleanup/userCommands.d.ts +4 -1
- package/dist/session/cleanup/userCommands.js +10 -5
- package/dist/session/daemonSocket.d.ts +10 -0
- package/dist/session/daemonSocket.js +22 -0
- package/dist/session/lastSession.d.ts +6 -3
- package/dist/session/lastSession.js +11 -5
- package/dist/session/paths.d.ts +3 -1
- package/dist/session/paths.js +5 -5
- package/dist/session/portClaims.js +4 -3
- package/dist/session/sessionList.d.ts +13 -5
- package/dist/session/sessionList.js +31 -7
- package/dist/telemetry/a11y.js +2 -2
- package/dist/telemetry/console.d.ts +2 -1
- package/dist/telemetry/console.js +30 -21
- package/dist/telemetry/pageCrash.d.ts +26 -0
- package/dist/telemetry/pageCrash.js +53 -0
- package/dist/types.d.ts +20 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +115 -0
- package/dist/ui/formatters/cdp.d.ts +138 -0
- package/dist/ui/formatters/cdp.js +131 -0
- package/dist/ui/formatters/console/chronological.js +3 -1
- package/dist/ui/formatters/console/follow.d.ts +2 -1
- package/dist/ui/formatters/console/follow.js +2 -2
- package/dist/ui/formatters/console/json.d.ts +2 -2
- package/dist/ui/formatters/console/json.js +11 -5
- package/dist/ui/formatters/console/shared.d.ts +30 -0
- package/dist/ui/formatters/console/shared.js +16 -0
- package/dist/ui/formatters/console/summarize.d.ts +9 -2
- package/dist/ui/formatters/console/summarize.js +40 -9
- package/dist/ui/formatters/console.d.ts +2 -1
- package/dist/ui/formatters/console.js +7 -5
- package/dist/ui/formatters/details.js +3 -1
- package/dist/ui/formatters/dom.d.ts +2 -2
- package/dist/ui/formatters/dom.js +10 -8
- package/dist/ui/formatters/helpFormatters.js +1 -1
- package/dist/ui/formatters/inspect.js +50 -17
- package/dist/ui/formatters/installSkill.d.ts +9 -1
- package/dist/ui/formatters/installSkill.js +32 -6
- package/dist/ui/formatters/layout.js +2 -1
- package/dist/ui/formatters/networkList.d.ts +1 -1
- package/dist/ui/formatters/networkList.js +1 -2
- package/dist/ui/formatters/preview.d.ts +2 -0
- package/dist/ui/formatters/preview.js +17 -7
- package/dist/ui/formatters/sessions.d.ts +2 -2
- package/dist/ui/formatters/sessions.js +9 -2
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/commands.d.ts +168 -11
- package/dist/ui/messages/commands.js +245 -18
- package/dist/ui/messages/consoleMessages.d.ts +24 -0
- package/dist/ui/messages/consoleMessages.js +32 -0
- package/dist/ui/messages/preview.d.ts +12 -0
- package/dist/ui/messages/preview.js +18 -2
- package/dist/ui/messages/session.d.ts +13 -2
- package/dist/ui/messages/session.js +22 -3
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/directories.d.ts +34 -0
- package/dist/utils/directories.js +88 -0
- package/dist/utils/display.d.ts +16 -0
- package/dist/utils/display.js +42 -0
- package/dist/utils/exitCodes.d.ts +1 -0
- package/dist/utils/exitCodes.js +6 -0
- package/dist/utils/process.d.ts +12 -0
- package/dist/utils/process.js +25 -0
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +3 -2
|
@@ -9,7 +9,7 @@ import { writeOutputFile } from '../../shared/outputFile.js';
|
|
|
9
9
|
import { CDPConnectionError } from '../../../connection/errors.js';
|
|
10
10
|
import { CommandError } from '../../../errors/index.js';
|
|
11
11
|
import { noNodesFoundError, elementNotVisibleError, elementZeroDimensionsError, } from '../../../errors/messages.js';
|
|
12
|
-
import { callCDP } from '../../../ipc/client.js';
|
|
12
|
+
import { callBdgScript, callCDP } from '../../../ipc/client.js';
|
|
13
13
|
import { DEEP_QUERY_JS, selectorArgsJS } from '../../../runtime/dom/targetNode.js';
|
|
14
14
|
import { viewportOverride } from '../../../runtime/page/emulation.js';
|
|
15
15
|
import { readSessionMetadata } from '../../../session/metadata.js';
|
|
@@ -26,7 +26,7 @@ const STABILITY_CHECK_INTERVAL_MS = 50;
|
|
|
26
26
|
*/
|
|
27
27
|
async function waitForPostScrollStability() {
|
|
28
28
|
const deadline = Date.now() + POST_SCROLL_MAX_WAIT_MS;
|
|
29
|
-
await
|
|
29
|
+
await callBdgScript('Runtime.evaluate', {
|
|
30
30
|
expression: `
|
|
31
31
|
(() => {
|
|
32
32
|
window.__bdg_scrollStability = {
|
|
@@ -66,7 +66,7 @@ async function waitForPostScrollStability() {
|
|
|
66
66
|
});
|
|
67
67
|
try {
|
|
68
68
|
while (Date.now() < deadline) {
|
|
69
|
-
const checkResult = await
|
|
69
|
+
const checkResult = await callBdgScript('Runtime.evaluate', {
|
|
70
70
|
expression: `
|
|
71
71
|
(() => {
|
|
72
72
|
const state = window.__bdg_scrollStability;
|
|
@@ -91,7 +91,7 @@ async function waitForPostScrollStability() {
|
|
|
91
91
|
log.debug('Post-scroll stability timeout, proceeding anyway');
|
|
92
92
|
}
|
|
93
93
|
finally {
|
|
94
|
-
await
|
|
94
|
+
await callBdgScript('Runtime.evaluate', {
|
|
95
95
|
expression: `
|
|
96
96
|
(() => {
|
|
97
97
|
const state = window.__bdg_scrollStability;
|
|
@@ -111,7 +111,7 @@ async function waitForPostScrollStability() {
|
|
|
111
111
|
* position so it can be restored afterwards.
|
|
112
112
|
*/
|
|
113
113
|
async function scrollToElement(selector) {
|
|
114
|
-
const result = await
|
|
114
|
+
const result = await callBdgScript('Runtime.evaluate', {
|
|
115
115
|
expression: `
|
|
116
116
|
(() => {
|
|
117
117
|
const el = (${DEEP_QUERY_JS})(${selectorArgsJS(selector)})[0];
|
|
@@ -133,7 +133,7 @@ async function scrollToElement(selector) {
|
|
|
133
133
|
return { x: value.originalX ?? 0, y: value.originalY ?? 0 };
|
|
134
134
|
}
|
|
135
135
|
async function restoreScrollPosition(position) {
|
|
136
|
-
await
|
|
136
|
+
await callBdgScript('Runtime.evaluate', {
|
|
137
137
|
expression: `window.scrollTo(${position.x}, ${position.y})`,
|
|
138
138
|
returnByValue: true,
|
|
139
139
|
});
|
|
@@ -147,7 +147,7 @@ async function restoreScrollPosition(position) {
|
|
|
147
147
|
* @returns Width and height in CSS px
|
|
148
148
|
*/
|
|
149
149
|
async function windowSize(viewport) {
|
|
150
|
-
const response = await
|
|
150
|
+
const response = await callBdgScript('Runtime.evaluate', {
|
|
151
151
|
expression: '[window.innerWidth, window.innerHeight]',
|
|
152
152
|
returnByValue: true,
|
|
153
153
|
});
|
|
@@ -175,14 +175,22 @@ async function useUnitPixelRatio(devicePixelRatio, viewport) {
|
|
|
175
175
|
const sessionViewport = readSessionMetadata()?.viewport;
|
|
176
176
|
const size = sessionViewport ?? (await windowSize(viewport));
|
|
177
177
|
await callCDP('Emulation.setDeviceMetricsOverride', viewportOverride(size, 1));
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
return restoreSessionMetrics;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Put back the session's device metrics: its `--viewport` (and a phone's
|
|
182
|
+
* touch input, which a capture beyond the viewport turns off), else none.
|
|
183
|
+
*/
|
|
184
|
+
async function restoreSessionMetrics() {
|
|
185
|
+
const sessionViewport = readSessionMetadata()?.viewport;
|
|
186
|
+
if (!sessionViewport) {
|
|
187
|
+
await callCDP('Emulation.clearDeviceMetricsOverride', {});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await callCDP('Emulation.setDeviceMetricsOverride', viewportOverride(sessionViewport));
|
|
191
|
+
if (sessionViewport.mobile) {
|
|
192
|
+
await callCDP('Emulation.setTouchEmulationEnabled', { enabled: true, maxTouchPoints: 5 });
|
|
193
|
+
}
|
|
186
194
|
}
|
|
187
195
|
/**
|
|
188
196
|
* Get the bounding box (border box, so padding and border are included) of an
|
|
@@ -237,7 +245,7 @@ export async function capturePageScreenshot(outputPath, options = {}) {
|
|
|
237
245
|
if (options.scroll) {
|
|
238
246
|
originalScrollPosition = await scrollToElement(options.scroll);
|
|
239
247
|
}
|
|
240
|
-
const dprResponse = await
|
|
248
|
+
const dprResponse = await callBdgScript('Runtime.evaluate', {
|
|
241
249
|
expression: 'window.devicePixelRatio',
|
|
242
250
|
returnByValue: true,
|
|
243
251
|
});
|
|
@@ -258,7 +266,7 @@ export async function capturePageScreenshot(outputPath, options = {}) {
|
|
|
258
266
|
const restoreMetrics = await useUnitPixelRatio(devicePixelRatio, viewport);
|
|
259
267
|
if (devicePixelRatio !== 1) {
|
|
260
268
|
if (options.scroll) {
|
|
261
|
-
await
|
|
269
|
+
await callBdgScript('Runtime.evaluate', {
|
|
262
270
|
expression: `(${DEEP_QUERY_JS})(${selectorArgsJS(options.scroll)})[0]?.scrollIntoView({ block: 'center', behavior: 'instant' })`,
|
|
263
271
|
returnByValue: true,
|
|
264
272
|
});
|
|
@@ -334,13 +342,17 @@ export async function capturePageScreenshot(outputPath, options = {}) {
|
|
|
334
342
|
/** Descendants {@link CONTENT_OVERFLOW_JS} looks at, so a huge element stays cheap */
|
|
335
343
|
const OVERFLOW_SCAN_LIMIT = 2000;
|
|
336
344
|
/**
|
|
337
|
-
* Page-side distances (CSS px, never negative) by which an element
|
|
338
|
-
*
|
|
339
|
-
* absolutely positioned and transformed
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
* element clips its
|
|
345
|
+
* Page-side distances (CSS px, never negative) by which what an element
|
|
346
|
+
* paints reaches beyond its border box on each side: its rendered
|
|
347
|
+
* descendants (uncleared floats, absolutely positioned and transformed
|
|
348
|
+
* children), its text (descenders past a tight line height, read from its
|
|
349
|
+
* scroll size beyond its client size, in transformed px, to the left on an
|
|
350
|
+
* RTL element), and its own outer box shadows and outline (a focus ring).
|
|
351
|
+
* Descendants of an element that clips its overflow (`overflow` other than
|
|
352
|
+
* `visible`) are cut off by it and not counted, nor are fixed ones (they
|
|
353
|
+
* belong to the viewport) or what lies outside the document (skip links at
|
|
354
|
+
* -9999px). Only the shadows and outline count when the element clips its
|
|
355
|
+
* own overflow.
|
|
344
356
|
*/
|
|
345
357
|
const CONTENT_OVERFLOW_JS = `function () {
|
|
346
358
|
const view = this.ownerDocument.defaultView;
|
|
@@ -365,8 +377,37 @@ const CONTENT_OVERFLOW_JS = `function () {
|
|
|
365
377
|
if (!clips(style)) walk(child);
|
|
366
378
|
}
|
|
367
379
|
};
|
|
368
|
-
|
|
369
|
-
|
|
380
|
+
const ownStyle = view.getComputedStyle(this);
|
|
381
|
+
if (!clips(ownStyle)) {
|
|
382
|
+
walk(this);
|
|
383
|
+
const scaleX = this.offsetWidth ? own.width / this.offsetWidth : 1;
|
|
384
|
+
const scaleY = this.offsetHeight ? own.height / this.offsetHeight : 1;
|
|
385
|
+
const wider = Math.max(0, this.scrollWidth - this.clientWidth) * scaleX;
|
|
386
|
+
const taller = Math.max(0, this.scrollHeight - this.clientHeight) * scaleY;
|
|
387
|
+
if (ownStyle.direction === 'rtl') reach.left = Math.min(reach.left, own.left - wider);
|
|
388
|
+
else reach.right = Math.max(reach.right, own.right + wider);
|
|
389
|
+
reach.bottom = Math.max(reach.bottom, own.bottom + taller);
|
|
390
|
+
}
|
|
391
|
+
const ink = { left: 0, top: 0, right: 0, bottom: 0 };
|
|
392
|
+
const grow = (side, amount) => { ink[side] = Math.max(ink[side], amount); };
|
|
393
|
+
for (const layer of ownStyle.boxShadow === 'none' ? [] : ownStyle.boxShadow.split(/,(?![^(]*\\))/)) {
|
|
394
|
+
if (/\\binset\\b/.test(layer)) continue;
|
|
395
|
+
const [x = 0, y = 0, blur = 0, spread = 0] = (layer.replace(/(rgba?|hsla?|color|oklch|lab|lch)\\([^)]*\\)/g, '').match(/-?[\\d.]+px/g) || []).map(parseFloat);
|
|
396
|
+
grow('left', blur + spread - x);
|
|
397
|
+
grow('right', blur + spread + x);
|
|
398
|
+
grow('top', blur + spread - y);
|
|
399
|
+
grow('bottom', blur + spread + y);
|
|
400
|
+
}
|
|
401
|
+
if (ownStyle.outlineStyle !== 'none') {
|
|
402
|
+
const outline = parseFloat(ownStyle.outlineWidth) + parseFloat(ownStyle.outlineOffset);
|
|
403
|
+
['left', 'top', 'right', 'bottom'].forEach((side) => grow(side, outline));
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
left: Math.max(own.left - reach.left, ink.left),
|
|
407
|
+
top: Math.max(own.top - reach.top, ink.top),
|
|
408
|
+
right: Math.max(reach.right - own.right, ink.right),
|
|
409
|
+
bottom: Math.max(reach.bottom - own.bottom, ink.bottom)
|
|
410
|
+
};
|
|
370
411
|
}`;
|
|
371
412
|
/**
|
|
372
413
|
* The visible viewport (without scrollbars) in CSS px.
|
|
@@ -393,27 +434,80 @@ function insideView(area, view) {
|
|
|
393
434
|
}
|
|
394
435
|
/**
|
|
395
436
|
* Measure the area to capture and, when it fits in the viewport but is not
|
|
396
|
-
* in view, scroll it to the middle first
|
|
397
|
-
* keeps the page as it is; one
|
|
398
|
-
* without its scrollbar,
|
|
399
|
-
*
|
|
437
|
+
* in view, scroll it to the middle first (the returned position puts the
|
|
438
|
+
* page back). A capture inside the viewport keeps the page as it is; one
|
|
439
|
+
* beyond it makes Chrome lay the page out without its scrollbar, so for an
|
|
440
|
+
* area larger than the viewport the scrollbars are hidden first and the
|
|
441
|
+
* area measured in that layout (centered content would else move by half
|
|
442
|
+
* the scrollbar's width).
|
|
400
443
|
*
|
|
401
444
|
* @param ref - Node reference
|
|
402
|
-
* @
|
|
445
|
+
* @param padding - Extra space around the area (CSS px)
|
|
446
|
+
* @returns Border box, area to capture (viewport coordinates), whether it is
|
|
447
|
+
* in view, and the scroll position to restore when it scrolled
|
|
403
448
|
*/
|
|
404
|
-
async function measureInView(ref) {
|
|
449
|
+
async function measureInView(ref, padding) {
|
|
405
450
|
const view = await visibleViewport();
|
|
406
451
|
let box = await getElementBounds(ref);
|
|
407
|
-
let bounds = await captureArea(ref, box);
|
|
452
|
+
let bounds = await captureArea(ref, box, padding);
|
|
408
453
|
const fits = bounds.width <= view.width && bounds.height <= view.height;
|
|
409
|
-
if (fits
|
|
410
|
-
|
|
411
|
-
const dy = bounds.y + bounds.height / 2 - view.height / 2;
|
|
412
|
-
await callCDP('Runtime.evaluate', { expression: `window.scrollBy(${dx}, ${dy})` });
|
|
454
|
+
if (!fits) {
|
|
455
|
+
await keepLayoutWithoutScrollbars(view);
|
|
413
456
|
box = await getElementBounds(ref);
|
|
414
|
-
bounds
|
|
457
|
+
return { box, bounds: await captureArea(ref, box, padding), inView: false };
|
|
415
458
|
}
|
|
416
|
-
|
|
459
|
+
if (insideView(bounds, view))
|
|
460
|
+
return { box, bounds, inView: true };
|
|
461
|
+
const scrolledFrom = await scrollPosition();
|
|
462
|
+
const dx = bounds.x + bounds.width / 2 - view.width / 2;
|
|
463
|
+
const dy = bounds.y + bounds.height / 2 - view.height / 2;
|
|
464
|
+
await callBdgScript('Runtime.evaluate', { expression: `window.scrollBy(${dx}, ${dy})` });
|
|
465
|
+
try {
|
|
466
|
+
box = await getElementBounds(ref);
|
|
467
|
+
bounds = await captureArea(ref, box, padding);
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
await restoreScrollPosition(scrolledFrom);
|
|
471
|
+
throw error;
|
|
472
|
+
}
|
|
473
|
+
return { box, bounds, inView: insideView(bounds, view), scrolledFrom };
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Lay the page out at its current width without scrollbars: a capture
|
|
477
|
+
* beyond the viewport hides them, and without this the page would widen by
|
|
478
|
+
* the scrollbar and centered content move after it was measured. The
|
|
479
|
+
* viewport is overridden at the visible width (CSS px, pixel ratio 1; still
|
|
480
|
+
* a phone in a `--mobile` session) until
|
|
481
|
+
* {@link restoreViewport}.
|
|
482
|
+
*
|
|
483
|
+
* @param view - Visible viewport size
|
|
484
|
+
*/
|
|
485
|
+
async function keepLayoutWithoutScrollbars(view) {
|
|
486
|
+
const phone = readSessionMetadata()?.viewport?.mobile;
|
|
487
|
+
await callCDP('Emulation.setScrollbarsHidden', { hidden: true });
|
|
488
|
+
await callCDP('Emulation.setDeviceMetricsOverride', viewportOverride({ ...view, ...(phone && { mobile: true }) }, 1));
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Put back the viewport a capture changed: the session's `--viewport`, else
|
|
492
|
+
* none, with scrollbars shown.
|
|
493
|
+
*/
|
|
494
|
+
async function restoreViewport() {
|
|
495
|
+
await callCDP('Emulation.setScrollbarsHidden', { hidden: false });
|
|
496
|
+
await restoreSessionMetrics();
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* The page's scroll position.
|
|
500
|
+
*
|
|
501
|
+
* @returns Scroll offsets in CSS px
|
|
502
|
+
*/
|
|
503
|
+
async function scrollPosition() {
|
|
504
|
+
const response = await callBdgScript('Runtime.evaluate', {
|
|
505
|
+
expression: '[window.scrollX, window.scrollY]',
|
|
506
|
+
returnByValue: true,
|
|
507
|
+
});
|
|
508
|
+
const value = response.data?.result?.result?.value;
|
|
509
|
+
const [x, y] = Array.isArray(value) ? value : [];
|
|
510
|
+
return { x: x ?? 0, y: y ?? 0 };
|
|
417
511
|
}
|
|
418
512
|
/** Overflow (px) below which the capture keeps to the border box (subpixel rounding) */
|
|
419
513
|
const OVERFLOW_SLACK = 1;
|
|
@@ -424,12 +518,33 @@ const OVERFLOW_SLACK = 1;
|
|
|
424
518
|
*
|
|
425
519
|
* @param ref - Node reference
|
|
426
520
|
* @param bounds - Border box (DOM.getBoxModel coordinates)
|
|
427
|
-
* @
|
|
521
|
+
* @param padding - Extra space around it (CSS px)
|
|
522
|
+
* @returns The area, or the border box (with the padding) when nothing
|
|
523
|
+
* overflows (or the page cannot be asked)
|
|
428
524
|
*/
|
|
429
|
-
async function captureArea(ref, bounds) {
|
|
525
|
+
async function captureArea(ref, bounds, padding) {
|
|
526
|
+
const area = await paintedArea(ref, bounds);
|
|
527
|
+
return padding > 0
|
|
528
|
+
? {
|
|
529
|
+
x: area.x - padding,
|
|
530
|
+
y: area.y - padding,
|
|
531
|
+
width: area.width + 2 * padding,
|
|
532
|
+
height: area.height + 2 * padding,
|
|
533
|
+
}
|
|
534
|
+
: area;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* The border box grown to what the element paints beyond it
|
|
538
|
+
* ({@link CONTENT_OVERFLOW_JS}).
|
|
539
|
+
*
|
|
540
|
+
* @param ref - Node reference
|
|
541
|
+
* @param bounds - Border box
|
|
542
|
+
* @returns The area
|
|
543
|
+
*/
|
|
544
|
+
async function paintedArea(ref, bounds) {
|
|
430
545
|
const objectGroup = `bdg-shot-${process.pid}`;
|
|
431
546
|
try {
|
|
432
|
-
const resolved = await
|
|
547
|
+
const resolved = await callBdgScript('DOM.resolveNode', { ...ref, objectGroup });
|
|
433
548
|
const objectId = resolved.data?.result?.object
|
|
434
549
|
.objectId;
|
|
435
550
|
if (!objectId)
|
|
@@ -471,23 +586,27 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
|
|
|
471
586
|
const format = options.format ?? 'png';
|
|
472
587
|
const quality = format === 'jpeg' ? (options.quality ?? 90) : undefined;
|
|
473
588
|
const noResize = options.noResize ?? false;
|
|
474
|
-
const dprResponse = await
|
|
589
|
+
const dprResponse = await callBdgScript('Runtime.evaluate', {
|
|
475
590
|
expression: 'window.devicePixelRatio',
|
|
476
591
|
returnByValue: true,
|
|
477
592
|
});
|
|
478
593
|
const devicePixelRatio = dprResponse.data?.result?.result?.value ?? 1;
|
|
479
594
|
const before = (await callCDP('Page.getLayoutMetrics', {})).data?.result;
|
|
480
595
|
const restoreMetrics = await useUnitPixelRatio(devicePixelRatio, before?.visualViewport ?? { clientWidth: 800, clientHeight: 600 });
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
596
|
+
const restore = async (wide, scrolledFrom) => {
|
|
597
|
+
await (wide ? restoreViewport() : restoreMetrics());
|
|
598
|
+
if (scrolledFrom)
|
|
599
|
+
await restoreScrollPosition(scrolledFrom);
|
|
600
|
+
};
|
|
601
|
+
let measured;
|
|
484
602
|
try {
|
|
485
|
-
|
|
603
|
+
measured = await measureInView(ref, options.padding ?? 0);
|
|
486
604
|
}
|
|
487
605
|
catch (error) {
|
|
488
|
-
await
|
|
606
|
+
await restoreViewport();
|
|
489
607
|
throw error;
|
|
490
608
|
}
|
|
609
|
+
const { box, bounds, inView, scrolledFrom } = measured;
|
|
491
610
|
const originalWidth = bounds.width;
|
|
492
611
|
const originalHeight = bounds.height;
|
|
493
612
|
const resized = shouldResize(originalWidth, originalHeight, noResize);
|
|
@@ -514,7 +633,7 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
|
|
|
514
633
|
screenshotResult = screenshotResponse.data?.result;
|
|
515
634
|
}
|
|
516
635
|
finally {
|
|
517
|
-
await
|
|
636
|
+
await restore(!inView, scrolledFrom);
|
|
518
637
|
}
|
|
519
638
|
if (!screenshotResult?.data) {
|
|
520
639
|
throw new CDPConnectionError('No screenshot data returned', new Error('Empty response'));
|
|
@@ -532,6 +651,7 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
|
|
|
532
651
|
element: {
|
|
533
652
|
bounds: roundBounds(onPage(box)),
|
|
534
653
|
...(bounds !== box && { captured: roundBounds(clip) }),
|
|
654
|
+
...(options.padding && { padding: options.padding }),
|
|
535
655
|
},
|
|
536
656
|
};
|
|
537
657
|
if (quality !== undefined) {
|
|
@@ -17,14 +17,16 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { Option } from 'commander';
|
|
19
19
|
import { registerA11yCommands } from './a11y.js';
|
|
20
|
+
import { registerAuditCommand } from './audit.js';
|
|
20
21
|
import { handleDomEval } from './eval.js';
|
|
21
22
|
import { registerFormCommand } from './form.js';
|
|
22
23
|
import { handleDomFrames } from './frames.js';
|
|
23
24
|
import { DOM_GET_DEFAULT_SELECTOR, handleDomGet } from './get.js';
|
|
25
|
+
import { QUERY_CACHE_LIMIT } from './helpers/query.js';
|
|
24
26
|
import { registerInspectCommand } from './inspect.js';
|
|
25
27
|
import { registerLayoutCommand } from './layout.js';
|
|
26
28
|
import { registerListenersCommand } from './listeners.js';
|
|
27
|
-
import { handleDomQuery } from './query.js';
|
|
29
|
+
import { handleDomQuery, QUERY_LIST_LIMIT } from './query.js';
|
|
28
30
|
import { handleDomScreenshot } from './screenshot.js';
|
|
29
31
|
import { registerWaitCommand } from './wait.js';
|
|
30
32
|
import { SELECTOR_OR_INDEX_ARGUMENT, SELECTOR_SCOPE_HELP, } from '../shared/commonOptions.js';
|
|
@@ -41,12 +43,14 @@ export function registerDomCommands(program) {
|
|
|
41
43
|
registerFormCommand(dom);
|
|
42
44
|
registerListenersCommand(dom);
|
|
43
45
|
registerLayoutCommand(dom);
|
|
46
|
+
registerAuditCommand(dom);
|
|
44
47
|
registerInspectCommand(dom);
|
|
45
48
|
registerWaitCommand(dom);
|
|
46
49
|
dom
|
|
47
50
|
.command('query')
|
|
48
51
|
.description('Find elements by CSS selector')
|
|
49
52
|
.argument('<selector>', 'CSS selector (e.g., ".error", "#app", "button")')
|
|
53
|
+
.option('--limit <n>', `Matches to list (default: ${QUERY_LIST_LIMIT}, ${QUERY_CACHE_LIMIT} with --json; 0 = all); the first ${QUERY_CACHE_LIMIT} (or more with a higher limit) are indexed`, integerOption(0))
|
|
50
54
|
.option('-j, --json', 'Output as JSON')
|
|
51
55
|
.addHelpText('after', SELECTOR_SCOPE_HELP)
|
|
52
56
|
.action(async (selector, options) => {
|
|
@@ -97,7 +101,8 @@ export function registerDomCommands(program) {
|
|
|
97
101
|
.argument('<path>', 'Output file path, or directory for --follow mode')
|
|
98
102
|
.argument('[selector]', 'Element to capture: CSS selector or index from a query (same as --selector / --index)')
|
|
99
103
|
.option('--selector <selector>', 'CSS selector for element capture')
|
|
100
|
-
.option('--index <number>', 'Cached element index (0-based) from previous query', integerOption(0))
|
|
104
|
+
.option('--index <number>', 'Cached element index (0-based) from a previous query; with --selector, which match', integerOption(0))
|
|
105
|
+
.option('--padding <px>', 'Element capture: extra space around it (shadows and focus rings are included anyway)', integerOption(0, 500))
|
|
101
106
|
.option('--format <format>', 'Image format: png or jpeg/jpg (default: from the file extension, else png)', screenshotFormatOption)
|
|
102
107
|
.option('--quality <number>', 'JPEG quality 0-100 (default: 90)', integerOption(0, 100))
|
|
103
108
|
.option('--no-full-page', 'Capture viewport only (default: full page)')
|
|
@@ -2,13 +2,30 @@
|
|
|
2
2
|
* `bdg dom query` — find elements by CSS selector and populate the query cache.
|
|
3
3
|
*/
|
|
4
4
|
import type { DomQueryCommandOptions } from '../shared/optionTypes.js';
|
|
5
|
+
import type { DomQueryResult } from '../../types.js';
|
|
6
|
+
/** Matches `dom query` lists without `--limit` (human output) */
|
|
7
|
+
export declare const QUERY_LIST_LIMIT = 50;
|
|
5
8
|
/**
|
|
6
9
|
* Handle `bdg dom query <selector>`.
|
|
7
10
|
*
|
|
8
|
-
* Runs the selector, caches the
|
|
9
|
-
* elements by index, and
|
|
11
|
+
* Runs the selector, caches the described matches so later commands can
|
|
12
|
+
* reference elements by index, and lists the first `--limit` of them (50,
|
|
13
|
+
* or {@link QUERY_CACHE_LIMIT} with `--json`; 0 = all) with the total count.
|
|
10
14
|
* No match exits 83, like `dom get` and `dom a11y`, and clears the cache so
|
|
11
15
|
* indices of an earlier query are not used by mistake.
|
|
12
16
|
*/
|
|
13
17
|
export declare function handleDomQuery(selector: string, options: DomQueryCommandOptions): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* The matches to list: the first `limit` (all with 0), with how many were
|
|
20
|
+
* left out and, when not every match was described, how many can be used by
|
|
21
|
+
* index. Nothing is added when the limit cut nothing (a match that could not
|
|
22
|
+
* be described is just missing, as before). When more than
|
|
23
|
+
* {@link VIEWPORT_HINT_LIMIT} are listed, `viewportChecked` says that only
|
|
24
|
+
* the first ones have a viewport position.
|
|
25
|
+
*
|
|
26
|
+
* @param result - Query result with every described match
|
|
27
|
+
* @param limit - Matches to list (0 = all)
|
|
28
|
+
* @returns Result to output
|
|
29
|
+
*/
|
|
30
|
+
export declare function listedMatches(result: DomQueryResult, limit: number): DomQueryResult;
|
|
14
31
|
//# sourceMappingURL=query.d.ts.map
|
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `bdg dom query` — find elements by CSS selector and populate the query cache.
|
|
3
3
|
*/
|
|
4
|
-
import { noMatchesError, queryDOMElements } from './helpers/index.js';
|
|
4
|
+
import { noMatchesError, pageDocumentId, queryDOMElements } from './helpers/index.js';
|
|
5
|
+
import { QUERY_CACHE_LIMIT, VIEWPORT_HINT_LIMIT } from './helpers/query.js';
|
|
5
6
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
6
7
|
import { QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
7
8
|
import { formatDomQuery } from '../../ui/formatters/dom.js';
|
|
8
9
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
10
|
+
/** Matches `dom query` lists without `--limit` (human output) */
|
|
11
|
+
export const QUERY_LIST_LIMIT = 50;
|
|
9
12
|
/**
|
|
10
13
|
* Handle `bdg dom query <selector>`.
|
|
11
14
|
*
|
|
12
|
-
* Runs the selector, caches the
|
|
13
|
-
* elements by index, and
|
|
15
|
+
* Runs the selector, caches the described matches so later commands can
|
|
16
|
+
* reference elements by index, and lists the first `--limit` of them (50,
|
|
17
|
+
* or {@link QUERY_CACHE_LIMIT} with `--json`; 0 = all) with the total count.
|
|
14
18
|
* No match exits 83, like `dom get` and `dom a11y`, and clears the cache so
|
|
15
19
|
* indices of an earlier query are not used by mistake.
|
|
16
20
|
*/
|
|
17
21
|
export async function handleDomQuery(selector, options) {
|
|
22
|
+
const limit = options.limit ?? (options.json ? QUERY_CACHE_LIMIT : QUERY_LIST_LIMIT);
|
|
18
23
|
await runCommand(async () => {
|
|
19
|
-
const
|
|
24
|
+
const document = await pageDocumentId();
|
|
25
|
+
const result = await queryDOMElements(selector, limit);
|
|
20
26
|
const cache = QueryCacheManager.getInstance();
|
|
21
27
|
if (result.count === 0) {
|
|
22
28
|
await cache.clear();
|
|
@@ -28,8 +34,33 @@ export async function handleDomQuery(selector, options) {
|
|
|
28
34
|
errorContext: { suggestion: err.suggestion },
|
|
29
35
|
};
|
|
30
36
|
}
|
|
31
|
-
await cache.set(result);
|
|
32
|
-
return { success: true, data: result };
|
|
37
|
+
await cache.set(result, document);
|
|
38
|
+
return { success: true, data: listedMatches(result, limit) };
|
|
33
39
|
}, options, formatDomQuery);
|
|
34
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The matches to list: the first `limit` (all with 0), with how many were
|
|
43
|
+
* left out and, when not every match was described, how many can be used by
|
|
44
|
+
* index. Nothing is added when the limit cut nothing (a match that could not
|
|
45
|
+
* be described is just missing, as before). When more than
|
|
46
|
+
* {@link VIEWPORT_HINT_LIMIT} are listed, `viewportChecked` says that only
|
|
47
|
+
* the first ones have a viewport position.
|
|
48
|
+
*
|
|
49
|
+
* @param result - Query result with every described match
|
|
50
|
+
* @param limit - Matches to list (0 = all)
|
|
51
|
+
* @returns Result to output
|
|
52
|
+
*/
|
|
53
|
+
export function listedMatches(result, limit) {
|
|
54
|
+
const listed = limit === 0 || result.count <= limit
|
|
55
|
+
? result
|
|
56
|
+
: {
|
|
57
|
+
...result,
|
|
58
|
+
nodes: result.nodes.slice(0, limit),
|
|
59
|
+
omitted: result.count - Math.min(limit, result.nodes.length),
|
|
60
|
+
...(result.nodes.length < result.count && { indexed: result.nodes.length }),
|
|
61
|
+
};
|
|
62
|
+
return listed.nodes.length > VIEWPORT_HINT_LIMIT
|
|
63
|
+
? { ...listed, viewportChecked: VIEWPORT_HINT_LIMIT }
|
|
64
|
+
: listed;
|
|
65
|
+
}
|
|
35
66
|
//# sourceMappingURL=query.js.map
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { extname } from 'path';
|
|
5
5
|
import { DomElementResolver } from './DomElementResolver.js';
|
|
6
|
-
import { capturePageScreenshot, captureElementScreenshot, resolveSelector, } from './helpers/index.js';
|
|
6
|
+
import { capturePageScreenshot, captureElementScreenshot, resolveSelector, selectMatch, } from './helpers/index.js';
|
|
7
7
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
8
8
|
import { assertFilePath, outputPathError } from '../shared/outputFile.js';
|
|
9
9
|
import { positiveIntRule } from '../shared/validation.js';
|
|
10
10
|
import { CommandError } from '../../errors/index.js';
|
|
11
|
-
import {
|
|
11
|
+
import { conflictingTargetError, genericError } from '../../errors/messages.js';
|
|
12
12
|
import { missingArgumentError } from '../../errors/messages.js';
|
|
13
13
|
import { OutputBuilder, buildSuccessResponse } from '../../ui/OutputBuilder.js';
|
|
14
14
|
import { formatDomScreenshot } from '../../ui/formatters/dom.js';
|
|
15
15
|
import { createLogger } from '../../ui/logging/index.js';
|
|
16
16
|
import { delay } from '../../utils/async.js';
|
|
17
|
+
import { makeDirectory } from '../../utils/directories.js';
|
|
17
18
|
import { getErrorMessage } from '../../utils/errors.js';
|
|
18
19
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
19
20
|
import { filterDefined } from '../../utils/objects.js';
|
|
@@ -60,12 +61,16 @@ function buildElementScreenshotOptions(options) {
|
|
|
60
61
|
format: options.format,
|
|
61
62
|
quality: options.quality,
|
|
62
63
|
noResize: options.resize === false,
|
|
64
|
+
padding: options.padding,
|
|
63
65
|
});
|
|
64
66
|
}
|
|
65
67
|
function hasElementTarget(options) {
|
|
66
68
|
return options.selector !== undefined || options.index !== undefined;
|
|
67
69
|
}
|
|
68
70
|
async function resolveElementNodeId(options) {
|
|
71
|
+
if (options.selector !== undefined && options.index !== undefined) {
|
|
72
|
+
return { backendNodeId: await selectMatch(options.selector, options.index) };
|
|
73
|
+
}
|
|
69
74
|
if (options.index !== undefined) {
|
|
70
75
|
const resolver = DomElementResolver.getInstance();
|
|
71
76
|
const node = await resolver.getNodeIdForIndex(options.index);
|
|
@@ -106,7 +111,7 @@ function ensureDirectory(dirPath, fs) {
|
|
|
106
111
|
throw new CommandError(`--follow needs a directory, but ${dirPath} is a file`, { suggestion: 'Give a directory for the frames, e.g. bdg dom screenshot ./frames --follow' }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
107
112
|
}
|
|
108
113
|
try {
|
|
109
|
-
|
|
114
|
+
makeDirectory(dirPath);
|
|
110
115
|
}
|
|
111
116
|
catch (error) {
|
|
112
117
|
throw outputPathError(dirPath, error);
|
|
@@ -207,8 +212,8 @@ function reportSequenceError(error, captured, json) {
|
|
|
207
212
|
process.exit(exitCode);
|
|
208
213
|
}
|
|
209
214
|
/**
|
|
210
|
-
* Reject options that would be ignored: `--
|
|
211
|
-
*
|
|
215
|
+
* Reject options that would be ignored: `--quality` for a PNG, and
|
|
216
|
+
* `--padding` without an element.
|
|
212
217
|
*
|
|
213
218
|
* @param outputPath - File to write
|
|
214
219
|
* @param options - Command options
|
|
@@ -216,8 +221,8 @@ function reportSequenceError(error, captured, json) {
|
|
|
216
221
|
*/
|
|
217
222
|
function assertScreenshotOptions(outputPath, options) {
|
|
218
223
|
let message;
|
|
219
|
-
if (options.
|
|
220
|
-
message =
|
|
224
|
+
if (options.padding !== undefined && !hasElementTarget(options)) {
|
|
225
|
+
message = '--padding applies to element captures; name an element (selector or index)';
|
|
221
226
|
}
|
|
222
227
|
else if (options.quality !== undefined &&
|
|
223
228
|
!options.follow &&
|
|
@@ -21,10 +21,11 @@ export interface SemanticNodeWithContext {
|
|
|
21
21
|
* link's href, a field's type and name), like `dom query` does, and is
|
|
22
22
|
* followed by up to 500 characters of the element's text
|
|
23
23
|
* (all of it with `dom get --full`) when it is longer than the one-line
|
|
24
|
-
* preview
|
|
24
|
+
* preview or the role line shows an accessible name other than the text,
|
|
25
|
+
* or, for an element without text or name, what it holds.
|
|
25
26
|
*
|
|
26
27
|
* @param data - Accessibility node and optional DOM context
|
|
27
|
-
* @returns Role line, plus a text line for elements with longer text
|
|
28
|
+
* @returns Role line, plus a text line for elements with longer or differently named text
|
|
28
29
|
*/
|
|
29
30
|
export declare function formatSemanticNodeWithContext(data: SemanticNodeWithContext): string;
|
|
30
31
|
/**
|