browser-debugger-cli 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/bdg/SKILL.md +4 -4
- package/README.md +143 -79
- package/dist/commands/cdp.d.ts +22 -1
- package/dist/commands/cdp.js +100 -43
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/console.js +62 -12
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/DomElementResolver.d.ts +3 -1
- package/dist/commands/dom/DomElementResolver.js +10 -3
- package/dist/commands/dom/a11y.js +3 -2
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/eval.d.ts +3 -2
- package/dist/commands/dom/eval.js +11 -5
- package/dist/commands/dom/form.js +10 -9
- package/dist/commands/dom/formInteraction.js +42 -11
- package/dist/commands/dom/get.js +8 -8
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/query.d.ts +27 -3
- package/dist/commands/dom/helpers/query.js +152 -64
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +169 -49
- package/dist/commands/dom/index.js +7 -2
- package/dist/commands/dom/query.d.ts +19 -2
- package/dist/commands/dom/query.js +37 -6
- package/dist/commands/dom/screenshot.js +12 -7
- package/dist/commands/dom/semanticUtils.d.ts +3 -2
- package/dist/commands/dom/semanticUtils.js +40 -9
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.d.ts +82 -19
- package/dist/commands/helpJson.js +112 -41
- package/dist/commands/helpTopic.d.ts +16 -1
- package/dist/commands/helpTopic.js +59 -1
- package/dist/commands/installSkill.d.ts +15 -5
- package/dist/commands/installSkill.js +86 -16
- package/dist/commands/network/list.js +22 -12
- package/dist/commands/optionBehaviors.js +53 -16
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
- package/dist/commands/shared/daemonErrorHandler.js +20 -9
- package/dist/commands/shared/dataFetcher.d.ts +12 -4
- package/dist/commands/shared/dataFetcher.js +12 -4
- package/dist/commands/shared/followMode.d.ts +9 -1
- package/dist/commands/shared/followMode.js +22 -4
- package/dist/commands/shared/optionTypes.d.ts +9 -2
- package/dist/commands/shared/outputFile.js +6 -1
- package/dist/commands/start.d.ts +20 -5
- package/dist/commands/start.js +84 -23
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.js +24 -1
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +2 -0
- package/dist/connection/cdp.d.ts +7 -0
- package/dist/connection/cdp.js +9 -0
- package/dist/connection/launcher.js +3 -2
- package/dist/daemon/SessionController.js +6 -1
- package/dist/daemon/launcher.d.ts +3 -2
- package/dist/daemon/launcher.js +47 -3
- package/dist/daemon/session/Session.d.ts +4 -1
- package/dist/daemon/session/Session.js +33 -2
- package/dist/daemon/session/TelemetryStore.d.ts +8 -1
- package/dist/daemon/session/TelemetryStore.js +13 -1
- package/dist/daemon/session/commandRegistry.js +36 -14
- package/dist/daemon/session/interactions.d.ts +2 -1
- package/dist/daemon/session/interactions.js +13 -1
- package/dist/daemon/session/plugins.js +19 -53
- package/dist/daemon/session/teardown.js +1 -1
- package/dist/daemon.js +9234 -7222
- package/dist/errors/messages.d.ts +88 -15
- package/dist/errors/messages.js +177 -27
- package/dist/index.js +19322 -13961
- package/dist/ipc/client.d.ts +22 -2
- package/dist/ipc/client.js +34 -5
- package/dist/ipc/protocol/auditTypes.d.ts +135 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +35 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +16 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +73 -8
- package/dist/ipc/session/types.d.ts +2 -0
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +9 -2
- package/dist/runtime/dom/actionEffects.js +30 -14
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +37 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +220 -0
- package/dist/runtime/dom/auditScripts.d.ts +113 -0
- package/dist/runtime/dom/auditScripts.js +148 -0
- package/dist/runtime/dom/elementGeometry.d.ts +16 -3
- package/dist/runtime/dom/elementGeometry.js +49 -10
- package/dist/runtime/dom/elementInfo.d.ts +74 -17
- package/dist/runtime/dom/elementInfo.js +187 -34
- package/dist/runtime/dom/evalHelpers.d.ts +12 -2
- package/dist/runtime/dom/evalHelpers.js +67 -7
- package/dist/runtime/dom/formDiscovery.d.ts +6 -2
- package/dist/runtime/dom/formDiscovery.js +20 -3
- package/dist/runtime/dom/formFillHelpers/fill.js +8 -12
- package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
- package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
- package/dist/runtime/dom/formSubmitHelpers.js +4 -3
- package/dist/runtime/dom/frameLayout.js +1 -0
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +92 -28
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +90 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +5 -1
- package/dist/runtime/dom/inspectModel.js +37 -10
- package/dist/runtime/dom/inspectPaintModel.d.ts +50 -22
- package/dist/runtime/dom/inspectPaintModel.js +182 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +112 -12
- package/dist/runtime/dom/inspectScripts.js +357 -32
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +40 -16
- package/dist/runtime/dom/reactEventHelpers.d.ts +21 -4
- package/dist/runtime/dom/reactEventHelpers.js +90 -36
- package/dist/runtime/dom/targetNode.d.ts +18 -5
- package/dist/runtime/dom/targetNode.js +268 -8
- package/dist/runtime/dom/wait.js +2 -1
- package/dist/runtime/page/bdgWorld.d.ts +57 -0
- package/dist/runtime/page/bdgWorld.js +180 -0
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
- package/dist/runtime/page/replacedBuiltins.js +136 -0
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/session/QueryCacheManager.d.ts +4 -1
- package/dist/session/QueryCacheManager.js +5 -2
- package/dist/session/chrome.d.ts +4 -1
- package/dist/session/chrome.js +7 -1
- package/dist/session/cleanup/staleSession.d.ts +21 -4
- package/dist/session/cleanup/staleSession.js +79 -9
- package/dist/session/cleanup/userCommands.d.ts +4 -1
- package/dist/session/cleanup/userCommands.js +10 -5
- package/dist/session/daemonSocket.d.ts +10 -0
- package/dist/session/daemonSocket.js +22 -0
- package/dist/session/lastSession.d.ts +6 -3
- package/dist/session/lastSession.js +11 -5
- package/dist/session/paths.d.ts +3 -1
- package/dist/session/paths.js +5 -5
- package/dist/session/portClaims.js +4 -3
- package/dist/session/sessionList.d.ts +13 -5
- package/dist/session/sessionList.js +31 -7
- package/dist/telemetry/a11y.js +2 -2
- package/dist/telemetry/console.d.ts +2 -1
- package/dist/telemetry/console.js +30 -21
- package/dist/telemetry/pageCrash.d.ts +26 -0
- package/dist/telemetry/pageCrash.js +53 -0
- package/dist/types.d.ts +20 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +115 -0
- package/dist/ui/formatters/cdp.d.ts +138 -0
- package/dist/ui/formatters/cdp.js +131 -0
- package/dist/ui/formatters/console/chronological.js +3 -1
- package/dist/ui/formatters/console/follow.d.ts +2 -1
- package/dist/ui/formatters/console/follow.js +2 -2
- package/dist/ui/formatters/console/json.d.ts +2 -2
- package/dist/ui/formatters/console/json.js +11 -5
- package/dist/ui/formatters/console/shared.d.ts +30 -0
- package/dist/ui/formatters/console/shared.js +16 -0
- package/dist/ui/formatters/console/summarize.d.ts +9 -2
- package/dist/ui/formatters/console/summarize.js +40 -9
- package/dist/ui/formatters/console.d.ts +2 -1
- package/dist/ui/formatters/console.js +7 -5
- package/dist/ui/formatters/details.js +3 -1
- package/dist/ui/formatters/dom.d.ts +2 -2
- package/dist/ui/formatters/dom.js +10 -8
- package/dist/ui/formatters/helpFormatters.js +1 -1
- package/dist/ui/formatters/inspect.js +50 -17
- package/dist/ui/formatters/installSkill.d.ts +9 -1
- package/dist/ui/formatters/installSkill.js +32 -6
- package/dist/ui/formatters/layout.js +2 -1
- package/dist/ui/formatters/networkList.d.ts +1 -1
- package/dist/ui/formatters/networkList.js +1 -2
- package/dist/ui/formatters/preview.d.ts +2 -0
- package/dist/ui/formatters/preview.js +17 -7
- package/dist/ui/formatters/sessions.d.ts +2 -2
- package/dist/ui/formatters/sessions.js +9 -2
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/commands.d.ts +168 -11
- package/dist/ui/messages/commands.js +245 -18
- package/dist/ui/messages/consoleMessages.d.ts +24 -0
- package/dist/ui/messages/consoleMessages.js +32 -0
- package/dist/ui/messages/preview.d.ts +12 -0
- package/dist/ui/messages/preview.js +18 -2
- package/dist/ui/messages/session.d.ts +13 -2
- package/dist/ui/messages/session.js +22 -3
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/directories.d.ts +34 -0
- package/dist/utils/directories.js +88 -0
- package/dist/utils/display.d.ts +16 -0
- package/dist/utils/display.js +42 -0
- package/dist/utils/exitCodes.d.ts +1 -0
- package/dist/utils/exitCodes.js +6 -0
- package/dist/utils/process.d.ts +12 -0
- package/dist/utils/process.js +25 -0
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +3 -2
|
@@ -4,6 +4,8 @@ import { createInteractionRunner } from './interactions.js';
|
|
|
4
4
|
import { withTriggeredRequestCount } from './triggeredRequests.js';
|
|
5
5
|
import { CommandError } from '../../errors/index.js';
|
|
6
6
|
import { cdpCallError, formDiscoveryFailedError } from '../../errors/messages.js';
|
|
7
|
+
import { searchStyleSheets } from '../../runtime/css/search.js';
|
|
8
|
+
import { auditPage } from '../../runtime/dom/audit.js';
|
|
7
9
|
import { evaluateScript, withBusyPageRecovery } from '../../runtime/dom/evalHelpers.js';
|
|
8
10
|
import { inspectEventListeners } from '../../runtime/dom/eventListeners.js';
|
|
9
11
|
import { FORM_DISCOVERY_SCRIPT, isRawFormData } from '../../runtime/dom/formDiscovery.js';
|
|
@@ -15,10 +17,12 @@ import { inspectElement } from '../../runtime/dom/inspect.js';
|
|
|
15
17
|
import { inspectLayout } from '../../runtime/dom/layout.js';
|
|
16
18
|
import { onScriptTarget } from '../../runtime/dom/targetNode.js';
|
|
17
19
|
import { waitForCondition } from '../../runtime/dom/wait.js';
|
|
20
|
+
import { evaluateInBdgWorld, sendForBdgScript } from '../../runtime/page/bdgWorld.js';
|
|
18
21
|
import { emulatePage, pageAppearance } from '../../runtime/page/emulation.js';
|
|
19
22
|
import { readDocumentReadyState } from '../../runtime/page/loadingState.js';
|
|
20
23
|
import { navigatePage } from '../../runtime/page/navigation.js';
|
|
21
24
|
import { skippedBodyReason } from '../../telemetry/network.js';
|
|
25
|
+
import { consoleMessageDroppedError } from '../../ui/messages/consoleMessages.js';
|
|
22
26
|
import { sessionCommand } from '../../ui/messages/sessionCommand.js';
|
|
23
27
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
24
28
|
import { filterDefined } from '../../utils/objects.js';
|
|
@@ -185,24 +189,28 @@ function findNetworkRequestOrThrow(store, id) {
|
|
|
185
189
|
return request;
|
|
186
190
|
}
|
|
187
191
|
/**
|
|
188
|
-
* Find console message by index or throw.
|
|
192
|
+
* Find console message by its session index or throw.
|
|
189
193
|
*
|
|
190
|
-
* @param messages -
|
|
194
|
+
* @param messages - Console messages kept
|
|
191
195
|
* @param indexStr - Index as string
|
|
196
|
+
* @param dropped - Messages dropped before the first kept one (its index)
|
|
192
197
|
* @returns Found message
|
|
193
|
-
* @throws
|
|
198
|
+
* @throws CommandError if the index is invalid, dropped or not found
|
|
194
199
|
*/
|
|
195
|
-
function findConsoleMessageOrThrow(messages, indexStr) {
|
|
200
|
+
function findConsoleMessageOrThrow(messages, indexStr, dropped) {
|
|
196
201
|
if (!/^\d+$/.test(indexStr)) {
|
|
197
202
|
throw new CommandError(`Invalid console message index: ${indexStr}`, { suggestion: `Use a 0-based index from: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
198
203
|
}
|
|
199
204
|
const index = parseInt(indexStr, 10);
|
|
200
|
-
if (index
|
|
205
|
+
if (index < dropped) {
|
|
206
|
+
throw new CommandError(consoleMessageDroppedError(index, dropped), { suggestion: `List messages with: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
207
|
+
}
|
|
208
|
+
if (index - dropped >= messages.length) {
|
|
201
209
|
throw new CommandError(messages.length === 0
|
|
202
210
|
? `Console message not found at index: ${indexStr} (no messages captured yet)`
|
|
203
|
-
: `Console message not found at index: ${indexStr} (available:
|
|
211
|
+
: `Console message not found at index: ${indexStr} (available: ${dropped}-${dropped + messages.length - 1})`, { suggestion: `List messages with: ${sessionCommand('bdg console --list')}` }, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
204
212
|
}
|
|
205
|
-
const message = messages[index];
|
|
213
|
+
const message = messages[index - dropped];
|
|
206
214
|
if (!message) {
|
|
207
215
|
throw new CommandError(`Console message not found at index: ${indexStr}`, {}, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
208
216
|
}
|
|
@@ -310,6 +318,7 @@ export function createCommandRegistry(store, emulation) {
|
|
|
310
318
|
const allNetwork = allNetworkRequests(store);
|
|
311
319
|
const totalNetwork = allNetwork.length;
|
|
312
320
|
const totalConsole = store.consoleMessages.length;
|
|
321
|
+
const dropped = store.consoleDropped;
|
|
313
322
|
const networkBounds = calculateSliceBounds(totalNetwork, lastN, offset);
|
|
314
323
|
const consoleBounds = calculateSliceBounds(totalConsole, lastN, offset);
|
|
315
324
|
const recentNetwork = params.only === 'console'
|
|
@@ -321,7 +330,7 @@ export function createCommandRegistry(store, emulation) {
|
|
|
321
330
|
? []
|
|
322
331
|
: store.consoleMessages
|
|
323
332
|
.slice(consoleBounds.start, consoleBounds.end)
|
|
324
|
-
.map((msg, i) => mapConsoleMessageToPreview(msg, consoleBounds.start + i));
|
|
333
|
+
.map((msg, i) => mapConsoleMessageToPreview(msg, dropped + consoleBounds.start + i));
|
|
325
334
|
return Promise.resolve({
|
|
326
335
|
version: VERSION,
|
|
327
336
|
startTime: store.sessionStartTime,
|
|
@@ -332,10 +341,12 @@ export function createCommandRegistry(store, emulation) {
|
|
|
332
341
|
},
|
|
333
342
|
activeTelemetry: store.activeTelemetry,
|
|
334
343
|
currentNavigationId: store.getCurrentNavigationId?.() ?? 0,
|
|
344
|
+
...(store.pageCrashedAt !== undefined && { pageCrashedAt: store.pageCrashedAt }),
|
|
335
345
|
network: recentNetwork,
|
|
336
346
|
console: recentConsole,
|
|
337
347
|
totalNetwork,
|
|
338
348
|
totalConsole,
|
|
349
|
+
...(dropped > 0 && { droppedConsole: dropped }),
|
|
339
350
|
hasMoreNetwork: networkBounds.start > 0,
|
|
340
351
|
hasMoreConsole: consoleBounds.start > 0,
|
|
341
352
|
});
|
|
@@ -346,7 +357,7 @@ export function createCommandRegistry(store, emulation) {
|
|
|
346
357
|
return Promise.resolve({ item: withBodyNotCaptured(request) });
|
|
347
358
|
}
|
|
348
359
|
if (params.itemType === 'console') {
|
|
349
|
-
const message = findConsoleMessageOrThrow(store.consoleMessages, params.id);
|
|
360
|
+
const message = findConsoleMessageOrThrow(store.consoleMessages, params.id, store.consoleDropped);
|
|
350
361
|
return Promise.resolve({ item: message });
|
|
351
362
|
}
|
|
352
363
|
return Promise.reject(new Error(`Unknown itemType: ${String(params.itemType)}. Expected 'network' or 'console'.`));
|
|
@@ -361,7 +372,9 @@ export function createCommandRegistry(store, emulation) {
|
|
|
361
372
|
target: {
|
|
362
373
|
url: store.targetInfo?.url ?? '',
|
|
363
374
|
title: store.targetInfo?.title ?? '',
|
|
364
|
-
...(
|
|
375
|
+
...(store.pageCrashedAt === undefined
|
|
376
|
+
? await pageAppearance(cdp)
|
|
377
|
+
: { crashedAt: store.pageCrashedAt }),
|
|
365
378
|
},
|
|
366
379
|
activeTelemetry: store.activeTelemetry,
|
|
367
380
|
activity: filterDefined({
|
|
@@ -399,10 +412,15 @@ export function createCommandRegistry(store, emulation) {
|
|
|
399
412
|
});
|
|
400
413
|
},
|
|
401
414
|
cdp_call: async (cdp, params) => {
|
|
402
|
-
const
|
|
415
|
+
const send = params.isolated
|
|
416
|
+
? sendForBdgScript(cdp, params.method, params.params ?? {})
|
|
417
|
+
: cdp.send(params.method, params.params ?? {});
|
|
418
|
+
const result = await withBusyPageRecovery(cdp, send.catch((error) => {
|
|
403
419
|
throw callerError(params.method, error) ?? error;
|
|
404
420
|
}));
|
|
405
|
-
const detectionResult =
|
|
421
|
+
const detectionResult = params.isolated
|
|
422
|
+
? { shouldShow: false, pattern: undefined }
|
|
423
|
+
: patternDetector.trackCommand(params.method);
|
|
406
424
|
let hint;
|
|
407
425
|
if (detectionResult.shouldShow && detectionResult.pattern) {
|
|
408
426
|
hint = {
|
|
@@ -458,7 +476,11 @@ export function createCommandRegistry(store, emulation) {
|
|
|
458
476
|
})), params.wait !== false))),
|
|
459
477
|
dom_listeners: async (cdp, params) => withBusyPageRecovery(cdp, inspectEventListeners(cdp, params)),
|
|
460
478
|
dom_layout: async (cdp, params) => withBusyPageRecovery(cdp, inspectLayout(cdp, params)),
|
|
461
|
-
|
|
479
|
+
dom_audit: async (cdp, params) => withBusyPageRecovery(cdp, auditPage(cdp, params)),
|
|
480
|
+
css_search: async (cdp, params) => searchStyleSheets(cdp, params),
|
|
481
|
+
dom_inspect: async (cdp, params) => withBusyPageRecovery(cdp, inspectElement(cdp, params).then((result) => result.theme === 'dark' && emulation.get().colorScheme === 'dark'
|
|
482
|
+
? { ...result, themeFrom: 'emulation' }
|
|
483
|
+
: result)),
|
|
462
484
|
dom_wait: async (cdp, params) => waitForCondition(cdp, params),
|
|
463
485
|
page_navigate: async (cdp, params) => interact(cdp, () => navigatePage(cdp, params.action, {
|
|
464
486
|
...filterDefined({ url: params.url, wait: params.wait }),
|
|
@@ -469,7 +491,7 @@ export function createCommandRegistry(store, emulation) {
|
|
|
469
491
|
return { emulated, ...(await pageAppearance(cdp)) };
|
|
470
492
|
},
|
|
471
493
|
dom_form_discover: async (cdp) => {
|
|
472
|
-
const response = await withBusyPageRecovery(cdp, cdp
|
|
494
|
+
const response = await withBusyPageRecovery(cdp, evaluateInBdgWorld(cdp, {
|
|
473
495
|
expression: FORM_DISCOVERY_SCRIPT,
|
|
474
496
|
returnByValue: true,
|
|
475
497
|
}));
|
|
@@ -51,7 +51,8 @@ export type InteractionRunner = <T extends object>(cdp: CDPConnection, action: (
|
|
|
51
51
|
* queued. After each one, the bound target (`window.__bdgTarget`) is removed
|
|
52
52
|
* from the page (without waiting: during a pending navigation that takes until
|
|
53
53
|
* the new page commits), and the dialogs it opened, what it changed on the
|
|
54
|
-
* page (see {@link watchActionEffects}
|
|
54
|
+
* page (see {@link watchActionEffects}; a console message logged meanwhile
|
|
55
|
+
* counts as an effect) and the network requests it
|
|
55
56
|
* triggered (see {@link watchTriggeredRequests}) are added to its result,
|
|
56
57
|
* and, when asked, what the page was still working on (see
|
|
57
58
|
* {@link pendingChanges}). They are attributed by time: a dialog or request
|
|
@@ -18,6 +18,15 @@ const log = createLogger('dom');
|
|
|
18
18
|
function succeeded(result) {
|
|
19
19
|
return !('success' in result) || result.success !== false;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Console messages the session has logged, dropped ones included.
|
|
23
|
+
*
|
|
24
|
+
* @param store - Session store
|
|
25
|
+
* @returns Count that only grows
|
|
26
|
+
*/
|
|
27
|
+
function consoleMessagesLogged(store) {
|
|
28
|
+
return store.consoleDropped + store.consoleMessages.length;
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* Create the runner for a session's interactions.
|
|
23
32
|
*
|
|
@@ -26,7 +35,8 @@ function succeeded(result) {
|
|
|
26
35
|
* queued. After each one, the bound target (`window.__bdgTarget`) is removed
|
|
27
36
|
* from the page (without waiting: during a pending navigation that takes until
|
|
28
37
|
* the new page commits), and the dialogs it opened, what it changed on the
|
|
29
|
-
* page (see {@link watchActionEffects}
|
|
38
|
+
* page (see {@link watchActionEffects}; a console message logged meanwhile
|
|
39
|
+
* counts as an effect) and the network requests it
|
|
30
40
|
* triggered (see {@link watchTriggeredRequests}) are added to its result,
|
|
31
41
|
* and, when asked, what the page was still working on (see
|
|
32
42
|
* {@link pendingChanges}). They are attributed by time: a dialog or request
|
|
@@ -41,6 +51,7 @@ export function createInteractionRunner(store) {
|
|
|
41
51
|
return (cdp, action, options = {}) => {
|
|
42
52
|
const run = queue.then(async () => {
|
|
43
53
|
const firstDialog = store.dialogs.length;
|
|
54
|
+
const firstConsoleMessage = consoleMessagesLogged(store);
|
|
44
55
|
const collectRequests = options.reportRequests === false ? undefined : watchTriggeredRequests(store);
|
|
45
56
|
const effects = options.reportEffects === false ? undefined : watchActionEffects(cdp);
|
|
46
57
|
try {
|
|
@@ -50,6 +61,7 @@ export function createInteractionRunner(store) {
|
|
|
50
61
|
return { ...result, ...(dialogs.length > 0 && { dialogs }) };
|
|
51
62
|
const collected = await effects?.collect({
|
|
52
63
|
dialogs: dialogs.length,
|
|
64
|
+
consoleMessages: () => consoleMessagesLogged(store) - firstConsoleMessage,
|
|
53
65
|
detectNoEffect: options.detectNoEffect === true,
|
|
54
66
|
reportShown: options.reportShown === true,
|
|
55
67
|
detectUnsettled: options.detectUnsettled === true,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { hideHeadlessUserAgent } from '../../runtime/page/userAgent.js';
|
|
1
2
|
import { startConsoleCollection } from '../../telemetry/console.js';
|
|
2
3
|
import { startDialogHandling } from '../../telemetry/dialogs.js';
|
|
3
4
|
import { prepareDOMCollection } from '../../telemetry/dom.js';
|
|
4
5
|
import { startNavigationTracking } from '../../telemetry/navigation.js';
|
|
5
6
|
import { startNetworkCollection, startWebSocketCollection } from '../../telemetry/network.js';
|
|
7
|
+
import { pageCrashedCommandError, startCrashTracking } from '../../telemetry/pageCrash.js';
|
|
6
8
|
import { getErrorMessage } from '../../utils/errors.js';
|
|
7
9
|
import { filterDefined } from '../../utils/objects.js';
|
|
8
10
|
/** Delay before reading the title after a same-document navigation */
|
|
@@ -83,56 +85,6 @@ async function emulatePageFocus(cdp, logger) {
|
|
|
83
85
|
.send('Emulation.setFocusEmulationEnabled', { enabled: true })
|
|
84
86
|
.catch((error) => logger.debug(`No focus emulation: ${getErrorMessage(error)}`));
|
|
85
87
|
}
|
|
86
|
-
/** Reads the client hints Chrome reports, renaming the HeadlessChrome brand */
|
|
87
|
-
const USER_AGENT_METADATA_SCRIPT = `(async () => {
|
|
88
|
-
const data = navigator.userAgentData;
|
|
89
|
-
if (!data) return null;
|
|
90
|
-
const values = await data.getHighEntropyValues(
|
|
91
|
-
['architecture', 'bitness', 'model', 'platformVersion', 'fullVersionList', 'wow64']
|
|
92
|
-
);
|
|
93
|
-
const rename = (list) => (list || []).map((entry) => ({
|
|
94
|
-
brand: entry.brand.replace('HeadlessChrome', 'Google Chrome'),
|
|
95
|
-
version: entry.version,
|
|
96
|
-
}));
|
|
97
|
-
return {
|
|
98
|
-
brands: rename(values.brands),
|
|
99
|
-
fullVersionList: rename(values.fullVersionList),
|
|
100
|
-
platform: values.platform,
|
|
101
|
-
platformVersion: values.platformVersion,
|
|
102
|
-
architecture: values.architecture,
|
|
103
|
-
model: values.model,
|
|
104
|
-
mobile: values.mobile,
|
|
105
|
-
bitness: values.bitness,
|
|
106
|
-
wow64: values.wow64,
|
|
107
|
-
};
|
|
108
|
-
})()`;
|
|
109
|
-
/**
|
|
110
|
-
* Send the user agent and client hints of regular Chrome from headless
|
|
111
|
-
* Chrome: sites serve "HeadlessChrome" a different page (or a bot
|
|
112
|
-
* challenge), so the page would not be the one a user sees.
|
|
113
|
-
*
|
|
114
|
-
* @param cdp - CDP connection
|
|
115
|
-
* @param logger - Logger for failures (the session works without it)
|
|
116
|
-
*/
|
|
117
|
-
async function hideHeadlessUserAgent(cdp, logger) {
|
|
118
|
-
try {
|
|
119
|
-
const { userAgent } = (await cdp.send('Browser.getVersion'));
|
|
120
|
-
if (!userAgent.includes('HeadlessChrome'))
|
|
121
|
-
return;
|
|
122
|
-
const metadata = (await cdp.send('Runtime.evaluate', {
|
|
123
|
-
expression: USER_AGENT_METADATA_SCRIPT,
|
|
124
|
-
awaitPromise: true,
|
|
125
|
-
returnByValue: true,
|
|
126
|
-
}));
|
|
127
|
-
await cdp.send('Emulation.setUserAgentOverride', {
|
|
128
|
-
userAgent: userAgent.replace('HeadlessChrome', 'Chrome'),
|
|
129
|
-
...(metadata.result?.value ? { userAgentMetadata: metadata.result.value } : {}),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
logger.debug(`User agent left as is: ${getErrorMessage(error)}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
88
|
export function createDefaultTelemetryPlugins() {
|
|
137
89
|
return [
|
|
138
90
|
{
|
|
@@ -145,12 +97,24 @@ export function createDefaultTelemetryPlugins() {
|
|
|
145
97
|
{
|
|
146
98
|
name: 'page-identity',
|
|
147
99
|
runAlways: true,
|
|
148
|
-
async start({ cdp, logger }) {
|
|
100
|
+
async start({ cdp, logger, config }) {
|
|
149
101
|
await emulatePageFocus(cdp, logger);
|
|
150
|
-
|
|
102
|
+
if (!config.viewport?.mobile)
|
|
103
|
+
await hideHeadlessUserAgent(cdp, logger);
|
|
151
104
|
return () => undefined;
|
|
152
105
|
},
|
|
153
106
|
},
|
|
107
|
+
{
|
|
108
|
+
name: 'page-crash',
|
|
109
|
+
runAlways: true,
|
|
110
|
+
async start({ cdp, store }) {
|
|
111
|
+
return startCrashTracking(cdp, (crashedAt) => {
|
|
112
|
+
store.pageCrashedAt = crashedAt;
|
|
113
|
+
if (crashedAt !== undefined)
|
|
114
|
+
cdp.rejectPending(pageCrashedCommandError(crashedAt));
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
},
|
|
154
118
|
{
|
|
155
119
|
name: 'navigation',
|
|
156
120
|
runAlways: true,
|
|
@@ -191,7 +155,9 @@ export function createDefaultTelemetryPlugins() {
|
|
|
191
155
|
name: 'console',
|
|
192
156
|
telemetry: 'console',
|
|
193
157
|
async start({ cdp, config, store }) {
|
|
194
|
-
return startConsoleCollection(cdp, store.consoleMessages, config.includeAll ?? false, store.getCurrentNavigationId ?? undefined)
|
|
158
|
+
return startConsoleCollection(cdp, store.consoleMessages, config.includeAll ?? false, store.getCurrentNavigationId ?? undefined, () => {
|
|
159
|
+
store.consoleDropped++;
|
|
160
|
+
});
|
|
195
161
|
},
|
|
196
162
|
},
|
|
197
163
|
{
|