browser-debugger-cli 0.8.0 → 0.10.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/README.md +7 -1
- package/dist/cdp/schema.d.ts +4 -1
- package/dist/cdp/schema.js +48 -7
- package/dist/commands/cdp.js +3 -2
- package/dist/commands/cleanup.d.ts +11 -0
- package/dist/commands/cleanup.js +161 -57
- package/dist/commands/console.d.ts +20 -1
- package/dist/commands/console.js +57 -17
- package/dist/commands/details.js +3 -2
- package/dist/commands/dom/DomElementResolver.d.ts +10 -3
- package/dist/commands/dom/DomElementResolver.js +35 -17
- package/dist/commands/dom/a11y.d.ts +10 -0
- package/dist/commands/dom/a11y.js +29 -6
- package/dist/commands/dom/eval.d.ts +3 -1
- package/dist/commands/dom/eval.js +29 -4
- package/dist/commands/dom/form.js +16 -62
- package/dist/commands/dom/formInteraction.js +189 -119
- package/dist/commands/dom/formSummary.d.ts +49 -0
- package/dist/commands/dom/formSummary.js +180 -0
- package/dist/commands/dom/frames.d.ts +2 -1
- package/dist/commands/dom/frames.js +17 -2
- package/dist/commands/dom/get.d.ts +6 -5
- package/dist/commands/dom/get.js +92 -82
- 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 +20 -0
- package/dist/commands/dom/helpers/keyAttributes.js +54 -0
- package/dist/commands/dom/helpers/query.d.ts +44 -17
- package/dist/commands/dom/helpers/query.js +300 -106
- package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
- package/dist/commands/dom/helpers/runElementCommand.js +98 -30
- package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
- package/dist/commands/dom/helpers/screenshot.js +239 -51
- package/dist/commands/dom/index.d.ts +4 -1
- package/dist/commands/dom/index.js +22 -7
- package/dist/commands/dom/inspect.d.ts +15 -0
- package/dist/commands/dom/inspect.js +82 -0
- package/dist/commands/dom/layout.d.ts +14 -0
- package/dist/commands/dom/layout.js +54 -0
- package/dist/commands/dom/listeners.d.ts +5 -1
- package/dist/commands/dom/listeners.js +15 -5
- package/dist/commands/dom/query.js +2 -3
- package/dist/commands/dom/screenshot.d.ts +12 -2
- package/dist/commands/dom/screenshot.js +27 -3
- package/dist/commands/dom/semanticUtils.d.ts +16 -10
- package/dist/commands/dom/semanticUtils.js +53 -16
- package/dist/commands/dom/wait.d.ts +13 -0
- package/dist/commands/dom/wait.js +83 -0
- package/dist/commands/helpJson.js +2 -2
- package/dist/commands/network/list.js +17 -13
- package/dist/commands/optionBehaviors.js +154 -21
- package/dist/commands/page.d.ts +3 -2
- package/dist/commands/page.js +100 -5
- package/dist/commands/peek.js +4 -11
- package/dist/commands/sessions.d.ts +8 -0
- package/dist/commands/sessions.js +19 -0
- package/dist/commands/shared/CommandRunner.js +4 -4
- package/dist/commands/shared/commonOptions.d.ts +4 -0
- package/dist/commands/shared/commonOptions.js +9 -0
- package/dist/commands/shared/dataFetcher.js +2 -2
- package/dist/commands/shared/followMode.d.ts +21 -1
- package/dist/commands/shared/followMode.js +29 -2
- package/dist/commands/shared/handleValidationError.d.ts +2 -2
- package/dist/commands/shared/handleValidationError.js +12 -3
- package/dist/commands/shared/optionTypes.d.ts +61 -5
- package/dist/commands/shared/startHelpers.d.ts +66 -0
- package/dist/commands/shared/startHelpers.js +103 -13
- package/dist/commands/shared/validation.d.ts +14 -2
- package/dist/commands/shared/validation.js +20 -3
- package/dist/commands/start.d.ts +63 -0
- package/dist/commands/start.js +115 -15
- package/dist/commands/status.js +29 -7
- package/dist/commands/stop.js +7 -6
- package/dist/commands/tail.js +4 -11
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/connection/chromeIdentity.d.ts +65 -0
- package/dist/connection/chromeIdentity.js +143 -0
- package/dist/connection/launcher/profilePreferences.d.ts +47 -0
- package/dist/connection/launcher/profilePreferences.js +151 -0
- package/dist/connection/launcher.d.ts +21 -2
- package/dist/connection/launcher.js +42 -16
- package/dist/connection/portReservation.d.ts +14 -4
- package/dist/connection/portReservation.js +21 -6
- package/dist/connection/startupExit.d.ts +8 -0
- package/dist/connection/startupExit.js +15 -6
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +9 -2
- package/dist/daemon/SessionController.js +23 -7
- package/dist/daemon/errors.d.ts +1 -1
- package/dist/daemon/errors.js +1 -1
- package/dist/daemon/launcher.d.ts +10 -2
- package/dist/daemon/launcher.js +8 -7
- package/dist/daemon/server/SocketServer.js +1 -2
- package/dist/daemon/session/Session.d.ts +20 -0
- package/dist/daemon/session/Session.js +80 -9
- package/dist/daemon/session/chromeConnection.d.ts +9 -0
- package/dist/daemon/session/chromeConnection.js +45 -8
- package/dist/daemon/session/commandRegistry.d.ts +14 -1
- package/dist/daemon/session/commandRegistry.js +113 -67
- package/dist/daemon/session/interactions.d.ts +48 -9
- package/dist/daemon/session/interactions.js +46 -9
- package/dist/daemon/session/triggeredRequests.d.ts +67 -0
- package/dist/daemon/session/triggeredRequests.js +157 -0
- package/dist/daemon/session/types.d.ts +5 -1
- package/dist/daemon.js +10630 -3601
- package/dist/errors/messages.d.ts +456 -24
- package/dist/errors/messages.js +862 -67
- package/dist/index.js +6915 -3401
- package/dist/ipc/client.d.ts +21 -1
- package/dist/ipc/client.js +35 -3
- package/dist/ipc/protocol/commands.d.ts +145 -5
- package/dist/ipc/protocol/commands.js +4 -0
- package/dist/ipc/protocol/domTypes.d.ts +291 -7
- package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
- package/dist/ipc/protocol/inspectTypes.js +10 -0
- package/dist/ipc/session/lifecycle.d.ts +8 -1
- package/dist/ipc/session/queries.d.ts +5 -1
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/index.d.ts +2 -1
- package/dist/ipc/transport/index.js +2 -2
- package/dist/runtime/dom/actionEffects.d.ts +185 -0
- package/dist/runtime/dom/actionEffects.js +402 -0
- package/dist/runtime/dom/actionEffectsScripts.d.ts +90 -0
- package/dist/runtime/dom/actionEffectsScripts.js +426 -0
- package/dist/runtime/dom/elementGeometry.d.ts +170 -0
- package/dist/runtime/dom/elementGeometry.js +553 -0
- package/dist/runtime/dom/elementInfo.d.ts +103 -0
- package/dist/runtime/dom/elementInfo.js +256 -0
- package/dist/runtime/dom/evalHelpers.d.ts +51 -6
- package/dist/runtime/dom/evalHelpers.js +136 -26
- package/dist/runtime/dom/eventListeners.d.ts +2 -1
- package/dist/runtime/dom/eventListeners.js +184 -47
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/formDiscovery.js +116 -16
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +9 -0
- package/dist/runtime/dom/formFillHelpers/fill.js +178 -14
- package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
- package/dist/runtime/dom/formFillHelpers/index.js +2 -2
- package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
- package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
- package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
- package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
- package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
- package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
- package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
- package/dist/runtime/dom/formSubmitHelpers.js +89 -15
- package/dist/runtime/dom/frameLayout.d.ts +60 -0
- package/dist/runtime/dom/frameLayout.js +140 -0
- package/dist/runtime/dom/frameOrigin.d.ts +50 -0
- package/dist/runtime/dom/frameOrigin.js +62 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
- package/dist/runtime/dom/frameScopedConnection.js +252 -0
- package/dist/runtime/dom/frameSelection.d.ts +12 -1
- package/dist/runtime/dom/frameSelection.js +22 -3
- package/dist/runtime/dom/frames.d.ts +61 -5
- package/dist/runtime/dom/frames.js +329 -75
- package/dist/runtime/dom/inspect.d.ts +28 -0
- package/dist/runtime/dom/inspect.js +557 -0
- package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
- package/dist/runtime/dom/inspectAllStyles.js +385 -0
- package/dist/runtime/dom/inspectCascade.d.ts +94 -0
- package/dist/runtime/dom/inspectCascade.js +371 -0
- package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
- package/dist/runtime/dom/inspectCascadeModel.js +232 -0
- package/dist/runtime/dom/inspectHints.d.ts +62 -0
- package/dist/runtime/dom/inspectHints.js +305 -0
- package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
- package/dist/runtime/dom/inspectLayoutModel.js +346 -0
- package/dist/runtime/dom/inspectModel.d.ts +74 -0
- package/dist/runtime/dom/inspectModel.js +184 -0
- package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
- package/dist/runtime/dom/inspectPaintModel.js +461 -0
- package/dist/runtime/dom/inspectRules.d.ts +37 -0
- package/dist/runtime/dom/inspectRules.js +101 -0
- package/dist/runtime/dom/inspectScripts.d.ts +132 -0
- package/dist/runtime/dom/inspectScripts.js +263 -0
- package/dist/runtime/dom/inspectTree.d.ts +40 -0
- package/dist/runtime/dom/inspectTree.js +134 -0
- package/dist/runtime/dom/inspectVariables.d.ts +33 -0
- package/dist/runtime/dom/inspectVariables.js +94 -0
- package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
- package/dist/runtime/dom/inspectWhyModel.js +134 -0
- package/dist/runtime/dom/layout.d.ts +71 -0
- package/dist/runtime/dom/layout.js +340 -0
- package/dist/runtime/dom/listenerPageScripts.d.ts +72 -0
- package/dist/runtime/dom/listenerPageScripts.js +365 -0
- package/dist/runtime/dom/listenerSummary.d.ts +136 -11
- package/dist/runtime/dom/listenerSummary.js +361 -22
- package/dist/runtime/dom/pageActivity.d.ts +41 -0
- package/dist/runtime/dom/pageActivity.js +123 -0
- package/dist/runtime/dom/reactEventHelpers.d.ts +63 -2
- package/dist/runtime/dom/reactEventHelpers.js +220 -41
- package/dist/runtime/dom/targetNode.d.ts +80 -27
- package/dist/runtime/dom/targetNode.js +249 -33
- package/dist/runtime/dom/wait.d.ts +25 -0
- package/dist/runtime/dom/wait.js +199 -0
- package/dist/runtime/dom/waitCondition.d.ts +71 -0
- package/dist/runtime/dom/waitCondition.js +75 -0
- package/dist/runtime/page/emulation.d.ts +71 -0
- package/dist/runtime/page/emulation.js +117 -0
- package/dist/runtime/page/loadingState.d.ts +36 -0
- package/dist/runtime/page/loadingState.js +86 -0
- package/dist/runtime/page/navigation.d.ts +46 -2
- package/dist/runtime/page/navigation.js +69 -33
- package/dist/session/QueryCacheManager.d.ts +11 -1
- package/dist/session/QueryCacheManager.js +25 -3
- package/dist/session/chromeOwners.d.ts +34 -0
- package/dist/session/chromeOwners.js +51 -0
- package/dist/session/cleanup/staleSession.d.ts +11 -1
- package/dist/session/cleanup/staleSession.js +17 -6
- package/dist/session/cleanup/userCommands.js +2 -4
- package/dist/session/metadata.d.ts +5 -1
- package/dist/session/metadata.js +2 -1
- package/dist/session/paths.d.ts +77 -3
- package/dist/session/paths.js +111 -5
- package/dist/session/port.d.ts +31 -7
- package/dist/session/port.js +50 -43
- package/dist/session/portClaims.d.ts +66 -0
- package/dist/session/portClaims.js +284 -0
- package/dist/session/sessionList.d.ts +58 -0
- package/dist/session/sessionList.js +199 -0
- package/dist/session/sessionName.d.ts +46 -0
- package/dist/session/sessionName.js +97 -0
- package/dist/telemetry/a11y.d.ts +18 -3
- package/dist/telemetry/a11y.js +170 -29
- package/dist/telemetry/console.d.ts +1 -0
- package/dist/telemetry/console.js +100 -5
- package/dist/telemetry/network.js +3 -1
- package/dist/telemetry/requestKinds.d.ts +32 -0
- package/dist/telemetry/requestKinds.js +61 -0
- package/dist/telemetry/requestState.d.ts +31 -0
- package/dist/telemetry/requestState.js +38 -0
- package/dist/types.d.ts +112 -3
- package/dist/ui/formatters/a11y.js +3 -0
- package/dist/ui/formatters/console/chronological.d.ts +8 -0
- package/dist/ui/formatters/console/chronological.js +17 -4
- package/dist/ui/formatters/console/json.js +3 -4
- package/dist/ui/formatters/console/shared.d.ts +12 -0
- package/dist/ui/formatters/console.d.ts +2 -2
- package/dist/ui/formatters/console.js +1 -1
- package/dist/ui/formatters/details.d.ts +8 -0
- package/dist/ui/formatters/details.js +61 -4
- package/dist/ui/formatters/dom.d.ts +27 -14
- package/dist/ui/formatters/dom.js +88 -59
- package/dist/ui/formatters/form.js +29 -18
- package/dist/ui/formatters/inspect.d.ts +39 -0
- package/dist/ui/formatters/inspect.js +596 -0
- package/dist/ui/formatters/keyAttributes.d.ts +19 -0
- package/dist/ui/formatters/keyAttributes.js +84 -0
- package/dist/ui/formatters/layout.d.ts +31 -0
- package/dist/ui/formatters/layout.js +53 -0
- package/dist/ui/formatters/listeners.d.ts +3 -2
- package/dist/ui/formatters/listeners.js +73 -9
- package/dist/ui/formatters/networkHeaders.d.ts +13 -0
- package/dist/ui/formatters/networkHeaders.js +36 -3
- package/dist/ui/formatters/networkList.d.ts +29 -1
- package/dist/ui/formatters/networkList.js +86 -20
- package/dist/ui/formatters/preview.js +2 -1
- package/dist/ui/formatters/requestStatus.d.ts +1 -17
- package/dist/ui/formatters/requestStatus.js +2 -30
- package/dist/ui/formatters/sessions.d.ts +12 -0
- package/dist/ui/formatters/sessions.js +40 -0
- package/dist/ui/formatters/status.d.ts +21 -2
- package/dist/ui/formatters/status.js +47 -10
- package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
- package/dist/ui/formatters/triggeredRequests.js +65 -0
- package/dist/ui/formatting.d.ts +19 -0
- package/dist/ui/formatting.js +31 -36
- package/dist/ui/messages/chrome.d.ts +9 -0
- package/dist/ui/messages/chrome.js +17 -5
- package/dist/ui/messages/commands.d.ts +504 -14
- package/dist/ui/messages/commands.js +835 -21
- package/dist/ui/messages/consoleMessages.d.ts +10 -0
- package/dist/ui/messages/consoleMessages.js +17 -0
- package/dist/ui/messages/hints.js +2 -1
- package/dist/ui/messages/networkMessages.d.ts +14 -0
- package/dist/ui/messages/networkMessages.js +18 -0
- package/dist/ui/messages/preview.js +5 -4
- package/dist/ui/messages/session.d.ts +30 -21
- package/dist/ui/messages/session.js +48 -26
- package/dist/ui/messages/sessionCommand.d.ts +43 -0
- package/dist/ui/messages/sessionCommand.js +52 -0
- package/dist/utils/async.d.ts +17 -0
- package/dist/utils/async.js +36 -0
- package/dist/utils/color.d.ts +84 -0
- package/dist/utils/color.js +376 -0
- package/dist/utils/cssValues.d.ts +109 -0
- package/dist/utils/cssValues.js +236 -0
- package/dist/utils/http.d.ts +22 -1
- package/dist/utils/http.js +28 -9
- package/dist/utils/selectorFilters.d.ts +48 -8
- package/dist/utils/selectorFilters.js +296 -53
- package/dist/utils/shellDetection.d.ts +8 -2
- package/dist/utils/shellDetection.js +120 -33
- package/dist/utils/suggestions.d.ts +26 -0
- package/dist/utils/suggestions.js +73 -0
- package/dist/utils/taskMappings.js +10 -0
- package/dist/utils/url.d.ts +12 -2
- package/dist/utils/url.js +69 -7
- package/package.json +1 -1
- package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
- package/dist/ui/formatters/sessionFormatters.js +0 -121
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* cleaning up stale files, and validating command arguments.
|
|
6
6
|
*/
|
|
7
7
|
import { buildAgentDiscoveryHelp, buildCommonTaskExamples, buildUrlExamples, buildSessionManagementReminder, } from '../formatters/helpFormatters.js';
|
|
8
|
-
import { joinLines } from '../formatting.js';
|
|
8
|
+
import { formatDuration, joinLines, pluralize, truncateUrl } from '../formatting.js';
|
|
9
|
+
import { sessionCommand } from './sessionCommand.js';
|
|
10
|
+
import { truncateByLength } from '../../utils/strings.js';
|
|
9
11
|
/**
|
|
10
12
|
* Chrome closed by `bdg stop` (gracefully, so the profile is saved).
|
|
11
13
|
*
|
|
@@ -33,14 +35,475 @@ export function orphanedDaemonsCleanedMessage(count) {
|
|
|
33
35
|
export function domClickFallbackWarning(reason) {
|
|
34
36
|
return `Element is ${reason ?? 'not reachable by the mouse'}; dispatched DOM events instead of mouse events (a user could not reach it like this)`;
|
|
35
37
|
}
|
|
38
|
+
/** Reason of a `bdg dom form` blocker for a required field left empty */
|
|
39
|
+
export const REQUIRED_FIELD_EMPTY_REASON = 'Required field is empty';
|
|
40
|
+
/**
|
|
41
|
+
* Field labels as a list (without a trailing colon), the first five and how
|
|
42
|
+
* many more.
|
|
43
|
+
*
|
|
44
|
+
* @param labels - Field labels
|
|
45
|
+
* @returns e.g. "Last Name, Zip"
|
|
46
|
+
*/
|
|
47
|
+
function fieldLabelList(labels) {
|
|
48
|
+
const shown = labels
|
|
49
|
+
.slice(0, 5)
|
|
50
|
+
.map((label) => label.replace(/\s*:\s*$/, ''))
|
|
51
|
+
.join(', ');
|
|
52
|
+
return labels.length > 5 ? `${shown} and ${labels.length - 5} more` : shown;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Part of the `bdg dom form` summary naming the required fields left empty.
|
|
56
|
+
*
|
|
57
|
+
* @param labels - Labels of the empty required fields
|
|
58
|
+
* @returns e.g. "2 required fields empty: Last Name, Zip"
|
|
59
|
+
*/
|
|
60
|
+
export function requiredFieldsEmptyMessage(labels) {
|
|
61
|
+
const fields = labels.length === 1 ? 'field' : 'fields';
|
|
62
|
+
return `${labels.length} required ${fields} empty: ${fieldLabelList(labels)}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Readiness at the end of the `bdg dom form` summary.
|
|
66
|
+
*
|
|
67
|
+
* @param summary - Whether the form is ready, how many fields are filled and
|
|
68
|
+
* required, and the labels of the empty ones
|
|
69
|
+
* @returns e.g. "READY to submit", "NOT ready (no fields filled)"
|
|
70
|
+
*/
|
|
71
|
+
export function formReadinessMessage(summary) {
|
|
72
|
+
if (!summary.readyToSubmit) {
|
|
73
|
+
return summary.filledFields === 0 ? 'NOT ready (no fields filled)' : 'NOT ready';
|
|
74
|
+
}
|
|
75
|
+
if (summary.requiredTotal > 0 || summary.emptyFieldLabels.length === 0)
|
|
76
|
+
return 'READY to submit';
|
|
77
|
+
return `READY to submit (no field is marked required; empty: ${fieldLabelList(summary.emptyFieldLabels)})`;
|
|
78
|
+
}
|
|
79
|
+
/** Why an action's status line is not a clean success when nothing changed */
|
|
80
|
+
export const NO_VISIBLE_EFFECT = 'no visible effect observed: no DOM change, requests or navigation within 300 ms';
|
|
81
|
+
/**
|
|
82
|
+
* Status line of a DOM action: a check mark only for a clean success.
|
|
83
|
+
*
|
|
84
|
+
* @param done - What was done, e.g. "Element Clicked"
|
|
85
|
+
* @param state - Whether the action has warnings (shown right below), had no
|
|
86
|
+
* visible effect, or returned while the page was still changing
|
|
87
|
+
* @returns e.g. "✓ Element Clicked", "⚠ Element Clicked (with warnings)",
|
|
88
|
+
* "⚠ Element Clicked (page still changing)" or
|
|
89
|
+
* "⚠ Element Clicked (no visible effect observed: no DOM change, requests or navigation within 300 ms)"
|
|
90
|
+
*/
|
|
91
|
+
export function actionStatusLine(done, state) {
|
|
92
|
+
if (state.noEffect)
|
|
93
|
+
return `⚠ ${done} (${NO_VISIBLE_EFFECT})`;
|
|
94
|
+
const notes = [state.warned && 'with warnings', state.stillChanging && 'page still changing'];
|
|
95
|
+
const shown = notes.filter((note) => typeof note === 'string');
|
|
96
|
+
return shown.length > 0 ? `⚠ ${done} (${shown.join('; ')})` : `✓ ${done}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Note under the status line of an action that returned while the page was
|
|
100
|
+
* still changing.
|
|
101
|
+
*
|
|
102
|
+
* @param action - What returned, e.g. "click", "key press"
|
|
103
|
+
* @param pending - What the page was still working on
|
|
104
|
+
* @returns e.g. "The page was still changing when the click returned (2 requests pending); wait for the result with bdg dom wait <selector>"
|
|
105
|
+
*/
|
|
106
|
+
export function stillChangingNote(action, pending) {
|
|
107
|
+
const parts = [
|
|
108
|
+
pending.requests !== undefined && `${pluralize(pending.requests, 'request')} pending`,
|
|
109
|
+
pending.navigation && 'a new page still loading',
|
|
110
|
+
pending.loading !== undefined && `loading indicator ${pending.loading} shown`,
|
|
111
|
+
pending.domChanging && 'DOM still changing',
|
|
112
|
+
pending.busy && 'page busy running a script',
|
|
113
|
+
].filter((part) => typeof part === 'string');
|
|
114
|
+
const wait = sessionCommand('bdg dom wait <selector>');
|
|
115
|
+
return `The page was still changing when the ${action} returned (${parts.join(', ')}); wait for the result with ${wait}`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* An element an action showed, for its `Shown:` rows.
|
|
119
|
+
*
|
|
120
|
+
* @param element - Shown element
|
|
121
|
+
* @returns e.g. `div.figcaption "name: user2 View profile"`
|
|
122
|
+
*/
|
|
123
|
+
export function shownElementText(element) {
|
|
124
|
+
return `${element.element} "${element.text}"`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* How an action changed the page's location, for its `Page:` row.
|
|
128
|
+
*
|
|
129
|
+
* @param navigation - Navigation the action caused
|
|
130
|
+
* @returns e.g. "navigated to https://example.com/secure (200)" or
|
|
131
|
+
* "URL changed to https://example.com/#/active (same document)"
|
|
132
|
+
*/
|
|
133
|
+
export function pageNavigationText(navigation) {
|
|
134
|
+
if (navigation.sameDocument)
|
|
135
|
+
return `URL changed to ${navigation.url} (same document)`;
|
|
136
|
+
const status = navigation.status === undefined ? '' : ` (${navigation.status})`;
|
|
137
|
+
return `navigated to ${navigation.url}${status}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A message an action made appear, for its `New text:` rows.
|
|
141
|
+
*
|
|
142
|
+
* @param message - New message
|
|
143
|
+
* @returns e.g. `"Your password is invalid!" (div#flash.flash.error)`
|
|
144
|
+
*/
|
|
145
|
+
export function newMessageText(message) {
|
|
146
|
+
return `"${message.text}" (${message.element})`;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Warning shown when a filled field's value read back is not the one given:
|
|
150
|
+
* cut to its maxlength, a password of another length (values never shown),
|
|
151
|
+
* or another value (naming the field the value went to, when one has it).
|
|
152
|
+
*
|
|
153
|
+
* @param mismatch - Value given and value found (masked for passwords)
|
|
154
|
+
* @returns Warning text
|
|
155
|
+
*/
|
|
156
|
+
export function valueMismatchWarning(mismatch) {
|
|
157
|
+
if (mismatch.truncatedTo !== undefined) {
|
|
158
|
+
return `The value was cut to ${mismatch.truncatedTo} characters by maxlength`;
|
|
159
|
+
}
|
|
160
|
+
if (mismatch.expectedLength !== undefined) {
|
|
161
|
+
return `The password field's value differs from the one filled (length ${mismatch.actualLength ?? 0}, expected ${mismatch.expectedLength}); the page may have rejected or changed the input`;
|
|
162
|
+
}
|
|
163
|
+
const outcome = mismatch.movedTo === undefined
|
|
164
|
+
? 'the page may have rejected or moved the input'
|
|
165
|
+
: `the value appeared in ${mismatch.movedTo} instead`;
|
|
166
|
+
return `The field's value is "${mismatch.actual}" after filling (expected "${mismatch.expected}"); ${outcome}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Warning shown when a mouse press was dispatched but the target never
|
|
170
|
+
* received it (e.g. a browser dialog or bubble captured the input).
|
|
171
|
+
*/
|
|
172
|
+
export const CLICK_NOT_RECEIVED_WARNING = 'The click may not have reached the element: the page saw no mouse press (the browser may be showing a dialog or bubble that captures input)';
|
|
36
173
|
/**
|
|
37
174
|
* Note under a shortened list of matches.
|
|
38
175
|
*
|
|
39
176
|
* @param hidden - Matches not listed
|
|
40
|
-
* @
|
|
177
|
+
* @param jsonLimit - How many JSON output lists, when it leaves some out too
|
|
178
|
+
* @returns e.g. "... and 1174 more (use --json for all)",
|
|
179
|
+
* "... and 8980 more (--json lists the first 100)"
|
|
180
|
+
*/
|
|
181
|
+
export function moreMatchesNote(hidden, jsonLimit) {
|
|
182
|
+
const where = jsonLimit === undefined ? 'use --json for all' : `--json lists the first ${jsonLimit}`;
|
|
183
|
+
return `... and ${hidden} more (${where})`;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Note under a list of a11y query matches cut by `--limit`.
|
|
187
|
+
*
|
|
188
|
+
* @param omitted - Matches not listed
|
|
189
|
+
* @returns e.g. "... and 213 more (--limit 0 lists all; their indices work too)"
|
|
190
|
+
*/
|
|
191
|
+
export function a11yMoreMatchesNote(omitted) {
|
|
192
|
+
return `... and ${omitted} more (--limit 0 lists all; their indices work too)`;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Note under a shortened list of requests an action triggered when JSON
|
|
196
|
+
* output left some out too (they are only in the network telemetry then).
|
|
197
|
+
*
|
|
198
|
+
* @param hidden - Requests not listed
|
|
199
|
+
* @returns e.g. "... and 50 more (see bdg network list)"
|
|
200
|
+
*/
|
|
201
|
+
export function moreRequestsNote(hidden) {
|
|
202
|
+
return `... and ${hidden} more (see ${sessionCommand('bdg network list')})`;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Title of the list of requests that started while an action ran (they are
|
|
206
|
+
* attributed by time, so a page poller's requests are listed too: the title
|
|
207
|
+
* doesn't claim the action caused them).
|
|
208
|
+
*
|
|
209
|
+
* @param total - Requests in all
|
|
210
|
+
* @returns e.g. "Requests during the action (18):"
|
|
211
|
+
*/
|
|
212
|
+
export function triggeredRequestsTitle(total) {
|
|
213
|
+
return `Requests during the action (${total}):`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Line counting the static assets an action loaded instead of listing them.
|
|
217
|
+
*
|
|
218
|
+
* @param count - Asset requests
|
|
219
|
+
* @param types - Short type names, e.g. ["css", "js", "images"]
|
|
220
|
+
* @returns e.g. "+ 97 assets (css, js, fonts, images)"
|
|
221
|
+
*/
|
|
222
|
+
export function assetRequestsNote(count, types) {
|
|
223
|
+
return `+ ${count} ${count === 1 ? 'asset' : 'assets'} (${types.join(', ')})`;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Pieces of the reasons `bdg dom layout` gives for hidden and invisible
|
|
227
|
+
* elements. The page-side measurement builds the reasons from them, e.g.
|
|
228
|
+
* `clipped by div#acc: zero height`, `opacity: 0 on div#menu`.
|
|
229
|
+
*/
|
|
230
|
+
export const LAYOUT_REASONS = {
|
|
231
|
+
/** Hidden: an `<option>` of a closed `<select>` has no box */
|
|
232
|
+
option: 'not rendered (an <option> is shown by its <select>)',
|
|
233
|
+
/** Hidden: start of the reason for a clipping container with no area, followed by it */
|
|
234
|
+
clippedBy: 'clipped by ',
|
|
235
|
+
/** Which size of that container is zero */
|
|
236
|
+
zeroHeight: 'zero height',
|
|
237
|
+
zeroWidth: 'zero width',
|
|
238
|
+
/** Invisible: fully transparent */
|
|
239
|
+
transparent: 'opacity: 0',
|
|
240
|
+
/** Joins an invisible reason to the ancestor causing it */
|
|
241
|
+
on: ' on ',
|
|
242
|
+
};
|
|
243
|
+
/** Start of the off-screen reason of an element a scroll-locked page hides ({@link scrollLockedReason}) */
|
|
244
|
+
const SCROLL_LOCKED_PREFIX = 'page scrolling is locked';
|
|
245
|
+
/**
|
|
246
|
+
* Off-screen reason for an element out of view on a page whose scrolling is
|
|
247
|
+
* locked, naming the visible dialog that likely locked it when there is one.
|
|
248
|
+
*
|
|
249
|
+
* @param lock - What locks it, e.g. `overflow: hidden on body`
|
|
250
|
+
* @param dialog - Visible dialog on the page, e.g. `div#consent` (null: none)
|
|
251
|
+
* @returns e.g. `page scrolling is locked (overflow: hidden on body), likely by dialog div#consent`,
|
|
252
|
+
* or `page scrolling is locked (overflow: hidden on body)`
|
|
253
|
+
*/
|
|
254
|
+
export function scrollLockedReason(lock, dialog = null) {
|
|
255
|
+
const cause = dialog ? `, likely by dialog ${dialog}` : '';
|
|
256
|
+
return `${SCROLL_LOCKED_PREFIX} (${lock})${cause}`;
|
|
257
|
+
}
|
|
258
|
+
/** Short location hints for elements a user cannot see without scrolling */
|
|
259
|
+
const VIEWPORT_POSITION_HINTS = {
|
|
260
|
+
above: 'above viewport',
|
|
261
|
+
below: 'below fold',
|
|
262
|
+
left: 'left of viewport',
|
|
263
|
+
right: 'right of viewport',
|
|
264
|
+
hidden: 'hidden',
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Location hint for an element outside the viewport or hidden.
|
|
268
|
+
*
|
|
269
|
+
* @param position - Where the element is
|
|
270
|
+
* @param clippedBy - Ancestor or iframe cutting it off, if any
|
|
271
|
+
* @returns e.g. "below fold", "out of view in ul#list"; undefined for
|
|
272
|
+
* elements (partly) in view
|
|
273
|
+
*/
|
|
274
|
+
export function viewportPositionHint(position, clippedBy) {
|
|
275
|
+
const outside = position !== 'visible' && position !== 'partly' && position !== 'hidden';
|
|
276
|
+
if (outside && clippedBy)
|
|
277
|
+
return `out of view in ${clippedBy}`;
|
|
278
|
+
return VIEWPORT_POSITION_HINTS[position];
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Page scroll that would bring an element into view, in words.
|
|
282
|
+
*
|
|
283
|
+
* @param scrollBy - Scroll amounts
|
|
284
|
+
* @param purpose - What the scroll does, e.g. "centre it"
|
|
285
|
+
* @returns e.g. "scroll down 760px to centre it"
|
|
286
|
+
*/
|
|
287
|
+
function scrollAdvice(scrollBy, purpose) {
|
|
288
|
+
const steps = [
|
|
289
|
+
scrollBy.y !== 0 && `${scrollBy.y > 0 ? 'down' : 'up'} ${Math.abs(scrollBy.y)}px`,
|
|
290
|
+
scrollBy.x !== 0 && `${scrollBy.x > 0 ? 'right' : 'left'} ${Math.abs(scrollBy.x)}px`,
|
|
291
|
+
].filter(Boolean);
|
|
292
|
+
return `scroll ${steps.join(', ')} to ${purpose}`;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Whether an element fits the viewport (the scroll then centres it; a larger
|
|
296
|
+
* one gets its start aligned).
|
|
297
|
+
*
|
|
298
|
+
* @param element - Element layout
|
|
299
|
+
* @param viewport - Viewport size, when known
|
|
300
|
+
* @returns True when it fits, or the viewport is unknown
|
|
301
|
+
*/
|
|
302
|
+
function fitsViewport(element, viewport) {
|
|
303
|
+
const { width, height } = element.bounds;
|
|
304
|
+
return !viewport || (width <= viewport.width && height <= viewport.height);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* How to bring an element that is out of view into view, in words.
|
|
308
|
+
*
|
|
309
|
+
* @param element - Element layout
|
|
310
|
+
* @param viewport - Viewport size (an element larger than it is not centred)
|
|
311
|
+
* @returns e.g. "scroll down 760px to centre it", "off-screen: fixed position, page scroll
|
|
312
|
+
* does not move it"; undefined when neither applies
|
|
313
|
+
*/
|
|
314
|
+
function layoutScrollNote(element, viewport) {
|
|
315
|
+
if (element.scrollBy) {
|
|
316
|
+
const purpose = fitsViewport(element, viewport) ? 'centre it' : 'bring it into view';
|
|
317
|
+
return scrollAdvice(element.scrollBy, purpose);
|
|
318
|
+
}
|
|
319
|
+
return element.offScreenReason && `off-screen: ${element.offScreenReason}`;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* How to see all of an element that is partly in view, in words.
|
|
323
|
+
*
|
|
324
|
+
* @param element - Element layout
|
|
325
|
+
* @param viewport - Viewport size (for an element larger than it, the scroll shows its start)
|
|
326
|
+
* @returns e.g. "scroll down 302px to see all of it", "sticky position, page scroll moves it
|
|
327
|
+
* only until it sticks"; undefined when neither applies
|
|
328
|
+
*/
|
|
329
|
+
function partlyVisibleNote(element, viewport) {
|
|
330
|
+
if (element.scrollBy) {
|
|
331
|
+
const purpose = fitsViewport(element, viewport) ? 'see all of it' : 'show it from its start';
|
|
332
|
+
return scrollAdvice(element.scrollBy, purpose);
|
|
333
|
+
}
|
|
334
|
+
return element.offScreenReason;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Where an element is relative to the viewport, for `bdg dom layout`.
|
|
338
|
+
*
|
|
339
|
+
* @param element - Element layout
|
|
340
|
+
* @param viewport - Viewport size, when known
|
|
341
|
+
* @returns e.g. "visible", "partly visible (40%); scroll down 302px to see all of it",
|
|
342
|
+
* "below fold (scroll down 760px to centre it)",
|
|
343
|
+
* "out of view in ul#list (below)", "hidden (display: none)",
|
|
344
|
+
* "left of viewport (off-screen: beyond the page's scroll range)",
|
|
345
|
+
* "below fold; page scrolling is locked (overflow: hidden on body), likely by dialog div#consent"
|
|
346
|
+
*/
|
|
347
|
+
export function layoutPositionLabel(element, viewport) {
|
|
348
|
+
const { inViewport, percentVisible, hiddenReason, clippedBy, offScreenReason } = element;
|
|
349
|
+
if (inViewport === 'visible')
|
|
350
|
+
return 'visible';
|
|
351
|
+
const locked = !element.scrollBy && offScreenReason?.startsWith(SCROLL_LOCKED_PREFIX);
|
|
352
|
+
if (inViewport === 'partly') {
|
|
353
|
+
const clipped = clippedBy ? `, clipped by ${clippedBy}` : '';
|
|
354
|
+
const label = `partly visible (${percentVisible ?? 0}%${clipped})`;
|
|
355
|
+
const note = partlyVisibleNote(element, viewport);
|
|
356
|
+
return note ? `${label}; ${note}` : label;
|
|
357
|
+
}
|
|
358
|
+
const note = locked ? undefined : layoutScrollNote(element, viewport);
|
|
359
|
+
const label = viewportPositionHint(inViewport, clippedBy) ?? inViewport;
|
|
360
|
+
if (hiddenReason)
|
|
361
|
+
return `${label} (${hiddenReason})`;
|
|
362
|
+
if (clippedBy)
|
|
363
|
+
return `${label} (${inViewport})`;
|
|
364
|
+
if (locked)
|
|
365
|
+
return `${label}; ${offScreenReason}`;
|
|
366
|
+
return note ? `${label} (${note})` : label;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* The `prefers-color-scheme` media feature the page sees, labelled as the
|
|
370
|
+
* preference it is (the page may still render its own theme), and where it
|
|
371
|
+
* comes from.
|
|
372
|
+
*
|
|
373
|
+
* @param scheme - Light or dark
|
|
374
|
+
* @param emulated - Set with `--color-scheme` or `page emulate` (otherwise the system setting)
|
|
375
|
+
* @returns e.g. `prefers-color-scheme: dark (from the system setting)`
|
|
376
|
+
*/
|
|
377
|
+
export function colorSchemeLabel(scheme, emulated) {
|
|
378
|
+
const source = emulated ? 'emulated' : 'from the system setting';
|
|
379
|
+
return `prefers-color-scheme: ${scheme} (${source})`;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* First line of `bdg status` for a running session.
|
|
383
|
+
*
|
|
384
|
+
* @param page - URL and title of the page, when the session reported them
|
|
385
|
+
* @returns e.g. `Session active: https://example.com/ — Example Domain`
|
|
386
|
+
*/
|
|
387
|
+
export function sessionActiveLine(page) {
|
|
388
|
+
if (!page)
|
|
389
|
+
return 'Session active';
|
|
390
|
+
return `Session active: ${page.url}${page.title ? ` — ${page.title}` : ''}`;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Page dimensions line of `bdg dom layout`.
|
|
394
|
+
*
|
|
395
|
+
* @param page - Viewport, scroll position, document size and the color scheme the page is told to prefer
|
|
396
|
+
* @returns e.g. "Page: viewport 1280×720, scrolled to 0,0, document 1280×2400, prefers-color-scheme: dark"
|
|
397
|
+
*/
|
|
398
|
+
export function pageLayoutLine(page) {
|
|
399
|
+
const { viewport, scroll, document, colorScheme } = page;
|
|
400
|
+
const scheme = colorScheme ? `, prefers-color-scheme: ${colorScheme}` : '';
|
|
401
|
+
return `Page: viewport ${viewport.width}×${viewport.height}, scrolled to ${scroll.x},${scroll.y}, document ${document.width}×${document.height}${scheme}`;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Headline of `bdg dom layout`.
|
|
405
|
+
*
|
|
406
|
+
* @param count - Elements matched
|
|
407
|
+
* @param listed - Elements reported (fewer with --index)
|
|
408
|
+
* @param selector - Selector they matched
|
|
409
|
+
* @returns e.g. '3 elements match "button" (page x,y and size in CSS px):',
|
|
410
|
+
* '1 of 3 elements matching "button" (...)'
|
|
411
|
+
*/
|
|
412
|
+
export function layoutHeadline(count, listed, selector) {
|
|
413
|
+
const matched = listed < count
|
|
414
|
+
? `${listed} of ${count} elements matching "${selector}"`
|
|
415
|
+
: `${count} element${count === 1 ? ' matches' : 's match'} "${selector}"`;
|
|
416
|
+
return `${matched} (page x,y and size in CSS px):`;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Headline of `bdg dom layout` for a cached index.
|
|
420
|
+
*
|
|
421
|
+
* @param target - The index and the list it refers to, in words
|
|
422
|
+
* @returns e.g. `Element at index 0 of the last dom query "h3" (page x,y and size in CSS px):`
|
|
423
|
+
*/
|
|
424
|
+
export function indexLayoutHeadline(target) {
|
|
425
|
+
return `Element at ${target} (page x,y and size in CSS px):`;
|
|
426
|
+
}
|
|
427
|
+
/** Help text explaining `bdg dom inspect`'s output notation */
|
|
428
|
+
export const INSPECT_OUTPUT_LEGEND = `
|
|
429
|
+
Output notation:
|
|
430
|
+
WxH @x,y rendered border box size and page position (CSS px, no unit)
|
|
431
|
+
m / p / b margin / padding / border widths, 1-4 values in CSS order (top right bottom left)
|
|
432
|
+
in-parent distances to the parent's content edges (l t r b); sib: gaps to the sibling on each side
|
|
433
|
+
scroll WxH the content (pseudo-elements too) is larger than the box
|
|
434
|
+
16/24 font size / line height; 'webfont loaded' = drawn with a downloaded font;
|
|
435
|
+
(rendered "X") = drawn with another font than declared (a fallback)
|
|
436
|
+
contrast 4.47 WCAG ratio, rounded down, against the background behind the text
|
|
437
|
+
(+N not rendered) children with display: none (or not in the layout)
|
|
438
|
+
hints declarations on this element that have no effect, why, the fix and where they are
|
|
439
|
+
('none': checked, nothing found)
|
|
440
|
+
← sel (file:N) --rules: the declaration that sets the value (file:line, or file:line:column in
|
|
441
|
+
minified files); 'over X': rules it beats; '= v': the value of a var() expression
|
|
442
|
+
✓ / ✗ --why: the winning declaration / ones it beats, highest precedence first;
|
|
443
|
+
[0,2,0]: selector specificity (ids, classes, types); indented --name lines: where
|
|
444
|
+
the winner's custom properties are set
|
|
445
|
+
Sessions follow the system color scheme; start with --color-scheme light|dark to choose.`;
|
|
446
|
+
/**
|
|
447
|
+
* What covers an element: a cover that paints nothing at that point (a
|
|
448
|
+
* transparent box over it) does not hide it, but takes its clicks.
|
|
449
|
+
*
|
|
450
|
+
* @param cover - Description of the covering element
|
|
451
|
+
* @param transparent - The cover paints nothing there
|
|
452
|
+
* @returns e.g. `covered by div#modal`, `under transparent ul.filters (clicks land on it)`
|
|
453
|
+
*/
|
|
454
|
+
export function coverText(cover, transparent) {
|
|
455
|
+
return transparent ? `under transparent ${cover} (clicks land on it)` : `covered by ${cover}`;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Note when `bdg dom inspect` could not read the element's matched rules, so
|
|
459
|
+
* no hints, rules or why were computed.
|
|
460
|
+
*
|
|
461
|
+
* @param reason - `timeout` (very large stylesheets) or `failed` (Chrome reported an error)
|
|
462
|
+
* @returns Note
|
|
41
463
|
*/
|
|
42
|
-
export function
|
|
43
|
-
return
|
|
464
|
+
export function inspectCascadeNote(reason) {
|
|
465
|
+
return reason === 'timeout'
|
|
466
|
+
? "CSS rules not read: the page's stylesheets took too long (hints wait 1 s; --rules and --why 5 s)"
|
|
467
|
+
: 'CSS rules not read: Chrome could not report the rules matching this element';
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Header badge of `bdg dom inspect` when the page is shown in its dark theme
|
|
471
|
+
* because the session follows the system's dark preference: the colors are
|
|
472
|
+
* the dark theme's, not what a light-mode visitor sees.
|
|
473
|
+
*
|
|
474
|
+
* @returns Badge
|
|
475
|
+
*/
|
|
476
|
+
export function inspectDarkThemeBadge() {
|
|
477
|
+
return '[dark theme from system; --color-scheme light for light]';
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Header badges of `bdg dom inspect` for what keeps an element from being seen.
|
|
481
|
+
*
|
|
482
|
+
* @param visibility - Not rendered, hidden, offscreen, covered
|
|
483
|
+
* @returns e.g. `[not rendered: display: none]`, `[offscreen: below]`, `[covered by div#modal]`
|
|
484
|
+
*/
|
|
485
|
+
export function inspectVisibilityBadges(visibility) {
|
|
486
|
+
const reason = (text) => (text ? `: ${text}` : '');
|
|
487
|
+
if (visibility.notRendered) {
|
|
488
|
+
return [`[not rendered${reason(visibility.hidden?.replace(/^not rendered \((.*)\)$/, '$1'))}]`];
|
|
489
|
+
}
|
|
490
|
+
return [
|
|
491
|
+
visibility.hidden && `[hidden: ${visibility.hidden}]`,
|
|
492
|
+
visibility.offscreen && `[offscreen: ${visibility.offscreen}]`,
|
|
493
|
+
visibility.coveredBy && `[${coverText(visibility.coveredBy, visibility.coverTransparent)}]`,
|
|
494
|
+
].filter((badge) => Boolean(badge));
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* What `bdg dom inspect` did when several elements matched and no --index was given.
|
|
498
|
+
*
|
|
499
|
+
* @param picked - How the match was chosen
|
|
500
|
+
* @param index - Index of the inspected match
|
|
501
|
+
* @returns e.g. "inspected the first visible one ([2])"
|
|
502
|
+
*/
|
|
503
|
+
export function inspectedMatchAction(picked, index) {
|
|
504
|
+
return picked === 'first-visible'
|
|
505
|
+
? `inspected the first visible one ([${index}])`
|
|
506
|
+
: 'inspected the first';
|
|
44
507
|
}
|
|
45
508
|
/**
|
|
46
509
|
* Warning when a selector matched several elements and no --index was given.
|
|
@@ -53,14 +516,55 @@ export function multipleMatchesWarning(count, action) {
|
|
|
53
516
|
return `${count} elements match; ${action} (use --index or a more specific selector)`;
|
|
54
517
|
}
|
|
55
518
|
/**
|
|
56
|
-
* Headline of `bdg dom listeners
|
|
519
|
+
* Headline of `bdg dom listeners`, saying where the counted listeners are:
|
|
520
|
+
* the list covers the element, its ancestors, its document and window.
|
|
57
521
|
*
|
|
58
522
|
* @param element - Inspected element, e.g. "button#save"
|
|
59
|
-
* @param
|
|
60
|
-
* @
|
|
523
|
+
* @param counts - Listeners found, by placement
|
|
524
|
+
* @param context - Index of the element and the iframe it is in, if any
|
|
525
|
+
* @returns e.g. "Event listeners for button#save (156: 3 on the element, 120 on ancestors, 33 on document and window)"
|
|
61
526
|
*/
|
|
62
|
-
export function listenersHeadline(element,
|
|
63
|
-
|
|
527
|
+
export function listenersHeadline(element, counts, context = {}) {
|
|
528
|
+
const index = context.index === undefined ? '' : ` [${context.index}]`;
|
|
529
|
+
const frame = context.frame ? ` in ${context.frame}` : '';
|
|
530
|
+
const total = counts.target + counts.ancestor + counts.global;
|
|
531
|
+
const where = [
|
|
532
|
+
counts.target > 0 && `${counts.target} on the element`,
|
|
533
|
+
counts.ancestor > 0 && `${counts.ancestor} on ancestors`,
|
|
534
|
+
counts.global > 0 && `${counts.global} on document and window`,
|
|
535
|
+
].filter(Boolean);
|
|
536
|
+
return `Event listeners for ${element}${index}${frame} (${total}: ${where.join(', ')})`;
|
|
537
|
+
}
|
|
538
|
+
/** Heading of the collapsed framework root listeners */
|
|
539
|
+
export const COLLAPSED_LISTENERS_HEADING = 'Framework roots (one line per node; --all lists each listener):';
|
|
540
|
+
/**
|
|
541
|
+
* One collapsed framework root.
|
|
542
|
+
*
|
|
543
|
+
* @param root - Framework label, event types, phases and dispatcher names
|
|
544
|
+
* @returns e.g. "React root: 90 event types, capture and bubble (dispatchEvent, …)"
|
|
545
|
+
*/
|
|
546
|
+
export function collapsedListenersSummary(root) {
|
|
547
|
+
const phases = [root.capture && 'capture', root.bubble && 'bubble'].filter(Boolean).join(' and ');
|
|
548
|
+
const label = root.framework ?? 'Dispatcher';
|
|
549
|
+
return `${label}: ${root.types.length} event types, ${phases} (${root.handlers.join(', ')})`;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* jQuery handlers left unresolved because there were too many.
|
|
553
|
+
*
|
|
554
|
+
* @param count - Handlers not resolved
|
|
555
|
+
* @returns One-line note
|
|
556
|
+
*/
|
|
557
|
+
export function jqueryHandlersSkippedNote(count) {
|
|
558
|
+
return `Note: ${count} more jQuery handler${count === 1 ? '' : 's'} not resolved; their jQuery dispatcher is listed instead (narrow down with --type)`;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Event types a mistyped `--type` probably meant.
|
|
562
|
+
*
|
|
563
|
+
* @param types - Suggested types
|
|
564
|
+
* @returns e.g. "Did you mean: --type click?"
|
|
565
|
+
*/
|
|
566
|
+
export function eventTypeSuggestion(types) {
|
|
567
|
+
return `Did you mean: --type ${types.join(',')}? (event types are case-sensitive, without "on")`;
|
|
64
568
|
}
|
|
65
569
|
/**
|
|
66
570
|
* `bdg dom listeners` found nothing.
|
|
@@ -75,14 +579,57 @@ export function noListenersMessage(element, types) {
|
|
|
75
579
|
}
|
|
76
580
|
/** What `bdg dom listeners` covers, shown when it found nothing */
|
|
77
581
|
export const NO_LISTENERS_HINT = 'Inline on… attributes and on… properties are included, and so are handlers frameworks delegate to ancestors (React, jQuery)';
|
|
582
|
+
/** Event types named in a note; the rest are counted */
|
|
583
|
+
const NOTE_TYPES_SHOWN = 5;
|
|
584
|
+
/**
|
|
585
|
+
* "click", "click and keydown", "click, keydown and input", "a, b, c, d, e
|
|
586
|
+
* and 3 more".
|
|
587
|
+
*
|
|
588
|
+
* @param types - Event types
|
|
589
|
+
* @returns The types as a list in prose
|
|
590
|
+
*/
|
|
591
|
+
function typeList(types) {
|
|
592
|
+
if (types.length > NOTE_TYPES_SHOWN + 1) {
|
|
593
|
+
return `${types.slice(0, NOTE_TYPES_SHOWN).join(', ')} and ${types.length - NOTE_TYPES_SHOWN} more`;
|
|
594
|
+
}
|
|
595
|
+
return types.length > 1
|
|
596
|
+
? `${types.slice(0, -1).join(', ')} and ${types[types.length - 1]}`
|
|
597
|
+
: (types[0] ?? '');
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Note for interaction event types the element has no listener of its own for.
|
|
601
|
+
*
|
|
602
|
+
* @param note - How the types reach their handlers
|
|
603
|
+
* @returns One-line note, or undefined when the listed handlers say it all
|
|
604
|
+
*/
|
|
605
|
+
export function delegationNote(note) {
|
|
606
|
+
const types = typeList(note.types);
|
|
607
|
+
const has = note.types.length === 1 ? 'has' : 'have';
|
|
608
|
+
const placeholders = typeList(note.placeholderTypes);
|
|
609
|
+
const placeholder = `the element's own ${placeholders} listener is only React's no-op placeholder`;
|
|
610
|
+
switch (note.kind) {
|
|
611
|
+
case 'react':
|
|
612
|
+
if (note.placeholderTypes.length === 0)
|
|
613
|
+
return undefined;
|
|
614
|
+
return `Note: ${placeholder}; the React on… handlers listed above for ${placeholders} run from React's root container`;
|
|
615
|
+
case 'react-root':
|
|
616
|
+
return `Note: React's root container (${note.node ?? 'its root'}) handles ${types}, but no React on… prop for ${note.types.length === 1 ? 'it' : 'them'} was found on the element or its ancestors${note.placeholderTypes.length > 0 ? `; ${placeholder}` : ''}`;
|
|
617
|
+
case 'jquery':
|
|
618
|
+
return `Note: ${types} ${has} no listener on the element itself; jQuery runs the handlers listed above by delegation from ${note.node ?? 'an ancestor'}`;
|
|
619
|
+
case 'delegated': {
|
|
620
|
+
const own = note.placeholderTypes.length > 0 ? 'no listener that does anything' : 'no listener';
|
|
621
|
+
return `Note: ${types} ${has} ${own} on the element itself; the listeners on its ancestors, document or window listed above still run for it (event delegation)`;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
78
625
|
/**
|
|
79
|
-
*
|
|
626
|
+
* React prop handlers left unresolved because there were too many.
|
|
80
627
|
*
|
|
81
|
-
* @param
|
|
628
|
+
* @param count - Handlers not resolved
|
|
82
629
|
* @returns One-line note
|
|
83
630
|
*/
|
|
84
|
-
export function
|
|
85
|
-
return `Note: ${
|
|
631
|
+
export function reactHandlersSkippedNote(count) {
|
|
632
|
+
return `Note: ${count} more React handler prop${count === 1 ? '' : 's'} not listed (narrow down with --type)`;
|
|
86
633
|
}
|
|
87
634
|
/**
|
|
88
635
|
* A JavaScript dialog bdg accepted, as one line.
|
|
@@ -101,6 +648,13 @@ export const POINTER_ACTION_DONE = {
|
|
|
101
648
|
right: 'Right-clicked',
|
|
102
649
|
hover: 'Hovered',
|
|
103
650
|
};
|
|
651
|
+
/** What each pointer action is called in notes ("when the click returned") */
|
|
652
|
+
export const POINTER_ACTION_NOUN = {
|
|
653
|
+
click: 'click',
|
|
654
|
+
double: 'double-click',
|
|
655
|
+
right: 'right-click',
|
|
656
|
+
hover: 'hover',
|
|
657
|
+
};
|
|
104
658
|
/** Headline of each `bdg page` action */
|
|
105
659
|
export const PAGE_ACTION_DONE = {
|
|
106
660
|
navigate: 'Navigated',
|
|
@@ -108,6 +662,10 @@ export const PAGE_ACTION_DONE = {
|
|
|
108
662
|
back: 'Went back',
|
|
109
663
|
forward: 'Went forward',
|
|
110
664
|
};
|
|
665
|
+
/** Description of `bdg page info` */
|
|
666
|
+
export const PAGE_INFO_DESCRIPTION = 'Show the URL and title of the session page';
|
|
667
|
+
/** Description of `bdg page emulate` */
|
|
668
|
+
export const PAGE_EMULATE_DESCRIPTION = 'Change the viewport or color scheme mid-session (like --viewport and --color-scheme at start), or --reset both';
|
|
111
669
|
/** Help text of the `bdg page` history commands */
|
|
112
670
|
export const PAGE_ACTION_DESCRIPTIONS = {
|
|
113
671
|
reload: 'Reload the page',
|
|
@@ -115,13 +673,21 @@ export const PAGE_ACTION_DESCRIPTIONS = {
|
|
|
115
673
|
forward: 'Go forward one page (like the browser button)',
|
|
116
674
|
};
|
|
117
675
|
/**
|
|
118
|
-
* `bdg page navigate`
|
|
676
|
+
* `bdg page navigate|reload|back|forward` when the document answered with an
|
|
677
|
+
* error status, or the page then loaded another document that answered
|
|
678
|
+
* differently (a 404 page whose script loads the app).
|
|
119
679
|
*
|
|
120
|
-
* @param status - HTTP status
|
|
121
|
-
* @
|
|
680
|
+
* @param status - HTTP status of the navigation's document
|
|
681
|
+
* @param later - The last document the page loaded afterwards, if any
|
|
682
|
+
* @returns Warning, or undefined when there is nothing to report
|
|
122
683
|
*/
|
|
123
|
-
export function
|
|
124
|
-
|
|
684
|
+
export function documentStatusWarning(status, later) {
|
|
685
|
+
const failed = status >= 400;
|
|
686
|
+
const laterFailed = later !== undefined && later.status >= 400;
|
|
687
|
+
if (later && (failed || laterFailed)) {
|
|
688
|
+
return `The page responded with HTTP ${status}, then loaded ${later.url} (HTTP ${later.status})`;
|
|
689
|
+
}
|
|
690
|
+
return failed ? `The page responded with HTTP ${status}` : undefined;
|
|
125
691
|
}
|
|
126
692
|
/**
|
|
127
693
|
* `bdg page navigate` to a URL that loaded no page.
|
|
@@ -138,7 +704,118 @@ export function notAPageWarning() {
|
|
|
138
704
|
* @returns Warning
|
|
139
705
|
*/
|
|
140
706
|
export function stillLoadingWarning(ms) {
|
|
141
|
-
return `The new page has not answered within ${Math.round(ms / 1000)}s; it is still loading (check with bdg status)`;
|
|
707
|
+
return `The new page has not answered within ${Math.round(ms / 1000)}s; it is still loading (check with ${sessionCommand('bdg status')})`;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* A request the page is still waiting for.
|
|
711
|
+
*
|
|
712
|
+
* @param request - Pending request
|
|
713
|
+
* @returns e.g. `GET code.jquery.com/ui/.../jquery-ui.js (pending 30s)`
|
|
714
|
+
*/
|
|
715
|
+
function pendingRequestLabel(request) {
|
|
716
|
+
return `${request.method} ${truncateUrl(request.url)} (pending ${formatDuration(request.pendingMs)})`;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Requests still running, the longest-running first, in words.
|
|
720
|
+
*
|
|
721
|
+
* @param pending - The requests to name
|
|
722
|
+
* @param count - All requests still running
|
|
723
|
+
* @returns e.g. `GET …/app.js (pending 30s) and 2 more`
|
|
724
|
+
*/
|
|
725
|
+
export function pendingRequestsText(pending, count) {
|
|
726
|
+
const more = count - pending.length;
|
|
727
|
+
return `${pending.map(pendingRequestLabel).join(', ')}${more > 0 ? ` and ${more} more` : ''}`;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* How far a page request got, in words.
|
|
731
|
+
*
|
|
732
|
+
* @param request - The page request
|
|
733
|
+
* @returns e.g. `POST …/authenticate pending for 30s`, `POST …/authenticate returned 503 Service Unavailable`,
|
|
734
|
+
* `POST …/authenticate failed (net::ERR_CONNECTION_REFUSED)`
|
|
735
|
+
*/
|
|
736
|
+
export function documentRequestText(request) {
|
|
737
|
+
const target = `${request.method} ${truncateUrl(request.url)}`;
|
|
738
|
+
if (request.errorText !== undefined)
|
|
739
|
+
return `${target} failed (${request.errorText})`;
|
|
740
|
+
if (request.status !== undefined) {
|
|
741
|
+
return `${target} returned ${request.status}${request.statusText ? ` ${request.statusText}` : ''}`;
|
|
742
|
+
}
|
|
743
|
+
return `${target} pending for ${formatDuration(request.pendingMs ?? 0)}`;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Start and `bdg page` when the document has not finished loading within
|
|
747
|
+
* the readiness wait: its readyState and the requests it is waiting on.
|
|
748
|
+
*
|
|
749
|
+
* @param state - Loading state of the page
|
|
750
|
+
* @returns Warning, e.g. `The page is still loading (document.readyState: loading); waiting on: GET …/jquery-ui.js (pending 30s)`
|
|
751
|
+
*/
|
|
752
|
+
export function pageLoadingWarning(state) {
|
|
753
|
+
const waitingOn = state.pending.length > 0
|
|
754
|
+
? `; waiting on: ${pendingRequestsText(state.pending, state.pendingCount)}`
|
|
755
|
+
: '';
|
|
756
|
+
return `The page is still loading (document.readyState: ${state.readyState})${waitingOn}. Elements may be missing until it finishes: ${sessionCommand('bdg dom wait <selector>')} waits for one`;
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Help of `dom click`/`submit`: they wait for the network only, so results a
|
|
760
|
+
* page shows later (timers, spinners, animations) are waited for with `dom wait`.
|
|
761
|
+
*/
|
|
762
|
+
export const CLICK_RESULT_WAIT_HELP = joinLines('', 'Waits only for the requests the action starts (150 ms idle, up to 2 s), not for', 'results the page shows later (timers, spinners, animations); the result says', '"page still changing" when it saw such work pending. Wait for those with:', " bdg dom wait '#result' --visible # or --text 'Saved', or '.spinner' --gone");
|
|
763
|
+
/** Examples in the help of `bdg dom wait` */
|
|
764
|
+
export const WAIT_HELP_EXAMPLES = joinLines('', 'Examples:', " bdg dom wait '#finish' --visible # timer-based loading (a spinner, then the result)", " bdg dom wait '.toast' --text 'Saved' # a match containing the text", " bdg dom wait '#loading' --gone # the spinner went away", ' bdg dom wait --load # the page finished loading');
|
|
765
|
+
/**
|
|
766
|
+
* The elements `bdg dom wait` waits for.
|
|
767
|
+
*
|
|
768
|
+
* @param condition - What is waited for
|
|
769
|
+
* @returns e.g. `#finish with text "hello world"`
|
|
770
|
+
*/
|
|
771
|
+
export function waitTargetLabel(condition) {
|
|
772
|
+
const text = condition.text !== undefined ? ` with text "${condition.text}"` : '';
|
|
773
|
+
return `${condition.selector ?? 'the page'}${text}`;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* One-line result of `bdg dom wait`.
|
|
777
|
+
*
|
|
778
|
+
* @param condition - What was waited for
|
|
779
|
+
* @param elapsedMs - How long it took
|
|
780
|
+
* @returns e.g. `✓ div#finish visible after 5.1s`
|
|
781
|
+
*/
|
|
782
|
+
export function waitMetMessage(condition, elapsedMs) {
|
|
783
|
+
const after = `after ${(elapsedMs / 1000).toFixed(1)}s`;
|
|
784
|
+
if (condition.selector === undefined)
|
|
785
|
+
return `✓ Page loaded ${after}`;
|
|
786
|
+
const state = condition.gone
|
|
787
|
+
? condition.visible
|
|
788
|
+
? 'hidden'
|
|
789
|
+
: 'gone'
|
|
790
|
+
: condition.visible
|
|
791
|
+
? 'visible'
|
|
792
|
+
: 'found';
|
|
793
|
+
const loaded = condition.load ? ' and page loaded' : '';
|
|
794
|
+
return `✓ ${waitTargetLabel(condition)} ${state}${loaded} ${after}`;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* What the page showed, for a `bdg dom wait` that timed out.
|
|
798
|
+
*
|
|
799
|
+
* @param snapshot - Last thing the page reported
|
|
800
|
+
* @param condition - What was waited for
|
|
801
|
+
* @returns e.g. `2 matches, none visible` or `document.readyState: loading`
|
|
802
|
+
*/
|
|
803
|
+
export function waitSnapshotSummary(snapshot, condition) {
|
|
804
|
+
const some = (count) => (count === 0 ? 'none' : String(count));
|
|
805
|
+
const parts = [];
|
|
806
|
+
if (condition.selector !== undefined) {
|
|
807
|
+
parts.push(snapshot.count === 0 ? 'no matches' : pluralize(snapshot.count, 'match', 'matches'));
|
|
808
|
+
if (condition.text !== undefined && snapshot.count > 0) {
|
|
809
|
+
parts.push(`${some(snapshot.textCount)} with text "${condition.text}"`);
|
|
810
|
+
}
|
|
811
|
+
if (condition.visible && snapshot.textCount > 0) {
|
|
812
|
+
parts.push(`${some(snapshot.visibleCount)} visible`);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (condition.load || snapshot.readyState !== 'complete') {
|
|
816
|
+
parts.push(`document.readyState: ${snapshot.readyState}`);
|
|
817
|
+
}
|
|
818
|
+
return parts.join(', ');
|
|
142
819
|
}
|
|
143
820
|
/**
|
|
144
821
|
* One line describing an iframe: index, URL, name/id, and how it is isolated.
|
|
@@ -152,7 +829,19 @@ export function frameLabel(frame) {
|
|
|
152
829
|
frame.crossOrigin ? 'cross-origin' : 'same-origin',
|
|
153
830
|
frame.outOfProcess && 'out-of-process',
|
|
154
831
|
].filter(Boolean);
|
|
155
|
-
|
|
832
|
+
const label = `[${frame.index}] ${frameUrlLabel(frame.url)}`;
|
|
833
|
+
return [label, ...names, isolation.join(', ')].join(' ');
|
|
834
|
+
}
|
|
835
|
+
/** Longest frame URL shown in human output (JSON has the full URL) */
|
|
836
|
+
const FRAME_URL_MAX_LENGTH = 100;
|
|
837
|
+
/**
|
|
838
|
+
* A frame URL for human output: shortened, and named when empty.
|
|
839
|
+
*
|
|
840
|
+
* @param url - Frame URL
|
|
841
|
+
* @returns e.g. `https://pay.example/checkout?…`, or `(no URL)`
|
|
842
|
+
*/
|
|
843
|
+
export function frameUrlLabel(url) {
|
|
844
|
+
return url ? truncateByLength(url, FRAME_URL_MAX_LENGTH) : '(no URL)';
|
|
156
845
|
}
|
|
157
846
|
/**
|
|
158
847
|
* `bdg dom frames` on a page without iframes.
|
|
@@ -162,6 +851,63 @@ export function frameLabel(frame) {
|
|
|
162
851
|
export function noFramesMessage() {
|
|
163
852
|
return 'The page has no iframes';
|
|
164
853
|
}
|
|
854
|
+
/**
|
|
855
|
+
* `bdg dom frames` while the page is still loading: its iframes may not
|
|
856
|
+
* exist yet.
|
|
857
|
+
*
|
|
858
|
+
* @param empty - No iframe was found
|
|
859
|
+
* @returns e.g. `No iframes yet; the page is still loading, so the list may be incomplete (bdg dom wait --load)`
|
|
860
|
+
*/
|
|
861
|
+
export function framesStillLoadingNote(empty) {
|
|
862
|
+
const wait = `(${sessionCommand('bdg dom wait --load')})`;
|
|
863
|
+
return empty
|
|
864
|
+
? `No iframes yet; the page is still loading, so the list may be incomplete ${wait}`
|
|
865
|
+
: `Note: the page is still loading, so the list may be incomplete ${wait}`;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Text of an element in `bdg dom get` output.
|
|
869
|
+
*
|
|
870
|
+
* @param text - Collapsed text, ending in `...` when it was cut
|
|
871
|
+
* @returns e.g. `Text: Welcome to ... (cut at 500 characters; --full shows all of it)`
|
|
872
|
+
*/
|
|
873
|
+
export function elementTextLine(text) {
|
|
874
|
+
const cut = text.endsWith('...') ? ' (cut at 500 characters; --full shows all of it)' : '';
|
|
875
|
+
return `Text: ${text}${cut}`;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* What an element without text holds, in `bdg dom get` output.
|
|
879
|
+
*
|
|
880
|
+
* @param children - First child elements, e.g. `iframe#app`
|
|
881
|
+
* @param count - Number of child elements
|
|
882
|
+
* @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`
|
|
883
|
+
*/
|
|
884
|
+
export function emptyElementLine(children, count) {
|
|
885
|
+
if (count === 0)
|
|
886
|
+
return 'No text and no child elements';
|
|
887
|
+
const more = count > children.length ? `, … ${count - children.length} more` : '';
|
|
888
|
+
return `No text; holds ${pluralize(count, 'element')}: ${children.join(', ')}${more} (see its HTML with --raw)`;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Note on an element screenshot that captured more than the element's border
|
|
892
|
+
* box, because content (floats, positioned children) overflows it.
|
|
893
|
+
*
|
|
894
|
+
* @param box - Border box
|
|
895
|
+
* @param captured - Area captured
|
|
896
|
+
* @returns e.g. `grown from 940×37 to 940×285 to include content overflowing the element`
|
|
897
|
+
*/
|
|
898
|
+
export function screenshotGrownNote(box, captured) {
|
|
899
|
+
return `grown from ${box.width}×${box.height} to ${captured.width}×${captured.height} to include content overflowing the element`;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Next commands after `bdg dom query`, by index so they reach matches in
|
|
903
|
+
* shadow roots and iframes too.
|
|
904
|
+
*
|
|
905
|
+
* @param index - Match to use in the examples
|
|
906
|
+
* @returns One line
|
|
907
|
+
*/
|
|
908
|
+
export function queryNextSteps(index) {
|
|
909
|
+
return `Next: bdg dom get ${index} (text), bdg dom get ${index} --raw (HTML), bdg dom layout ${index} (position)`;
|
|
910
|
+
}
|
|
165
911
|
/**
|
|
166
912
|
* Header of `bdg dom eval --frame` output naming the frame the script ran in.
|
|
167
913
|
*
|
|
@@ -169,7 +915,7 @@ export function noFramesMessage() {
|
|
|
169
915
|
* @returns e.g. `Frame: https://pay.example/`
|
|
170
916
|
*/
|
|
171
917
|
export function evalFrameLine(url) {
|
|
172
|
-
return `Frame: ${url}`;
|
|
918
|
+
return `Frame: ${frameUrlLabel(url)}`;
|
|
173
919
|
}
|
|
174
920
|
/**
|
|
175
921
|
* Generate warning message.
|
|
@@ -204,6 +950,15 @@ export function sessionOutputRemovedMessage() {
|
|
|
204
950
|
export function sessionDirectoryCleanMessage() {
|
|
205
951
|
return 'Session directory is now clean';
|
|
206
952
|
}
|
|
953
|
+
/**
|
|
954
|
+
* `bdg cleanup --purge` deleted a named session's directory.
|
|
955
|
+
*
|
|
956
|
+
* @param dir - Deleted directory
|
|
957
|
+
* @returns Message
|
|
958
|
+
*/
|
|
959
|
+
export function sessionDirectoryPurgedMessage(dir) {
|
|
960
|
+
return `Session directory removed: ${dir}`;
|
|
961
|
+
}
|
|
207
962
|
/**
|
|
208
963
|
* Generate no session files found message.
|
|
209
964
|
*
|
|
@@ -221,6 +976,15 @@ export function noSessionFilesMessage() {
|
|
|
221
976
|
export function sessionStillActiveError(pid) {
|
|
222
977
|
return `Session is still active (PID ${pid})`;
|
|
223
978
|
}
|
|
979
|
+
/**
|
|
980
|
+
* How to clean up a session that is still running.
|
|
981
|
+
*
|
|
982
|
+
* @param session - Name of a named session, or null for the default session
|
|
983
|
+
* @returns Suggestion lines
|
|
984
|
+
*/
|
|
985
|
+
export function sessionStillActiveSuggestion(session) {
|
|
986
|
+
return `Stop gracefully: ${sessionCommand('bdg stop', session)}\nForce cleanup: ${sessionCommand('bdg cleanup --force', session)}`;
|
|
987
|
+
}
|
|
224
988
|
/**
|
|
225
989
|
* Generate help message when no URL is provided to start command.
|
|
226
990
|
*
|
|
@@ -238,4 +1002,54 @@ export function sessionStillActiveError(pid) {
|
|
|
238
1002
|
export function startCommandHelpMessage() {
|
|
239
1003
|
return joinLines('', buildAgentDiscoveryHelp(), '', buildCommonTaskExamples(), '', buildUrlExamples(), '', buildSessionManagementReminder(), '', 'Not sure which command? Start a session to see all available commands:', ' bdg <url>', '');
|
|
240
1004
|
}
|
|
1005
|
+
/**
|
|
1006
|
+
* `bdg page emulate` without anything to change.
|
|
1007
|
+
*
|
|
1008
|
+
* @returns Message and suggestion
|
|
1009
|
+
*/
|
|
1010
|
+
export function pageEmulateNothingError() {
|
|
1011
|
+
return {
|
|
1012
|
+
message: 'Nothing to emulate',
|
|
1013
|
+
suggestion: 'Give --viewport <WxH>, --color-scheme light|dark, or --reset, e.g. bdg page emulate --viewport 900x700',
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Lines of `bdg page emulate`: what is emulated and what the page now has.
|
|
1018
|
+
*
|
|
1019
|
+
* @param result - Emulation and page appearance
|
|
1020
|
+
* @returns Label/value pairs
|
|
1021
|
+
*/
|
|
1022
|
+
export function pageEmulationLines(result) {
|
|
1023
|
+
const size = (v) => `${v.width}x${v.height}`;
|
|
1024
|
+
const { emulated } = result;
|
|
1025
|
+
return [
|
|
1026
|
+
['Viewport', emulated.viewport ? size(emulated.viewport) : 'the browser window'],
|
|
1027
|
+
...(result.viewport
|
|
1028
|
+
? [['Layout', `${size(result.viewport)} (without scrollbars)`]]
|
|
1029
|
+
: []),
|
|
1030
|
+
[
|
|
1031
|
+
'Scheme',
|
|
1032
|
+
emulated.colorScheme ??
|
|
1033
|
+
`system setting${result.colorScheme ? ` (${result.colorScheme})` : ''}`,
|
|
1034
|
+
],
|
|
1035
|
+
];
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Header badge of `bdg dom inspect` while CSS transitions or animations run
|
|
1039
|
+
* on the element: the values read are mid-way.
|
|
1040
|
+
*
|
|
1041
|
+
* @param animating - Transitioned properties and animation names
|
|
1042
|
+
* @returns e.g. `[animating: background-color; values are mid-way, inspect again]`
|
|
1043
|
+
*/
|
|
1044
|
+
export function inspectAnimatingBadge(animating) {
|
|
1045
|
+
return `[animating: ${animating.join(', ')}; values are mid-way, inspect again]`;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* `--why` note on a computed value read during its transition.
|
|
1049
|
+
*
|
|
1050
|
+
* @returns Note
|
|
1051
|
+
*/
|
|
1052
|
+
export function inspectMidTransitionNote() {
|
|
1053
|
+
return '(mid-transition: inspect again for the final value)';
|
|
1054
|
+
}
|
|
241
1055
|
//# sourceMappingURL=commands.js.map
|