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
|
@@ -14,15 +14,67 @@
|
|
|
14
14
|
* all, not even to `Runtime.terminateExecution`.
|
|
15
15
|
*/
|
|
16
16
|
import { CDPConnection } from '../../connection/cdp.js';
|
|
17
|
+
import type { Protocol } from '../../connection/typed-cdp.js';
|
|
18
|
+
import type { CommandError } from '../../errors/index.js';
|
|
17
19
|
import type { DomEvalData, DomFrame } from '../../ipc/protocol/commands.js';
|
|
20
|
+
import { type CDPSender } from '../../telemetry/objectExpander.js';
|
|
21
|
+
/** The default (main-world) execution context of a frame */
|
|
22
|
+
interface FrameContext {
|
|
23
|
+
/** `ExecutionContextDescription.uniqueId` */
|
|
24
|
+
uniqueId: string;
|
|
25
|
+
/** Origin its scripts run with (`"://"` when opaque) */
|
|
26
|
+
origin: string;
|
|
27
|
+
}
|
|
28
|
+
/** A frame with the session that owns it */
|
|
29
|
+
interface FrameNode {
|
|
30
|
+
frame: Protocol.Page.Frame;
|
|
31
|
+
sessionId?: string;
|
|
32
|
+
context?: FrameContext;
|
|
33
|
+
}
|
|
34
|
+
/** The page's iframes as listed, and the frame id behind each index */
|
|
35
|
+
export interface FrameListing {
|
|
36
|
+
frames: DomFrame[];
|
|
37
|
+
/** Frame id of each listed frame, by index */
|
|
38
|
+
frameIds: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Iframes below the main frame, depth-first, siblings in the document order
|
|
42
|
+
* of their iframe elements (frames without a known place last, in tree order).
|
|
43
|
+
*
|
|
44
|
+
* @param nodes - All frames
|
|
45
|
+
* @param mainFrameId - The page's main frame
|
|
46
|
+
* @param rank - Place of each frame among its siblings, by id
|
|
47
|
+
* @returns Iframes in listing order
|
|
48
|
+
*/
|
|
49
|
+
export declare function iframesInOrder<T extends Pick<FrameNode, 'frame'>>(nodes: T[], mainFrameId: string, rank: Map<string, number>): T[];
|
|
18
50
|
/**
|
|
19
51
|
* List the page's iframes.
|
|
20
52
|
*
|
|
21
53
|
* @param page - The session's connection
|
|
22
54
|
* @param wsUrl - WebSocket URL of the page target
|
|
23
|
-
* @returns Iframes in listing order
|
|
55
|
+
* @returns Iframes in listing order, and the frame id behind each index
|
|
56
|
+
*/
|
|
57
|
+
export declare function listFrames(page: CDPConnection, wsUrl: string): Promise<FrameListing>;
|
|
58
|
+
/** A frame whose script lost its context */
|
|
59
|
+
export interface LostFrame {
|
|
60
|
+
frameId: string;
|
|
61
|
+
/** Session of the parent frame, which owns the iframe element */
|
|
62
|
+
ownerSession?: string;
|
|
63
|
+
/** Frame URL when the script started */
|
|
64
|
+
url: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The error for a script whose frame context went away: the page was
|
|
68
|
+
* closed, the frame navigated (its iframe element is still there) or was
|
|
69
|
+
* removed.
|
|
70
|
+
*
|
|
71
|
+
* @param conn - Connection the frame was found on
|
|
72
|
+
* @param page - The session's connection to the page
|
|
73
|
+
* @param frame - The frame
|
|
74
|
+
* @returns Command error (83)
|
|
75
|
+
* @throws Errors of the checks other than Chrome saying the frame is gone
|
|
24
76
|
*/
|
|
25
|
-
export declare function
|
|
77
|
+
export declare function frameContextLostError(conn: Pick<CDPConnection, 'send'>, page: CDPSender, frame: LostFrame): Promise<CommandError>;
|
|
26
78
|
/**
|
|
27
79
|
* Evaluate a `bdg dom eval` script in one iframe, like {@link evaluateScript}
|
|
28
80
|
* does in the page.
|
|
@@ -30,9 +82,13 @@ export declare function listFrames(page: CDPConnection, wsUrl: string): Promise<
|
|
|
30
82
|
* @param page - The session's connection
|
|
31
83
|
* @param wsUrl - WebSocket URL of the page target
|
|
32
84
|
* @param script - JavaScript expression
|
|
33
|
-
* @param query - Requested frame (index, name/id attribute, or part of the URL)
|
|
85
|
+
* @param query - Requested frame (index, name/id attribute, or part of the name, id or URL)
|
|
86
|
+
* @param listedIds - Frame id behind each index of the last `dom frames` listing, if any
|
|
34
87
|
* @returns Value, type and the frame's URL
|
|
35
|
-
* @throws CommandError (81/83) when the frame is ambiguous or missing,
|
|
88
|
+
* @throws CommandError (81/83) when the frame is ambiguous or missing, (87)
|
|
89
|
+
* when an index names another frame than when it was listed, (83) when it
|
|
90
|
+
* navigated or was removed while the script ran, else as evaluateScript
|
|
36
91
|
*/
|
|
37
|
-
export declare function evaluateInFrame(page: CDPConnection, wsUrl: string, script: string, query: string): Promise<DomEvalData>;
|
|
92
|
+
export declare function evaluateInFrame(page: CDPConnection, wsUrl: string, script: string, query: string, listedIds?: string[]): Promise<DomEvalData>;
|
|
93
|
+
export {};
|
|
38
94
|
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
* all, not even to `Runtime.terminateExecution`.
|
|
15
15
|
*/
|
|
16
16
|
import { CDPConnection } from '../../connection/cdp.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
17
|
+
import { CDPProtocolError } from '../../connection/errors.js';
|
|
18
|
+
import { frameLostDuringEvalError, frameNavigatedDuringEvalError, frameNotReadyError, frameRemovedDuringEvalError, pageClosedDuringEvalError, } from '../../errors/messages.js';
|
|
19
|
+
import { evaluateScript, isContextLostError, pageStillOpen, settledWithin, withBusyPageRecovery, } from './evalHelpers.js';
|
|
20
|
+
import { effectiveFrameOrigin, isCrossOrigin } from './frameOrigin.js';
|
|
21
|
+
import { assertFrameIndexCurrent, frameError, selectFrame } from './frameSelection.js';
|
|
20
22
|
import { attachedSessionOf } from '../../telemetry/attachedTargets.js';
|
|
21
23
|
import { senderFor } from '../../telemetry/objectExpander.js';
|
|
22
24
|
import { createLogger } from '../../ui/logging/index.js';
|
|
@@ -25,6 +27,32 @@ import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
|
25
27
|
const log = createLogger('dom');
|
|
26
28
|
/** Auto-attach without pausing new targets: only existing frames are needed */
|
|
27
29
|
const AUTO_ATTACH = { autoAttach: true, waitForDebuggerOnStart: false, flatten: true };
|
|
30
|
+
/**
|
|
31
|
+
* Page function, called with iframe elements of one document: their
|
|
32
|
+
* indices in document order. Shadow roots are walked through their host
|
|
33
|
+
* (a shadow root's content comes before the host's children, as in
|
|
34
|
+
* shadow-including tree order).
|
|
35
|
+
*/
|
|
36
|
+
const DOCUMENT_ORDER_JS = `function (...nodes) {
|
|
37
|
+
const path = (node) => {
|
|
38
|
+
const nodesUp = [];
|
|
39
|
+
for (let n = node; n; n = n.parentNode || (n.nodeType === 11 ? n.host : null)) nodesUp.unshift(n);
|
|
40
|
+
return nodesUp;
|
|
41
|
+
};
|
|
42
|
+
const paths = nodes.map(path);
|
|
43
|
+
const compare = (i, j) => {
|
|
44
|
+
const a = paths[i];
|
|
45
|
+
const b = paths[j];
|
|
46
|
+
let depth = 0;
|
|
47
|
+
while (depth < a.length && depth < b.length && a[depth] === b[depth]) depth++;
|
|
48
|
+
const x = a[depth];
|
|
49
|
+
const y = b[depth];
|
|
50
|
+
if (!x || !y) return a.length - b.length;
|
|
51
|
+
if (x.nodeType === 11 || y.nodeType === 11) return x.nodeType === 11 ? -1 : 1;
|
|
52
|
+
return x.compareDocumentPosition(y) & 4 ? -1 : 1;
|
|
53
|
+
};
|
|
54
|
+
return nodes.map((_, i) => i).sort(compare);
|
|
55
|
+
}`;
|
|
28
56
|
/**
|
|
29
57
|
* Run `work` on a second connection to the page, closed afterwards.
|
|
30
58
|
*
|
|
@@ -70,18 +98,45 @@ function recoverySender(fc, sessionId) {
|
|
|
70
98
|
*/
|
|
71
99
|
async function sendToSession(fc, method, params, sessionId) {
|
|
72
100
|
const command = fc.conn.send(method, params, sessionId);
|
|
73
|
-
|
|
101
|
+
const scope = sessionId === undefined ? 'page' : 'frame';
|
|
102
|
+
return (await withBusyPageRecovery(recoverySender(fc, sessionId), command, { scope }));
|
|
74
103
|
}
|
|
75
104
|
/**
|
|
76
|
-
*
|
|
105
|
+
* Default execution contexts of a session's frames, reported when Runtime is
|
|
106
|
+
* enabled.
|
|
107
|
+
*
|
|
108
|
+
* @param fc - Frame connection
|
|
109
|
+
* @param sessionId - Session, undefined for the page
|
|
110
|
+
* @returns Context of each frame, by frame id
|
|
111
|
+
*/
|
|
112
|
+
async function defaultContexts(fc, sessionId) {
|
|
113
|
+
const contexts = new Map();
|
|
114
|
+
const stop = fc.conn.on('Runtime.executionContextCreated', ({ context }, eventSession) => {
|
|
115
|
+
const auxData = (context.auxData ?? {});
|
|
116
|
+
const frameId = auxData['frameId'];
|
|
117
|
+
if (eventSession !== sessionId || !auxData['isDefault'] || typeof frameId !== 'string')
|
|
118
|
+
return;
|
|
119
|
+
contexts.set(frameId, { uniqueId: context.uniqueId, origin: context.origin });
|
|
120
|
+
});
|
|
121
|
+
try {
|
|
122
|
+
await sendToSession(fc, 'Runtime.enable', {}, sessionId);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
stop();
|
|
126
|
+
}
|
|
127
|
+
return contexts;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Frame tree of a session and the default contexts of its frames.
|
|
77
131
|
*
|
|
78
132
|
* @param fc - Frame connection
|
|
79
133
|
* @param sessionId - Session, undefined for the page
|
|
80
134
|
* @returns The tree
|
|
81
135
|
*/
|
|
82
|
-
async function
|
|
136
|
+
async function readSession(fc, sessionId) {
|
|
137
|
+
const contexts = await defaultContexts(fc, sessionId);
|
|
83
138
|
const { frameTree: tree } = await sendToSession(fc, 'Page.getFrameTree', {}, sessionId);
|
|
84
|
-
return { tree, ...(sessionId && { sessionId }) };
|
|
139
|
+
return { tree, contexts, ...(sessionId && { sessionId }) };
|
|
85
140
|
}
|
|
86
141
|
/**
|
|
87
142
|
* Attach to the out-of-process iframes directly below a session. Chrome
|
|
@@ -116,38 +171,63 @@ async function attachChildFrames(fc, parentSession) {
|
|
|
116
171
|
*/
|
|
117
172
|
async function outOfProcessTrees(fc, parentSession) {
|
|
118
173
|
const sessions = await attachChildFrames(fc, parentSession);
|
|
119
|
-
const nested = await Promise.all(sessions.map(
|
|
120
|
-
await frameTree(fc, sessionId),
|
|
121
|
-
...(await outOfProcessTrees(fc, sessionId)),
|
|
122
|
-
]));
|
|
174
|
+
const nested = await Promise.all(sessions.map((sessionId) => childSessionTrees(fc, sessionId)));
|
|
123
175
|
return nested.flat();
|
|
124
176
|
}
|
|
125
177
|
/**
|
|
126
|
-
*
|
|
178
|
+
* Trees of an out-of-process iframe and the ones nested in it. A frame
|
|
179
|
+
* removed while the page is being listed (its session is gone) is skipped.
|
|
180
|
+
*
|
|
181
|
+
* @param fc - Frame connection
|
|
182
|
+
* @param sessionId - The iframe's session
|
|
183
|
+
* @returns Its tree and the nested ones, or none when it went away
|
|
184
|
+
*/
|
|
185
|
+
async function childSessionTrees(fc, sessionId) {
|
|
186
|
+
try {
|
|
187
|
+
return [await readSession(fc, sessionId), ...(await outOfProcessTrees(fc, sessionId))];
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
if (!(error instanceof CDPProtocolError))
|
|
191
|
+
throw error;
|
|
192
|
+
log.debug(`Frame session ${sessionId} went away while listing: ${error.message}`);
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* All frames of the trees, each with its session and default context.
|
|
127
198
|
*
|
|
128
199
|
* @param trees - Frame trees
|
|
129
200
|
* @returns Frames in tree order
|
|
130
201
|
*/
|
|
131
202
|
function flattenTrees(trees) {
|
|
132
203
|
const nodes = [];
|
|
133
|
-
const walk = (tree,
|
|
134
|
-
|
|
135
|
-
|
|
204
|
+
const walk = (tree, owner) => {
|
|
205
|
+
const context = owner.contexts.get(tree.frame.id);
|
|
206
|
+
nodes.push({
|
|
207
|
+
frame: tree.frame,
|
|
208
|
+
...(owner.sessionId && { sessionId: owner.sessionId }),
|
|
209
|
+
...(context && { context }),
|
|
210
|
+
});
|
|
211
|
+
tree.childFrames?.forEach((child) => walk(child, owner));
|
|
136
212
|
};
|
|
137
|
-
trees.forEach((
|
|
213
|
+
trees.forEach((owner) => walk(owner.tree, owner));
|
|
138
214
|
return nodes;
|
|
139
215
|
}
|
|
140
216
|
/**
|
|
141
|
-
* Iframes below the main frame, depth-first
|
|
217
|
+
* Iframes below the main frame, depth-first, siblings in the document order
|
|
218
|
+
* of their iframe elements (frames without a known place last, in tree order).
|
|
142
219
|
*
|
|
143
220
|
* @param nodes - All frames
|
|
144
221
|
* @param mainFrameId - The page's main frame
|
|
222
|
+
* @param rank - Place of each frame among its siblings, by id
|
|
145
223
|
* @returns Iframes in listing order
|
|
146
224
|
*/
|
|
147
|
-
function iframesInOrder(nodes, mainFrameId) {
|
|
225
|
+
export function iframesInOrder(nodes, mainFrameId, rank) {
|
|
148
226
|
const ordered = [];
|
|
227
|
+
const place = (node) => rank.get(node.frame.id) ?? Number.MAX_SAFE_INTEGER;
|
|
149
228
|
const visit = (parentId) => {
|
|
150
|
-
|
|
229
|
+
const children = nodes.filter((n) => n.frame.parentId === parentId);
|
|
230
|
+
for (const node of children.sort((a, b) => place(a) - place(b))) {
|
|
151
231
|
ordered.push(node);
|
|
152
232
|
visit(node.frame.id);
|
|
153
233
|
}
|
|
@@ -170,116 +250,275 @@ function attributeValue(attributes = [], key) {
|
|
|
170
250
|
return undefined;
|
|
171
251
|
}
|
|
172
252
|
/**
|
|
173
|
-
*
|
|
253
|
+
* The iframe element of a frame (read in its parent's session).
|
|
174
254
|
*
|
|
175
255
|
* @param fc - Frame connection
|
|
176
256
|
* @param frameId - Frame
|
|
177
257
|
* @param ownerSession - Session of the parent frame
|
|
178
|
-
* @returns `name` and `
|
|
258
|
+
* @returns Its node, and `name`, `id` and `sandbox` attributes when set
|
|
179
259
|
*/
|
|
180
|
-
async function
|
|
260
|
+
async function frameOwner(fc, frameId, ownerSession) {
|
|
181
261
|
try {
|
|
182
262
|
const { backendNodeId } = await sendToSession(fc, 'DOM.getFrameOwner', { frameId }, ownerSession);
|
|
183
263
|
const { node } = await sendToSession(fc, 'DOM.describeNode', { backendNodeId }, ownerSession);
|
|
184
264
|
const name = attributeValue(node.attributes, 'name');
|
|
185
265
|
const id = attributeValue(node.attributes, 'id');
|
|
186
|
-
|
|
266
|
+
const sandbox = attributeValue(node.attributes, 'sandbox');
|
|
267
|
+
return {
|
|
268
|
+
backendNodeId,
|
|
269
|
+
...(name && { name }),
|
|
270
|
+
...(id && { id }),
|
|
271
|
+
...(sandbox !== undefined && { sandbox }),
|
|
272
|
+
};
|
|
187
273
|
}
|
|
188
274
|
catch (error) {
|
|
189
275
|
log.debug(`No iframe element for frame ${frameId}: ${getErrorMessage(error)}`);
|
|
190
276
|
return {};
|
|
191
277
|
}
|
|
192
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Where a frame sits in the listing: its origin, and the index of its parent.
|
|
281
|
+
* Parents are placed before their children, so a child can inherit its
|
|
282
|
+
* parent's origin.
|
|
283
|
+
*
|
|
284
|
+
* @param node - The frame
|
|
285
|
+
* @param index - Its position
|
|
286
|
+
* @param owner - Attributes of its iframe element
|
|
287
|
+
* @param state - Frames placed so far (updated)
|
|
288
|
+
* @returns Origin and parent index
|
|
289
|
+
*/
|
|
290
|
+
function placeFrame(node, index, owner, state) {
|
|
291
|
+
const { frame, context } = node;
|
|
292
|
+
const parentId = frame.parentId ?? '';
|
|
293
|
+
const origin = effectiveFrameOrigin({
|
|
294
|
+
url: frame.url,
|
|
295
|
+
securityOrigin: frame.securityOrigin,
|
|
296
|
+
contextOrigin: context?.origin,
|
|
297
|
+
parentOrigin: state.originOf.get(parentId),
|
|
298
|
+
sandbox: owner.sandbox,
|
|
299
|
+
});
|
|
300
|
+
const parentIndex = state.indexOf.get(parentId);
|
|
301
|
+
state.originOf.set(frame.id, origin);
|
|
302
|
+
state.indexOf.set(frame.id, index);
|
|
303
|
+
return { origin, ...(parentIndex !== undefined && { parentIndex }) };
|
|
304
|
+
}
|
|
193
305
|
/**
|
|
194
306
|
* Describe an iframe for listing. Chrome names a frame after its element's
|
|
195
307
|
* `id` when it has no `name`, so such a name is not repeated.
|
|
196
308
|
*
|
|
197
|
-
* @param fc - Frame connection
|
|
198
309
|
* @param node - The frame
|
|
199
310
|
* @param index - Its position
|
|
200
|
-
* @param
|
|
311
|
+
* @param owner - Attributes of its iframe element
|
|
312
|
+
* @param state - Frames described so far (updated)
|
|
201
313
|
* @returns The located frame
|
|
202
314
|
*/
|
|
203
|
-
|
|
204
|
-
const { frame, sessionId } = node;
|
|
205
|
-
const owner = await ownerAttributes(fc, frame.id, context.sessionOf.get(frame.parentId ?? ''));
|
|
315
|
+
function describeFrame(node, index, owner, state) {
|
|
316
|
+
const { frame, sessionId, context } = node;
|
|
206
317
|
const name = owner.name ?? (frame.name === owner.id ? undefined : frame.name);
|
|
318
|
+
const { origin, parentIndex } = placeFrame(node, index, owner, state);
|
|
207
319
|
const info = {
|
|
208
320
|
index,
|
|
209
321
|
url: frame.url + (frame.urlFragment ?? ''),
|
|
210
322
|
...(name && { name }),
|
|
211
323
|
...(owner.id && { id: owner.id }),
|
|
212
|
-
origin
|
|
213
|
-
crossOrigin:
|
|
324
|
+
origin,
|
|
325
|
+
crossOrigin: isCrossOrigin(origin, state.topOrigin),
|
|
214
326
|
outOfProcess: sessionId !== undefined,
|
|
327
|
+
...(parentIndex !== undefined && { parentIndex }),
|
|
328
|
+
};
|
|
329
|
+
const ownerSession = state.sessionOf.get(frame.parentId ?? '');
|
|
330
|
+
return {
|
|
331
|
+
info,
|
|
332
|
+
frameId: frame.id,
|
|
333
|
+
...(sessionId && { sessionId }),
|
|
334
|
+
...(ownerSession && { ownerSession }),
|
|
335
|
+
...(context && { context }),
|
|
215
336
|
};
|
|
216
|
-
return { info, frameId: frame.id, ...(sessionId && { sessionId }) };
|
|
217
337
|
}
|
|
218
338
|
/**
|
|
219
|
-
*
|
|
339
|
+
* The listing state before the first iframe: the page's own origin.
|
|
340
|
+
*
|
|
341
|
+
* @param page - The page's session tree
|
|
342
|
+
* @param sessionOf - Session of each frame
|
|
343
|
+
* @returns Initial state
|
|
344
|
+
*/
|
|
345
|
+
function initialListingState(page, sessionOf) {
|
|
346
|
+
const top = page.tree.frame;
|
|
347
|
+
const topOrigin = effectiveFrameOrigin({
|
|
348
|
+
url: top.url,
|
|
349
|
+
securityOrigin: top.securityOrigin,
|
|
350
|
+
contextOrigin: page.contexts.get(top.id)?.origin,
|
|
351
|
+
});
|
|
352
|
+
return { topOrigin, originOf: new Map([[top.id, topOrigin]]), indexOf: new Map(), sessionOf };
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Indices of iframe elements of one document, in document order.
|
|
220
356
|
*
|
|
221
357
|
* @param fc - Frame connection
|
|
222
|
-
* @
|
|
358
|
+
* @param backendNodeIds - The iframe elements
|
|
359
|
+
* @param ownerSession - Session of the document
|
|
360
|
+
* @returns Their indices in document order
|
|
361
|
+
* @throws Errors of CDP (e.g. an element removed meanwhile)
|
|
223
362
|
*/
|
|
224
|
-
async function
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
363
|
+
async function documentOrder(fc, backendNodeIds, ownerSession) {
|
|
364
|
+
const objectIds = await Promise.all(backendNodeIds.map(async (backendNodeId) => {
|
|
365
|
+
const { object } = await sendToSession(fc, 'DOM.resolveNode', { backendNodeId }, ownerSession);
|
|
366
|
+
return object.objectId ?? '';
|
|
367
|
+
}));
|
|
368
|
+
const { result } = await sendToSession(fc, 'Runtime.callFunctionOn', {
|
|
369
|
+
objectId: objectIds[0],
|
|
370
|
+
functionDeclaration: DOCUMENT_ORDER_JS,
|
|
371
|
+
arguments: objectIds.map((objectId) => ({ objectId })),
|
|
372
|
+
returnByValue: true,
|
|
373
|
+
}, ownerSession);
|
|
374
|
+
return result.value;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Frames grouped by their parent.
|
|
378
|
+
*
|
|
379
|
+
* @param iframes - Frames
|
|
380
|
+
* @returns Frames of each parent, by parent id
|
|
381
|
+
*/
|
|
382
|
+
function groupByParent(iframes) {
|
|
383
|
+
const byParent = new Map();
|
|
384
|
+
for (const node of iframes) {
|
|
385
|
+
const parentId = node.frame.parentId ?? '';
|
|
386
|
+
byParent.set(parentId, [...(byParent.get(parentId) ?? []), node]);
|
|
387
|
+
}
|
|
388
|
+
return byParent;
|
|
231
389
|
}
|
|
232
390
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
391
|
+
* Place of each frame among its siblings, from the document order of their
|
|
392
|
+
* iframe elements. Chrome's frame tree lists frames in the order they were
|
|
393
|
+
* attached and leaves out-of-process ones to their own sessions, so neither
|
|
394
|
+
* gives a stable order. Siblings that cannot be ordered get no place.
|
|
235
395
|
*
|
|
236
396
|
* @param fc - Frame connection
|
|
237
|
-
* @param
|
|
238
|
-
* @
|
|
239
|
-
* @
|
|
397
|
+
* @param iframes - All iframes
|
|
398
|
+
* @param owners - Iframe element of each frame, by id
|
|
399
|
+
* @param sessionOf - Session of each frame, by id
|
|
400
|
+
* @returns Place of each frame among its siblings, by id
|
|
240
401
|
*/
|
|
241
|
-
async function
|
|
242
|
-
const
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
402
|
+
async function siblingRanks(fc, iframes, owners, sessionOf) {
|
|
403
|
+
const rank = new Map();
|
|
404
|
+
const groups = [...groupByParent(iframes)].map(async ([parentId, siblings]) => {
|
|
405
|
+
const placed = siblings.flatMap((node) => {
|
|
406
|
+
const backendNodeId = owners.get(node.frame.id)?.backendNodeId;
|
|
407
|
+
return backendNodeId === undefined ? [] : [{ id: node.frame.id, backendNodeId }];
|
|
408
|
+
});
|
|
409
|
+
if (placed.length < 2)
|
|
410
|
+
return;
|
|
411
|
+
try {
|
|
412
|
+
const nodeIds = placed.map((item) => item.backendNodeId);
|
|
413
|
+
const order = await documentOrder(fc, nodeIds, sessionOf.get(parentId));
|
|
414
|
+
order.forEach((index, place) => rank.set(placed[index]?.id ?? '', place));
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
log.debug(`Frames of ${parentId} not ordered: ${getErrorMessage(error)}`);
|
|
418
|
+
}
|
|
246
419
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
420
|
+
await Promise.all(groups);
|
|
421
|
+
return rank;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Find every iframe of the page, nested and out-of-process ones included,
|
|
425
|
+
* siblings in the document order of their iframe elements. Frames that go
|
|
426
|
+
* away while they are being listed are skipped.
|
|
427
|
+
*
|
|
428
|
+
* @param fc - Frame connection
|
|
429
|
+
* @returns Iframes in listing order
|
|
430
|
+
*/
|
|
431
|
+
async function discoverFrames(fc) {
|
|
432
|
+
const [page, outOfProcess] = await Promise.all([readSession(fc), outOfProcessTrees(fc)]);
|
|
433
|
+
const nodes = flattenTrees([page, ...outOfProcess]);
|
|
434
|
+
const sessionOf = new Map(nodes.map((node) => [node.frame.id, node.sessionId]));
|
|
435
|
+
const mainFrameId = page.tree.frame.id;
|
|
436
|
+
const iframes = nodes.filter((node) => node.frame.id !== mainFrameId);
|
|
437
|
+
const owners = new Map(await Promise.all(iframes.map(async (node) => [
|
|
438
|
+
node.frame.id,
|
|
439
|
+
await frameOwner(fc, node.frame.id, sessionOf.get(node.frame.parentId ?? '')),
|
|
440
|
+
])));
|
|
441
|
+
const rank = await siblingRanks(fc, iframes, owners, sessionOf);
|
|
442
|
+
const state = initialListingState(page, sessionOf);
|
|
443
|
+
return iframesInOrder(iframes, mainFrameId, rank).map((node, index) => describeFrame(node, index, owners.get(node.frame.id) ?? {}, state));
|
|
258
444
|
}
|
|
259
445
|
/**
|
|
260
446
|
* List the page's iframes.
|
|
261
447
|
*
|
|
262
448
|
* @param page - The session's connection
|
|
263
449
|
* @param wsUrl - WebSocket URL of the page target
|
|
264
|
-
* @returns Iframes in listing order
|
|
450
|
+
* @returns Iframes in listing order, and the frame id behind each index
|
|
265
451
|
*/
|
|
266
452
|
export async function listFrames(page, wsUrl) {
|
|
267
453
|
const frames = await withFrameConnection(page, wsUrl, discoverFrames);
|
|
268
|
-
return frames.map((frame) => frame.info);
|
|
454
|
+
return { frames: frames.map((frame) => frame.info), frameIds: frames.map((f) => f.frameId) };
|
|
269
455
|
}
|
|
270
456
|
/**
|
|
271
457
|
* Find the requested frame and its default execution context.
|
|
272
458
|
*
|
|
273
459
|
* @param fc - Frame connection
|
|
274
460
|
* @param query - Requested frame
|
|
461
|
+
* @param listedIds - Frame id behind each index of the last `dom frames` listing, if any
|
|
275
462
|
* @returns The frame and its context's unique id
|
|
276
|
-
* @throws CommandError (81/83) when the frame is ambiguous, missing or has no
|
|
463
|
+
* @throws CommandError (81/83) when the frame is ambiguous, missing or has no
|
|
464
|
+
* context, (87) when an index names another frame than when it was listed
|
|
277
465
|
*/
|
|
278
|
-
async function resolveFrame(fc, query) {
|
|
466
|
+
async function resolveFrame(fc, query, listedIds) {
|
|
279
467
|
const frames = await discoverFrames(fc);
|
|
468
|
+
assertFrameIndexCurrent(query, frames.map((frame) => frame.frameId), listedIds);
|
|
280
469
|
const selected = selectFrame(frames.map((frame) => frame.info), query);
|
|
281
470
|
const frame = frames[selected.index];
|
|
282
|
-
|
|
471
|
+
if (!frame.context) {
|
|
472
|
+
throw frameError(frameNotReadyError(frame.info.url), EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
473
|
+
}
|
|
474
|
+
return { frame, uniqueContextId: frame.context.uniqueId };
|
|
475
|
+
}
|
|
476
|
+
/** Chrome's messages when a frame (or the session of its parent) no longer exists */
|
|
477
|
+
const FRAME_GONE_PATTERN = /not found|no frame|no node/i;
|
|
478
|
+
/** How long the frame's parent gets to say whether the frame is still there */
|
|
479
|
+
const OWNER_CHECK_MS = 2_000;
|
|
480
|
+
/**
|
|
481
|
+
* Whether the frame's iframe element is still in its parent.
|
|
482
|
+
*
|
|
483
|
+
* @param conn - Connection the frame was found on
|
|
484
|
+
* @param frame - The frame
|
|
485
|
+
* @returns `attached`, `removed`, or `unknown` when the parent did not answer in time
|
|
486
|
+
* @throws Errors other than Chrome saying the frame is gone (e.g. a lost connection)
|
|
487
|
+
*/
|
|
488
|
+
async function frameOwnerState(conn, frame) {
|
|
489
|
+
try {
|
|
490
|
+
const owner = conn.send('DOM.getFrameOwner', { frameId: frame.frameId }, frame.ownerSession);
|
|
491
|
+
return (await settledWithin(owner, OWNER_CHECK_MS)).settled ? 'attached' : 'unknown';
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
if (!(error instanceof CDPProtocolError) || !FRAME_GONE_PATTERN.test(error.message))
|
|
495
|
+
throw error;
|
|
496
|
+
log.debug(`Frame ${frame.frameId} is gone: ${error.message}`);
|
|
497
|
+
return 'removed';
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* The error for a script whose frame context went away: the page was
|
|
502
|
+
* closed, the frame navigated (its iframe element is still there) or was
|
|
503
|
+
* removed.
|
|
504
|
+
*
|
|
505
|
+
* @param conn - Connection the frame was found on
|
|
506
|
+
* @param page - The session's connection to the page
|
|
507
|
+
* @param frame - The frame
|
|
508
|
+
* @returns Command error (83)
|
|
509
|
+
* @throws Errors of the checks other than Chrome saying the frame is gone
|
|
510
|
+
*/
|
|
511
|
+
export async function frameContextLostError(conn, page, frame) {
|
|
512
|
+
if (!(await pageStillOpen(page))) {
|
|
513
|
+
return frameError(pageClosedDuringEvalError(), EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
514
|
+
}
|
|
515
|
+
const messages = {
|
|
516
|
+
attached: frameNavigatedDuringEvalError,
|
|
517
|
+
removed: frameRemovedDuringEvalError,
|
|
518
|
+
unknown: frameLostDuringEvalError,
|
|
519
|
+
};
|
|
520
|
+
const err = messages[await frameOwnerState(conn, frame)](frame.url);
|
|
521
|
+
return frameError(err, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
283
522
|
}
|
|
284
523
|
/**
|
|
285
524
|
* Evaluate a `bdg dom eval` script in one iframe, like {@link evaluateScript}
|
|
@@ -288,18 +527,33 @@ async function resolveFrame(fc, query) {
|
|
|
288
527
|
* @param page - The session's connection
|
|
289
528
|
* @param wsUrl - WebSocket URL of the page target
|
|
290
529
|
* @param script - JavaScript expression
|
|
291
|
-
* @param query - Requested frame (index, name/id attribute, or part of the URL)
|
|
530
|
+
* @param query - Requested frame (index, name/id attribute, or part of the name, id or URL)
|
|
531
|
+
* @param listedIds - Frame id behind each index of the last `dom frames` listing, if any
|
|
292
532
|
* @returns Value, type and the frame's URL
|
|
293
|
-
* @throws CommandError (81/83) when the frame is ambiguous or missing,
|
|
533
|
+
* @throws CommandError (81/83) when the frame is ambiguous or missing, (87)
|
|
534
|
+
* when an index names another frame than when it was listed, (83) when it
|
|
535
|
+
* navigated or was removed while the script ran, else as evaluateScript
|
|
294
536
|
*/
|
|
295
|
-
export async function evaluateInFrame(page, wsUrl, script, query) {
|
|
537
|
+
export async function evaluateInFrame(page, wsUrl, script, query, listedIds) {
|
|
296
538
|
return withFrameConnection(page, wsUrl, async (fc) => {
|
|
297
|
-
const { frame, uniqueContextId } = await resolveFrame(fc, query);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
539
|
+
const { frame, uniqueContextId } = await resolveFrame(fc, query, listedIds);
|
|
540
|
+
try {
|
|
541
|
+
const result = await evaluateScript(fc.conn, script, {
|
|
542
|
+
...(frame.sessionId && { sessionId: frame.sessionId }),
|
|
543
|
+
uniqueContextId,
|
|
544
|
+
recovery: recoverySender(fc, frame.sessionId),
|
|
545
|
+
});
|
|
546
|
+
return { ...result, frame: frame.info.url };
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
if (!isContextLostError(error))
|
|
550
|
+
throw error;
|
|
551
|
+
throw await frameContextLostError(fc.conn, fc.page, {
|
|
552
|
+
frameId: frame.frameId,
|
|
553
|
+
url: frame.info.url,
|
|
554
|
+
...(frame.ownerSession && { ownerSession: frame.ownerSession }),
|
|
555
|
+
});
|
|
556
|
+
}
|
|
303
557
|
});
|
|
304
558
|
}
|
|
305
559
|
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bdg dom inspect`: what one element looks like, read in the daemon.
|
|
3
|
+
*
|
|
4
|
+
* The element is found like the other element commands find it (selector
|
|
5
|
+
* with filters through open shadow roots and same-origin iframes, or the
|
|
6
|
+
* exact cached node). Then, in parallel: one page-side walk on the element
|
|
7
|
+
* ({@link INSPECT_PAGE_JS}: text, placement in the parent, backgrounds, child
|
|
8
|
+
* tree), `dom layout`'s measurement (page position, hidden, covered,
|
|
9
|
+
* offscreen) and, once the nodes are pushed to CDP, `CSS.getComputedStyleForNode`
|
|
10
|
+
* for the element, its layout parent and its `::before`/`::after`,
|
|
11
|
+
* `CSS.getPlatformFontsForNode` for its text and `DOM.getBoxModel`. DOM and
|
|
12
|
+
* CSS are enabled on the first inspect and kept on. Matched rules are not
|
|
13
|
+
* read (no cascade).
|
|
14
|
+
*/
|
|
15
|
+
import type { CDPConnection } from '../../connection/cdp.js';
|
|
16
|
+
import type { DomInspectCommand } from '../../ipc/protocol/commands.js';
|
|
17
|
+
import type { InspectResult } from '../../ipc/protocol/inspectTypes.js';
|
|
18
|
+
/**
|
|
19
|
+
* Inspect one element.
|
|
20
|
+
*
|
|
21
|
+
* @param cdp - CDP connection
|
|
22
|
+
* @param params - Selector (and index) or backend node id, and options
|
|
23
|
+
* @returns Inspect result
|
|
24
|
+
* @throws CommandError (83) no match, (81) index out of range, invalid
|
|
25
|
+
* selector or unknown property, (87) the cached element left the page
|
|
26
|
+
*/
|
|
27
|
+
export declare function inspectElement(cdp: CDPConnection, params: DomInspectCommand): Promise<InspectResult>;
|
|
28
|
+
//# sourceMappingURL=inspect.d.ts.map
|