browser-debugger-cli 0.9.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 +4 -1
- package/dist/commands/dom/a11y.js +2 -1
- package/dist/commands/dom/formInteraction.js +56 -25
- 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 +1 -1
- package/dist/commands/dom/helpers/query.js +66 -19
- package/dist/commands/dom/helpers/runElementCommand.js +4 -3
- package/dist/commands/dom/helpers/screenshot.js +85 -12
- package/dist/commands/dom/index.d.ts +1 -0
- package/dist/commands/dom/index.js +8 -3
- package/dist/commands/dom/inspect.d.ts +15 -0
- package/dist/commands/dom/inspect.js +82 -0
- package/dist/commands/dom/layout.js +2 -2
- package/dist/commands/dom/listeners.js +2 -2
- package/dist/commands/dom/semanticUtils.d.ts +14 -1
- package/dist/commands/dom/semanticUtils.js +44 -3
- package/dist/commands/network/list.js +13 -2
- package/dist/commands/optionBehaviors.js +48 -6
- package/dist/commands/page.d.ts +1 -1
- package/dist/commands/page.js +62 -3
- package/dist/commands/shared/commonOptions.d.ts +4 -0
- package/dist/commands/shared/commonOptions.js +9 -0
- package/dist/commands/shared/optionTypes.d.ts +21 -0
- package/dist/commands/shared/startHelpers.d.ts +66 -0
- package/dist/commands/shared/startHelpers.js +91 -10
- package/dist/commands/shared/validation.d.ts +11 -0
- package/dist/commands/shared/validation.js +16 -0
- package/dist/daemon/launcher.d.ts +8 -1
- package/dist/daemon/launcher.js +3 -1
- package/dist/daemon/session/Session.d.ts +7 -0
- package/dist/daemon/session/Session.js +23 -1
- package/dist/daemon/session/commandRegistry.d.ts +14 -1
- package/dist/daemon/session/commandRegistry.js +65 -9
- package/dist/daemon/session/interactions.d.ts +18 -5
- package/dist/daemon/session/interactions.js +22 -12
- package/dist/daemon.js +3565 -329
- package/dist/errors/messages.d.ts +69 -0
- package/dist/errors/messages.js +102 -1
- package/dist/index.js +2416 -1320
- package/dist/ipc/client.d.ts +9 -0
- package/dist/ipc/client.js +13 -0
- package/dist/ipc/protocol/commands.d.ts +56 -1
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +35 -2
- package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
- package/dist/ipc/protocol/inspectTypes.js +10 -0
- package/dist/runtime/dom/actionEffects.d.ts +94 -15
- package/dist/runtime/dom/actionEffects.js +173 -27
- package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -14
- package/dist/runtime/dom/actionEffectsScripts.js +224 -32
- package/dist/runtime/dom/elementInfo.d.ts +26 -0
- package/dist/runtime/dom/elementInfo.js +65 -0
- package/dist/runtime/dom/eventListeners.js +14 -4
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +3 -4
- package/dist/runtime/dom/formFillHelpers/fill.js +77 -28
- package/dist/runtime/dom/frameSelection.d.ts +11 -0
- package/dist/runtime/dom/frameSelection.js +20 -1
- package/dist/runtime/dom/frames.d.ts +38 -5
- package/dist/runtime/dom/frames.js +136 -21
- 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 +5 -1
- package/dist/runtime/dom/layout.js +10 -3
- package/dist/runtime/dom/listenerPageScripts.d.ts +11 -5
- package/dist/runtime/dom/listenerPageScripts.js +95 -9
- package/dist/runtime/dom/listenerSummary.d.ts +4 -0
- package/dist/runtime/dom/listenerSummary.js +26 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +5 -0
- package/dist/runtime/dom/reactEventHelpers.js +12 -4
- package/dist/runtime/page/emulation.d.ts +20 -0
- package/dist/runtime/page/emulation.js +37 -0
- package/dist/telemetry/a11y.d.ts +10 -0
- package/dist/telemetry/a11y.js +78 -1
- package/dist/telemetry/console.d.ts +1 -0
- package/dist/telemetry/console.js +100 -5
- package/dist/telemetry/network.js +3 -1
- package/dist/types.d.ts +32 -0
- package/dist/ui/formatters/details.d.ts +8 -0
- package/dist/ui/formatters/details.js +59 -3
- package/dist/ui/formatters/dom.d.ts +2 -1
- package/dist/ui/formatters/dom.js +25 -9
- 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.js +2 -2
- package/dist/ui/formatters/networkHeaders.d.ts +13 -0
- package/dist/ui/formatters/networkHeaders.js +23 -3
- package/dist/ui/formatters/networkList.d.ts +29 -1
- package/dist/ui/formatters/networkList.js +86 -20
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/formatting.d.ts +9 -0
- package/dist/ui/formatting.js +6 -3
- package/dist/ui/messages/commands.d.ts +123 -7
- package/dist/ui/messages/commands.js +181 -10
- package/dist/ui/messages/networkMessages.d.ts +14 -0
- package/dist/ui/messages/networkMessages.js +18 -0
- package/dist/ui/messages/session.d.ts +14 -0
- package/dist/ui/messages/session.js +20 -0
- package/dist/utils/async.d.ts +9 -0
- package/dist/utils/async.js +17 -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/selectorFilters.d.ts +12 -0
- package/dist/utils/selectorFilters.js +29 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ import { getSessionPort } from '../../session/port.js';
|
|
|
21
21
|
import { createLogger } from '../../ui/logging/index.js';
|
|
22
22
|
import { formatChromeNotice } from '../../ui/messages/chrome.js';
|
|
23
23
|
import { delay } from '../../utils/async.js';
|
|
24
|
+
import { getErrorMessage } from '../../utils/errors.js';
|
|
24
25
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
25
26
|
import { filterDefined } from '../../utils/objects.js';
|
|
26
27
|
import { isProcessAlive } from '../../utils/process.js';
|
|
@@ -55,7 +56,10 @@ export class Session {
|
|
|
55
56
|
config;
|
|
56
57
|
onEnded;
|
|
57
58
|
store = new TelemetryStore();
|
|
58
|
-
registry = createCommandRegistry(this.store
|
|
59
|
+
registry = createCommandRegistry(this.store, {
|
|
60
|
+
get: () => filterDefined({ viewport: this.config.viewport, colorScheme: this.config.colorScheme }),
|
|
61
|
+
set: (emulation) => this.setEmulation(emulation),
|
|
62
|
+
});
|
|
59
63
|
notify = (notice) => log.info(formatChromeNotice(notice));
|
|
60
64
|
chrome = null;
|
|
61
65
|
cdp = null;
|
|
@@ -174,6 +178,24 @@ export class Session {
|
|
|
174
178
|
}),
|
|
175
179
|
};
|
|
176
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Record a page emulation changed mid-session, so screenshots restore it
|
|
183
|
+
* and `bdg status` reports it.
|
|
184
|
+
*
|
|
185
|
+
* @param emulation - Viewport and color scheme now emulated
|
|
186
|
+
*/
|
|
187
|
+
setEmulation(emulation) {
|
|
188
|
+
const { viewport: _viewport, colorScheme: _colorScheme, ...rest } = this.config;
|
|
189
|
+
this.config = { ...rest, ...emulation };
|
|
190
|
+
if (!this.started)
|
|
191
|
+
return;
|
|
192
|
+
try {
|
|
193
|
+
writeSessionMetadata(this.metadata());
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
log.debug(`Session metadata not updated: ${getErrorMessage(error)}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
177
199
|
/**
|
|
178
200
|
* Whether stop() has been called.
|
|
179
201
|
*
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import type { TelemetryStore } from './TelemetryStore.js';
|
|
2
2
|
import type { CDPConnection } from '../../connection/cdp.js';
|
|
3
3
|
import type { CommandName, CommandSchemas } from '../../ipc/index.js';
|
|
4
|
+
import { type SessionEmulation } from '../../runtime/page/emulation.js';
|
|
4
5
|
type Handler<K extends CommandName> = (cdp: CDPConnection, params: CommandSchemas[K]['requestSchema']) => Promise<CommandSchemas[K]['responseSchema']>;
|
|
5
6
|
export type CommandRegistry = {
|
|
6
7
|
[K in CommandName]: Handler<K>;
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
+
/** The session's page emulation, which `page emulate` reads and changes */
|
|
10
|
+
export interface EmulationState {
|
|
11
|
+
get: () => SessionEmulation;
|
|
12
|
+
set: (emulation: SessionEmulation) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The handlers of the session commands.
|
|
16
|
+
*
|
|
17
|
+
* @param store - Telemetry of the session
|
|
18
|
+
* @param emulation - The session's page emulation
|
|
19
|
+
* @returns Command registry
|
|
20
|
+
*/
|
|
21
|
+
export declare function createCommandRegistry(store: TelemetryStore, emulation: EmulationState): CommandRegistry;
|
|
9
22
|
export {};
|
|
10
23
|
//# sourceMappingURL=commandRegistry.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { CDPConnectionError } from '../../connection/errors.js';
|
|
1
|
+
import { CDPConnectionError, CDPProtocolError } from '../../connection/errors.js';
|
|
2
2
|
import { PatternDetector } from '../patternDetector.js';
|
|
3
3
|
import { createInteractionRunner } from './interactions.js';
|
|
4
4
|
import { withTriggeredRequestCount } from './triggeredRequests.js';
|
|
5
5
|
import { CommandError } from '../../errors/index.js';
|
|
6
|
-
import { formDiscoveryFailedError } from '../../errors/messages.js';
|
|
6
|
+
import { cdpCallError, formDiscoveryFailedError } from '../../errors/messages.js';
|
|
7
7
|
import { evaluateScript, withBusyPageRecovery } from '../../runtime/dom/evalHelpers.js';
|
|
8
8
|
import { inspectEventListeners } from '../../runtime/dom/eventListeners.js';
|
|
9
9
|
import { FORM_DISCOVERY_SCRIPT, isRawFormData } from '../../runtime/dom/formDiscovery.js';
|
|
@@ -11,10 +11,11 @@ import { fillElement, clickElement, pressKeyElement, scrollPage, withActionStabi
|
|
|
11
11
|
import { exceptionSummary } from '../../runtime/dom/formFillHelpers/shared.js';
|
|
12
12
|
import { submitForm } from '../../runtime/dom/formSubmitHelpers.js';
|
|
13
13
|
import { evaluateInFrame, listFrames } from '../../runtime/dom/frames.js';
|
|
14
|
+
import { inspectElement } from '../../runtime/dom/inspect.js';
|
|
14
15
|
import { inspectLayout } from '../../runtime/dom/layout.js';
|
|
15
16
|
import { onScriptTarget } from '../../runtime/dom/targetNode.js';
|
|
16
17
|
import { waitForCondition } from '../../runtime/dom/wait.js';
|
|
17
|
-
import { pageAppearance } from '../../runtime/page/emulation.js';
|
|
18
|
+
import { emulatePage, pageAppearance } from '../../runtime/page/emulation.js';
|
|
18
19
|
import { readDocumentReadyState } from '../../runtime/page/loadingState.js';
|
|
19
20
|
import { navigatePage } from '../../runtime/page/navigation.js';
|
|
20
21
|
import { skippedBodyReason } from '../../telemetry/network.js';
|
|
@@ -62,6 +63,8 @@ function mapNetworkRequestToPreview(req, withHeaders = false) {
|
|
|
62
63
|
return filterDefined({
|
|
63
64
|
requestId: req.requestId,
|
|
64
65
|
timestamp: req.timestamp,
|
|
66
|
+
sentTime: req.sentTime,
|
|
67
|
+
navigationId: req.navigationId,
|
|
65
68
|
method: req.method,
|
|
66
69
|
url: req.url,
|
|
67
70
|
status: req.status,
|
|
@@ -260,9 +263,45 @@ function pageWebSocketUrl(store) {
|
|
|
260
263
|
throw new CDPConnectionError('No page target');
|
|
261
264
|
return url;
|
|
262
265
|
}
|
|
263
|
-
|
|
266
|
+
/** Chrome's "server error" code, used for failures on the page's state (a missing node, a bad id…) */
|
|
267
|
+
const CDP_SERVER_ERROR = -32000;
|
|
268
|
+
/**
|
|
269
|
+
* A `bdg cdp` failure that is the caller's: wrong parameters (81), or an
|
|
270
|
+
* id of a node, target or frame that does not exist (83). Other failures
|
|
271
|
+
* (internal errors, a detached page) stay software errors.
|
|
272
|
+
*
|
|
273
|
+
* @param method - CDP method
|
|
274
|
+
* @param error - What the call threw
|
|
275
|
+
* @returns The error to report, or undefined to keep the original
|
|
276
|
+
*/
|
|
277
|
+
function callerError(method, error) {
|
|
278
|
+
if (!(error instanceof CDPProtocolError))
|
|
279
|
+
return undefined;
|
|
280
|
+
const err = cdpCallError(method, error.message);
|
|
281
|
+
if (error.isRequestError()) {
|
|
282
|
+
return new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
283
|
+
}
|
|
284
|
+
if (error.code === CDP_SERVER_ERROR && err.notFound) {
|
|
285
|
+
return new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
286
|
+
}
|
|
287
|
+
if (error.code === CDP_SERVER_ERROR &&
|
|
288
|
+
/must be specified|invalid|expected|missing/i.test(error.message)) {
|
|
289
|
+
return new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
290
|
+
}
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The handlers of the session commands.
|
|
295
|
+
*
|
|
296
|
+
* @param store - Telemetry of the session
|
|
297
|
+
* @param emulation - The session's page emulation
|
|
298
|
+
* @returns Command registry
|
|
299
|
+
*/
|
|
300
|
+
export function createCommandRegistry(store, emulation) {
|
|
264
301
|
const patternDetector = new PatternDetector();
|
|
265
302
|
const interact = createInteractionRunner(store);
|
|
303
|
+
/** Frame id behind each index of the last `dom frames` listing */
|
|
304
|
+
let listedFrameIds;
|
|
266
305
|
return {
|
|
267
306
|
session_peek: async (_cdp, params) => {
|
|
268
307
|
const lastN = calculateLastN(params.lastN);
|
|
@@ -360,7 +399,9 @@ export function createCommandRegistry(store) {
|
|
|
360
399
|
});
|
|
361
400
|
},
|
|
362
401
|
cdp_call: async (cdp, params) => {
|
|
363
|
-
const result = await withBusyPageRecovery(cdp, cdp.send(params.method, params.params ?? {}))
|
|
402
|
+
const result = await withBusyPageRecovery(cdp, cdp.send(params.method, params.params ?? {}).catch((error) => {
|
|
403
|
+
throw callerError(params.method, error) ?? error;
|
|
404
|
+
}));
|
|
364
405
|
const detectionResult = patternDetector.trackCommand(params.method);
|
|
365
406
|
let hint;
|
|
366
407
|
if (detectionResult.shouldShow && detectionResult.pattern) {
|
|
@@ -376,11 +417,21 @@ export function createCommandRegistry(store) {
|
|
|
376
417
|
},
|
|
377
418
|
dom_eval: async (cdp, params) => params.frame === undefined
|
|
378
419
|
? evaluateScript(cdp, params.script)
|
|
379
|
-
: evaluateInFrame(cdp, pageWebSocketUrl(store), params.script, params.frame),
|
|
380
|
-
dom_frames: async (cdp) =>
|
|
420
|
+
: evaluateInFrame(cdp, pageWebSocketUrl(store), params.script, params.frame, listedFrameIds),
|
|
421
|
+
dom_frames: async (cdp) => {
|
|
422
|
+
const { frames, frameIds } = await listFrames(cdp, pageWebSocketUrl(store));
|
|
423
|
+
listedFrameIds = frameIds;
|
|
424
|
+
return { frames };
|
|
425
|
+
},
|
|
381
426
|
dom_fill: async (cdp, params) => interact(cdp, async () => onScriptTarget(cdp, params, (target) => withActionStability(cdp, () => fillElement(target.cdp, target.selector, params.value, filterDefined({ index: target.index, blur: params.blur, cwd: params.cwd })), params.wait !== false))),
|
|
382
|
-
dom_click: async (cdp, params) => interact(cdp, async () => onScriptTarget(cdp, params, (target) => withActionStability(cdp, () => clickElement(target.cdp, target.selector, filterDefined({
|
|
427
|
+
dom_click: async (cdp, params) => interact(cdp, async () => onScriptTarget(cdp, params, (target) => withActionStability(cdp, () => clickElement(target.cdp, target.selector, filterDefined({
|
|
428
|
+
index: target.index,
|
|
429
|
+
action: params.action,
|
|
430
|
+
strict: params.strict,
|
|
431
|
+
})), params.wait !== false)), {
|
|
383
432
|
detectNoEffect: params.wait !== false && params.action !== 'hover' && params.action !== 'right',
|
|
433
|
+
reportShown: params.action === 'hover',
|
|
434
|
+
detectUnsettled: params.wait !== false && params.action !== 'hover',
|
|
384
435
|
}),
|
|
385
436
|
dom_submit: async (cdp, params) => withTriggeredRequestCount(await interact(cdp, async () => onScriptTarget(cdp, params, (target) => submitForm(target.cdp, target.selector, {
|
|
386
437
|
...filterDefined({
|
|
@@ -395,7 +446,7 @@ export function createCommandRegistry(store) {
|
|
|
395
446
|
index: target.index,
|
|
396
447
|
times: params.times,
|
|
397
448
|
modifiers: params.modifiers,
|
|
398
|
-
})), params.wait !== false))),
|
|
449
|
+
})), params.wait !== false)), { reportShown: true, detectUnsettled: params.wait !== false }),
|
|
399
450
|
dom_scroll: async (cdp, params) => interact(cdp, async () => onScriptTarget(cdp, params, (target) => withActionStability(cdp, () => scrollPage(target.cdp, target.selector || undefined, filterDefined({
|
|
400
451
|
index: target.index,
|
|
401
452
|
down: params.down,
|
|
@@ -407,11 +458,16 @@ export function createCommandRegistry(store) {
|
|
|
407
458
|
})), params.wait !== false))),
|
|
408
459
|
dom_listeners: async (cdp, params) => withBusyPageRecovery(cdp, inspectEventListeners(cdp, params)),
|
|
409
460
|
dom_layout: async (cdp, params) => withBusyPageRecovery(cdp, inspectLayout(cdp, params)),
|
|
461
|
+
dom_inspect: async (cdp, params) => withBusyPageRecovery(cdp, inspectElement(cdp, params)),
|
|
410
462
|
dom_wait: async (cdp, params) => waitForCondition(cdp, params),
|
|
411
463
|
page_navigate: async (cdp, params) => interact(cdp, () => navigatePage(cdp, params.action, {
|
|
412
464
|
...filterDefined({ url: params.url, wait: params.wait }),
|
|
413
465
|
pendingRequests: () => store.pendingNetworkRequests.values(),
|
|
414
466
|
}), { reportRequests: false, reportEffects: false }),
|
|
467
|
+
page_emulate: async (cdp, params) => {
|
|
468
|
+
const emulated = await emulatePage(cdp, emulation.get(), params, emulation.set);
|
|
469
|
+
return { emulated, ...(await pageAppearance(cdp)) };
|
|
470
|
+
},
|
|
415
471
|
dom_form_discover: async (cdp) => {
|
|
416
472
|
const response = await withBusyPageRecovery(cdp, cdp.send('Runtime.evaluate', {
|
|
417
473
|
expression: FORM_DISCOVERY_SCRIPT,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Running page interactions (fill, click, submit, pressKey, scroll) one at a
|
|
3
|
-
* time, reporting the dialogs, network requests and page changes they caused
|
|
3
|
+
* time, reporting the dialogs, network requests and page changes they caused,
|
|
4
|
+
* and whether the page was still changing when they returned.
|
|
4
5
|
*/
|
|
5
6
|
import type { TelemetryStore } from './TelemetryStore.js';
|
|
6
7
|
import type { CDPConnection } from '../../connection/cdp.js';
|
|
@@ -28,6 +29,17 @@ export interface InteractionOptions {
|
|
|
28
29
|
* whose effect shows in the DOM (click, submit) and that waited for it
|
|
29
30
|
*/
|
|
30
31
|
detectNoEffect?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* List the elements it showed (`shown`): for hover and key presses, whose
|
|
34
|
+
* effect is often a menu, tooltip or new item rather than a message
|
|
35
|
+
*/
|
|
36
|
+
reportShown?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Say when the page was still changing as it returned (`settled: false`
|
|
39
|
+
* with `pending`): for actions that start app transitions (click, key
|
|
40
|
+
* press) and waited for the network
|
|
41
|
+
*/
|
|
42
|
+
detectUnsettled?: boolean;
|
|
31
43
|
}
|
|
32
44
|
/** Runs one interaction after the previous one finished */
|
|
33
45
|
export type InteractionRunner = <T extends object>(cdp: CDPConnection, action: () => Promise<T>, options?: InteractionOptions) => Promise<T & InteractionReport>;
|
|
@@ -40,10 +52,11 @@ export type InteractionRunner = <T extends object>(cdp: CDPConnection, action: (
|
|
|
40
52
|
* from the page (without waiting: during a pending navigation that takes until
|
|
41
53
|
* the new page commits), and the dialogs it opened, what it changed on the
|
|
42
54
|
* page (see {@link watchActionEffects}) and the network requests it
|
|
43
|
-
* triggered (see {@link watchTriggeredRequests}) are added to its result
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
55
|
+
* triggered (see {@link watchTriggeredRequests}) are added to its result,
|
|
56
|
+
* and, when asked, what the page was still working on (see
|
|
57
|
+
* {@link pendingChanges}). They are attributed by time: a dialog or request
|
|
58
|
+
* started by a page timer or a navigation started earlier is reported by
|
|
59
|
+
* whichever interaction is running then.
|
|
47
60
|
*
|
|
48
61
|
* @param store - Session store recording accepted dialogs and network requests
|
|
49
62
|
* @returns Interaction runner
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Running page interactions (fill, click, submit, pressKey, scroll) one at a
|
|
3
|
-
* time, reporting the dialogs, network requests and page changes they caused
|
|
3
|
+
* time, reporting the dialogs, network requests and page changes they caused,
|
|
4
|
+
* and whether the page was still changing when they returned.
|
|
4
5
|
*/
|
|
5
|
-
import { watchActionEffects } from '../../runtime/dom/actionEffects.js';
|
|
6
|
+
import { pendingChanges, watchActionEffects } from '../../runtime/dom/actionEffects.js';
|
|
6
7
|
import { UNBIND_TARGET_SCRIPT } from '../../runtime/dom/targetNode.js';
|
|
7
8
|
import { createLogger } from '../../ui/logging/index.js';
|
|
8
9
|
import { getErrorMessage } from '../../utils/errors.js';
|
|
@@ -26,10 +27,11 @@ function succeeded(result) {
|
|
|
26
27
|
* from the page (without waiting: during a pending navigation that takes until
|
|
27
28
|
* the new page commits), and the dialogs it opened, what it changed on the
|
|
28
29
|
* page (see {@link watchActionEffects}) and the network requests it
|
|
29
|
-
* triggered (see {@link watchTriggeredRequests}) are added to its result
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* triggered (see {@link watchTriggeredRequests}) are added to its result,
|
|
31
|
+
* and, when asked, what the page was still working on (see
|
|
32
|
+
* {@link pendingChanges}). They are attributed by time: a dialog or request
|
|
33
|
+
* started by a page timer or a navigation started earlier is reported by
|
|
34
|
+
* whichever interaction is running then.
|
|
33
35
|
*
|
|
34
36
|
* @param store - Session store recording accepted dialogs and network requests
|
|
35
37
|
* @returns Interaction runner
|
|
@@ -44,17 +46,25 @@ export function createInteractionRunner(store) {
|
|
|
44
46
|
try {
|
|
45
47
|
const result = await action();
|
|
46
48
|
const dialogs = store.dialogs.slice(firstDialog);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (!succeeded(result))
|
|
50
|
+
return { ...result, ...(dialogs.length > 0 && { dialogs }) };
|
|
51
|
+
const collected = await effects?.collect({
|
|
52
|
+
dialogs: dialogs.length,
|
|
53
|
+
detectNoEffect: options.detectNoEffect === true,
|
|
54
|
+
reportShown: options.reportShown === true,
|
|
55
|
+
detectUnsettled: options.detectUnsettled === true,
|
|
56
|
+
});
|
|
57
|
+
const { work, ...changes } = collected ?? {};
|
|
58
|
+
const requests = collectRequests?.();
|
|
59
|
+
const pending = options.detectUnsettled && work
|
|
60
|
+
? pendingChanges(work, requests?.triggeredRequests)
|
|
52
61
|
: undefined;
|
|
53
62
|
return {
|
|
54
63
|
...result,
|
|
55
64
|
...(dialogs.length > 0 && { dialogs }),
|
|
56
65
|
...changes,
|
|
57
|
-
...(
|
|
66
|
+
...(pending && { settled: false, pending }),
|
|
67
|
+
...requests,
|
|
58
68
|
};
|
|
59
69
|
}
|
|
60
70
|
finally {
|