playwriter 0.0.63 → 0.0.80
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/dist/aria-snapshot.d.ts +41 -3
- package/dist/aria-snapshot.d.ts.map +1 -1
- package/dist/aria-snapshot.js +131 -54
- package/dist/aria-snapshot.js.map +1 -1
- package/dist/aria-snapshot.test.js +5 -2
- package/dist/aria-snapshot.test.js.map +1 -1
- package/dist/aria-snapshot.unit.test.js +83 -41
- package/dist/aria-snapshot.unit.test.js.map +1 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
- package/dist/bippy.js +1 -1
- package/dist/cdp-log.d.ts +1 -1
- package/dist/cdp-log.d.ts.map +1 -1
- package/dist/cdp-log.js +1 -1
- package/dist/cdp-log.js.map +1 -1
- package/dist/cdp-relay.d.ts.map +1 -1
- package/dist/cdp-relay.js +408 -298
- package/dist/cdp-relay.js.map +1 -1
- package/dist/cdp-session.d.ts.map +1 -1
- package/dist/cdp-session.js.map +1 -1
- package/dist/cdp-types.d.ts.map +1 -1
- package/dist/cdp-types.js +7 -7
- package/dist/cdp-types.js.map +1 -1
- package/dist/clean-html.d.ts.map +1 -1
- package/dist/clean-html.js +4 -5
- package/dist/clean-html.js.map +1 -1
- package/dist/cli.js +45 -27
- package/dist/cli.js.map +1 -1
- package/dist/create-logger.d.ts.map +1 -1
- package/dist/create-logger.js +3 -1
- package/dist/create-logger.js.map +1 -1
- package/dist/debugger-examples-types.d.ts.map +1 -1
- package/dist/debugger.d.ts.map +1 -1
- package/dist/debugger.js +1 -3
- package/dist/debugger.js.map +1 -1
- package/dist/diff-utils.d.ts.map +1 -1
- package/dist/diff-utils.js +1 -4
- package/dist/diff-utils.js.map +1 -1
- package/dist/editor-api.md +12 -2
- package/dist/editor-examples.d.ts +1 -1
- package/dist/editor-examples.d.ts.map +1 -1
- package/dist/editor-examples.js +1 -1
- package/dist/editor-examples.js.map +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1 -1
- package/dist/editor.js.map +1 -1
- package/dist/executor.d.ts +26 -3
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +295 -64
- package/dist/executor.js.map +1 -1
- package/dist/executor.unit.test.js +38 -1
- package/dist/executor.unit.test.js.map +1 -1
- package/dist/extension-connection.test.js +139 -36
- package/dist/extension-connection.test.js.map +1 -1
- package/dist/ffmpeg.d.ts +148 -0
- package/dist/ffmpeg.d.ts.map +1 -0
- package/dist/ffmpeg.js +523 -0
- package/dist/ffmpeg.js.map +1 -0
- package/dist/ghost-browser.d.ts.map +1 -1
- package/dist/ghost-browser.js.map +1 -1
- package/dist/ghost-cursor-client.js +281 -0
- package/dist/ghost-cursor.d.ts +27 -0
- package/dist/ghost-cursor.d.ts.map +1 -0
- package/dist/ghost-cursor.js +63 -0
- package/dist/ghost-cursor.js.map +1 -0
- package/dist/htmlrewrite.d.ts.map +1 -1
- package/dist/htmlrewrite.js +17 -55
- package/dist/htmlrewrite.js.map +1 -1
- package/dist/htmlrewrite.test.js.map +1 -1
- package/dist/kill-port.d.ts.map +1 -1
- package/dist/kill-port.js +1 -3
- package/dist/kill-port.js.map +1 -1
- package/dist/locator-selector.test.d.ts +2 -0
- package/dist/locator-selector.test.d.ts.map +1 -0
- package/dist/locator-selector.test.js +96 -0
- package/dist/locator-selector.test.js.map +1 -0
- package/dist/mcp-client.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +8 -3
- package/dist/mcp.js.map +1 -1
- package/dist/on-mouse-action.test.d.ts +2 -0
- package/dist/on-mouse-action.test.d.ts.map +1 -0
- package/dist/on-mouse-action.test.js +155 -0
- package/dist/on-mouse-action.test.js.map +1 -0
- package/dist/page-markdown.js +4 -4
- package/dist/page-markdown.js.map +1 -1
- package/dist/prompt.md +594 -255
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/readability.js +1 -1
- package/dist/recording-ghost-cursor.d.ts +41 -0
- package/dist/recording-ghost-cursor.d.ts.map +1 -0
- package/dist/recording-ghost-cursor.js +79 -0
- package/dist/recording-ghost-cursor.js.map +1 -0
- package/dist/recording-relay.d.ts.map +1 -1
- package/dist/recording-relay.js +8 -8
- package/dist/recording-relay.js.map +1 -1
- package/dist/relay-client.d.ts +17 -4
- package/dist/relay-client.d.ts.map +1 -1
- package/dist/relay-client.js +44 -10
- package/dist/relay-client.js.map +1 -1
- package/dist/relay-core.test.d.ts.map +1 -1
- package/dist/relay-core.test.js +187 -26
- package/dist/relay-core.test.js.map +1 -1
- package/dist/relay-navigation.test.d.ts.map +1 -1
- package/dist/relay-navigation.test.js +54 -31
- package/dist/relay-navigation.test.js.map +1 -1
- package/dist/relay-session.test.d.ts.map +1 -1
- package/dist/relay-session.test.js +113 -65
- package/dist/relay-session.test.js.map +1 -1
- package/dist/relay-state.d.ts +158 -0
- package/dist/relay-state.d.ts.map +1 -0
- package/dist/relay-state.js +306 -0
- package/dist/relay-state.js.map +1 -0
- package/dist/relay-state.test.d.ts +2 -0
- package/dist/relay-state.test.d.ts.map +1 -0
- package/dist/relay-state.test.js +472 -0
- package/dist/relay-state.test.js.map +1 -0
- package/dist/scoped-fs.d.ts.map +1 -1
- package/dist/scoped-fs.js.map +1 -1
- package/dist/screen-recording.d.ts +42 -4
- package/dist/screen-recording.d.ts.map +1 -1
- package/dist/screen-recording.js +88 -13
- package/dist/screen-recording.js.map +1 -1
- package/dist/selector-generator.js +1 -1
- package/dist/snapshot-tools.test.js +71 -28
- package/dist/snapshot-tools.test.js.map +1 -1
- package/dist/start-relay-server.d.ts +1 -1
- package/dist/start-relay-server.d.ts.map +1 -1
- package/dist/start-relay-server.js +1 -1
- package/dist/start-relay-server.js.map +1 -1
- package/dist/styles-api.md +8 -1
- package/dist/styles-examples.d.ts +1 -1
- package/dist/styles-examples.d.ts.map +1 -1
- package/dist/styles-examples.js +1 -1
- package/dist/styles-examples.js.map +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +1 -3
- package/dist/styles.js.map +1 -1
- package/dist/test-declarations.d.ts.map +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +7 -5
- package/dist/test-utils.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/dist/wait-for-page-load.d.ts.map +1 -1
- package/dist/wait-for-page-load.js +1 -1
- package/dist/wait-for-page-load.js.map +1 -1
- package/package.json +4 -3
- package/src/a11y-client.ts +5 -4
- package/src/aria-snapshot.test.ts +5 -2
- package/src/aria-snapshot.ts +303 -116
- package/src/aria-snapshot.unit.test.ts +199 -141
- package/src/aria-snapshots/github-raw.txt +1 -1
- package/src/aria-snapshots/hackernews-interactive.txt +240 -240
- package/src/aria-snapshots/hackernews-raw.txt +270 -270
- package/src/assets/aria-labels-example.png +0 -0
- package/src/assets/aria-labels-github.png +0 -0
- package/src/assets/aria-labels-hacker-news.png +0 -0
- package/src/assets/aria-labels-old-reddit.png +0 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
- package/src/cdp-log.ts +4 -1
- package/src/cdp-relay.ts +949 -737
- package/src/cdp-session.ts +12 -3
- package/src/cdp-types.ts +51 -51
- package/src/clean-html.ts +4 -5
- package/src/cli.ts +82 -55
- package/src/create-logger.ts +5 -3
- package/src/debugger-examples-types.ts +4 -1
- package/src/debugger.ts +1 -5
- package/src/diff-utils.ts +2 -5
- package/src/editor-examples.ts +11 -1
- package/src/editor.ts +10 -2
- package/src/executor.ts +372 -73
- package/src/executor.unit.test.ts +48 -1
- package/src/extension-connection.test.ts +612 -488
- package/src/ffmpeg.ts +769 -0
- package/src/ghost-browser.ts +4 -6
- package/src/ghost-cursor-client.ts +368 -0
- package/src/ghost-cursor.ts +110 -0
- package/src/htmlrewrite.test.ts +6 -2
- package/src/htmlrewrite.ts +348 -386
- package/src/kill-port.ts +1 -3
- package/src/locator-selector.test.ts +115 -0
- package/src/mcp-client.ts +1 -1
- package/src/mcp.ts +21 -15
- package/src/on-mouse-action.test.ts +196 -0
- package/src/page-markdown.ts +7 -7
- package/src/protocol.ts +73 -57
- package/src/recording-ghost-cursor.ts +107 -0
- package/src/recording-relay.ts +20 -12
- package/src/relay-client.ts +84 -17
- package/src/relay-core.test.ts +761 -583
- package/src/relay-navigation.test.ts +517 -484
- package/src/relay-session.test.ts +984 -929
- package/src/relay-state.test.ts +570 -0
- package/src/relay-state.ts +497 -0
- package/src/resource.md +21 -49
- package/src/scoped-fs.ts +9 -3
- package/src/screen-recording.ts +175 -31
- package/src/skill.md +619 -271
- package/src/snapshot-tools.test.ts +580 -528
- package/src/snapshots/shadcn-ui-accessibility-full.md +181 -183
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +119 -121
- package/src/start-relay-server.ts +14 -11
- package/src/styles-examples.ts +8 -1
- package/src/styles.ts +20 -21
- package/src/test-declarations.ts +6 -6
- package/src/test-utils.ts +104 -91
- package/src/utils.ts +2 -1
- package/src/wait-for-page-load.ts +6 -1
package/dist/aria-snapshot.d.ts
CHANGED
|
@@ -26,6 +26,44 @@ export interface ScreenshotResult {
|
|
|
26
26
|
snapshot: string;
|
|
27
27
|
labelCount: number;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* LLM-optimal max dimension. Claude auto-resizes images larger than 1568px
|
|
31
|
+
* on any edge, adding latency. Token cost: (width * height) / 750.
|
|
32
|
+
*/
|
|
33
|
+
export declare const LLM_MAX_DIMENSION = 1568;
|
|
34
|
+
export interface ResizeImageOptions {
|
|
35
|
+
/** Input: file path or Buffer */
|
|
36
|
+
input: string | Buffer;
|
|
37
|
+
/** Max pixels on longest edge. Default 1568 (Claude-optimal).
|
|
38
|
+
* Ignored if explicit width/height provided. */
|
|
39
|
+
maxDimension?: number;
|
|
40
|
+
/** Explicit target width in px (aspect ratio preserved unless both width+height set) */
|
|
41
|
+
width?: number;
|
|
42
|
+
/** Explicit target height in px */
|
|
43
|
+
height?: number;
|
|
44
|
+
/** How to fit when both width+height specified. Default 'inside' (preserve aspect ratio, no crop) */
|
|
45
|
+
fit?: 'inside' | 'cover' | 'contain' | 'fill';
|
|
46
|
+
/** JPEG quality 1-100. Default 80 */
|
|
47
|
+
quality?: number;
|
|
48
|
+
/** Output file path. Defaults to overwriting the input file (when input is a path) */
|
|
49
|
+
output?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface ResizeImageResult {
|
|
52
|
+
buffer: Buffer;
|
|
53
|
+
mimeType: 'image/jpeg';
|
|
54
|
+
/** Only set if output path was provided */
|
|
55
|
+
path?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resize an image using sharp. Useful for shrinking screenshots before reading
|
|
59
|
+
* them back into context so they consume fewer tokens.
|
|
60
|
+
*
|
|
61
|
+
* Default behavior (no width/height): fits within 1568×1568px, preserving
|
|
62
|
+
* aspect ratio, never upscales. This is optimal for Claude vision.
|
|
63
|
+
*
|
|
64
|
+
* Explicit width/height: resizes to those dimensions using the fit strategy.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resizeImage(options: ResizeImageOptions): Promise<ResizeImageResult>;
|
|
29
67
|
export interface AriaSnapshotResult {
|
|
30
68
|
snapshot: string;
|
|
31
69
|
tree: AriaSnapshotNode[];
|
|
@@ -140,7 +178,7 @@ export declare function finalizeSnapshotOutput(lines: SnapshotLine[], nodes: Sna
|
|
|
140
178
|
* await page.locator(selector).click()
|
|
141
179
|
* ```
|
|
142
180
|
*/
|
|
143
|
-
export declare function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly, cdp }: {
|
|
181
|
+
export declare function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly, cdp, }: {
|
|
144
182
|
page: Page;
|
|
145
183
|
frame?: Frame | FrameLocator;
|
|
146
184
|
locator?: Locator;
|
|
@@ -171,7 +209,7 @@ export declare function getAriaSnapshot({ page, frame, locator, refFilter, inter
|
|
|
171
209
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
172
210
|
* ```
|
|
173
211
|
*/
|
|
174
|
-
export declare function showAriaRefLabels({ page, locator, interactiveOnly, logger }: {
|
|
212
|
+
export declare function showAriaRefLabels({ page, locator, interactiveOnly, logger, }: {
|
|
175
213
|
page: Page;
|
|
176
214
|
locator?: Locator;
|
|
177
215
|
interactiveOnly?: boolean;
|
|
@@ -206,7 +244,7 @@ export declare function hideAriaRefLabels({ page }: {
|
|
|
206
244
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
207
245
|
* ```
|
|
208
246
|
*/
|
|
209
|
-
export declare function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly, collector, logger }: {
|
|
247
|
+
export declare function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly, collector, logger, }: {
|
|
210
248
|
page: Page;
|
|
211
249
|
locator?: Locator;
|
|
212
250
|
interactiveOnly?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aria-snapshot.d.ts","sourceRoot":"","sources":["../src/aria-snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAKhG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"aria-snapshot.d.ts","sourceRoot":"","sources":["../src/aria-snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/aria-snapshot.js
CHANGED
|
@@ -6,8 +6,12 @@ import { Sema } from 'async-sema';
|
|
|
6
6
|
import { getCDPSessionForPage } from './cdp-session.js';
|
|
7
7
|
// Import sharp at module level - resolves to null if not available
|
|
8
8
|
const sharpPromise = import('sharp')
|
|
9
|
-
.then((m) => {
|
|
10
|
-
|
|
9
|
+
.then((m) => {
|
|
10
|
+
return m.default;
|
|
11
|
+
})
|
|
12
|
+
.catch(() => {
|
|
13
|
+
return null;
|
|
14
|
+
});
|
|
11
15
|
export const DEFAULT_SNAPSHOT_FORMAT = 'raw';
|
|
12
16
|
// ============================================================================
|
|
13
17
|
// A11y Client Code Loading
|
|
@@ -29,6 +33,78 @@ async function ensureA11yClient(page) {
|
|
|
29
33
|
await page.evaluate(code);
|
|
30
34
|
}
|
|
31
35
|
}
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Image Resize Utility
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* LLM-optimal max dimension. Claude auto-resizes images larger than 1568px
|
|
41
|
+
* on any edge, adding latency. Token cost: (width * height) / 750.
|
|
42
|
+
*/
|
|
43
|
+
export const LLM_MAX_DIMENSION = 1568;
|
|
44
|
+
/**
|
|
45
|
+
* Resize an image using sharp. Useful for shrinking screenshots before reading
|
|
46
|
+
* them back into context so they consume fewer tokens.
|
|
47
|
+
*
|
|
48
|
+
* Default behavior (no width/height): fits within 1568×1568px, preserving
|
|
49
|
+
* aspect ratio, never upscales. This is optimal for Claude vision.
|
|
50
|
+
*
|
|
51
|
+
* Explicit width/height: resizes to those dimensions using the fit strategy.
|
|
52
|
+
*/
|
|
53
|
+
export async function resizeImage(options) {
|
|
54
|
+
const sharp = await sharpPromise;
|
|
55
|
+
if (!sharp) {
|
|
56
|
+
throw new Error('sharp is not installed — install it with: pnpm add sharp');
|
|
57
|
+
}
|
|
58
|
+
const inputBuffer = (() => {
|
|
59
|
+
if (Buffer.isBuffer(options.input)) {
|
|
60
|
+
return options.input;
|
|
61
|
+
}
|
|
62
|
+
return fs.readFileSync(options.input);
|
|
63
|
+
})();
|
|
64
|
+
const quality = options.quality ?? 80;
|
|
65
|
+
const hasExplicitDimensions = options.width !== undefined || options.height !== undefined;
|
|
66
|
+
const fit = options.fit ?? 'inside';
|
|
67
|
+
const resizeOpts = (() => {
|
|
68
|
+
if (hasExplicitDimensions) {
|
|
69
|
+
return {
|
|
70
|
+
width: options.width,
|
|
71
|
+
height: options.height,
|
|
72
|
+
fit,
|
|
73
|
+
withoutEnlargement: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const max = options.maxDimension ?? LLM_MAX_DIMENSION;
|
|
77
|
+
return {
|
|
78
|
+
width: max,
|
|
79
|
+
height: max,
|
|
80
|
+
fit,
|
|
81
|
+
withoutEnlargement: true,
|
|
82
|
+
};
|
|
83
|
+
})();
|
|
84
|
+
const buffer = await sharp(inputBuffer)
|
|
85
|
+
.resize(resizeOpts)
|
|
86
|
+
.jpeg({ quality })
|
|
87
|
+
.toBuffer();
|
|
88
|
+
// Default: overwrite input file. When input is a Buffer, no file is written
|
|
89
|
+
// unless output is explicitly set.
|
|
90
|
+
const outputPath = (() => {
|
|
91
|
+
if (options.output) {
|
|
92
|
+
return options.output;
|
|
93
|
+
}
|
|
94
|
+
if (typeof options.input === 'string') {
|
|
95
|
+
return options.input;
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
})();
|
|
99
|
+
if (outputPath) {
|
|
100
|
+
fs.writeFileSync(outputPath, buffer);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
buffer,
|
|
104
|
+
mimeType: 'image/jpeg',
|
|
105
|
+
...(outputPath ? { path: outputPath } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
32
108
|
export function buildShortRefMap({ refs }) {
|
|
33
109
|
const map = new Map();
|
|
34
110
|
refs.forEach((entry, index) => {
|
|
@@ -58,9 +134,7 @@ const INTERACTIVE_ROLES = new Set([
|
|
|
58
134
|
'video',
|
|
59
135
|
'audio',
|
|
60
136
|
]);
|
|
61
|
-
const LABEL_ROLES = new Set([
|
|
62
|
-
'labeltext',
|
|
63
|
-
]);
|
|
137
|
+
const LABEL_ROLES = new Set(['labeltext']);
|
|
64
138
|
const MAX_LABEL_POSITION_CONCURRENCY = 24;
|
|
65
139
|
const BOX_MODEL_TIMEOUT_MS = 5000;
|
|
66
140
|
const CONTEXT_ROLES = new Set([
|
|
@@ -78,12 +152,7 @@ const CONTEXT_ROLES = new Set([
|
|
|
78
152
|
'row',
|
|
79
153
|
'cell',
|
|
80
154
|
]);
|
|
81
|
-
const SKIP_WRAPPER_ROLES = new Set([
|
|
82
|
-
'generic',
|
|
83
|
-
'group',
|
|
84
|
-
'none',
|
|
85
|
-
'presentation',
|
|
86
|
-
]);
|
|
155
|
+
const SKIP_WRAPPER_ROLES = new Set(['generic', 'group', 'none', 'presentation']);
|
|
87
156
|
const TEST_ID_ATTRS = [
|
|
88
157
|
'data-testid',
|
|
89
158
|
'data-test-id',
|
|
@@ -130,7 +199,7 @@ function buildLocatorFromStable(stable) {
|
|
|
130
199
|
const escaped = escapeLocatorValue(stable.value);
|
|
131
200
|
return `[${stable.attr}="${escaped}"]`;
|
|
132
201
|
}
|
|
133
|
-
function buildBaseLocator({ role, name, stable }) {
|
|
202
|
+
function buildBaseLocator({ role, name, stable, }) {
|
|
134
203
|
if (stable) {
|
|
135
204
|
return buildLocatorFromStable(stable);
|
|
136
205
|
}
|
|
@@ -158,7 +227,7 @@ function getAxRole(node) {
|
|
|
158
227
|
const role = getAxValueString(node.role);
|
|
159
228
|
return role.toLowerCase();
|
|
160
229
|
}
|
|
161
|
-
function buildSnapshotLine({ role, name, baseLocator, indent, hasChildren }) {
|
|
230
|
+
function buildSnapshotLine({ role, name, baseLocator, indent, hasChildren, }) {
|
|
162
231
|
const prefix = ' '.repeat(indent);
|
|
163
232
|
let text = `${prefix}- ${role}`;
|
|
164
233
|
if (name) {
|
|
@@ -199,13 +268,15 @@ export function buildRawSnapshotTree(options) {
|
|
|
199
268
|
}
|
|
200
269
|
const role = getAxRole(node);
|
|
201
270
|
const name = getAxValueString(node.name).trim();
|
|
202
|
-
const children = (node.childIds ?? [])
|
|
271
|
+
const children = (node.childIds ?? [])
|
|
272
|
+
.map((childId) => {
|
|
203
273
|
return buildRawSnapshotTree({
|
|
204
274
|
nodeId: childId,
|
|
205
275
|
axById: options.axById,
|
|
206
276
|
isNodeInScope: options.isNodeInScope,
|
|
207
277
|
});
|
|
208
|
-
})
|
|
278
|
+
})
|
|
279
|
+
.filter(isTruthy);
|
|
209
280
|
const inScope = options.isNodeInScope(node) || children.length > 0;
|
|
210
281
|
if (!inScope) {
|
|
211
282
|
return null;
|
|
@@ -429,7 +500,8 @@ export function finalizeSnapshotOutput(lines, nodes, shortRefMap) {
|
|
|
429
500
|
return acc;
|
|
430
501
|
}, []);
|
|
431
502
|
let lineLocatorIndex = 0;
|
|
432
|
-
const snapshot = lines
|
|
503
|
+
const snapshot = lines
|
|
504
|
+
.map((line) => {
|
|
433
505
|
let text = line.text;
|
|
434
506
|
if (line.baseLocator) {
|
|
435
507
|
const locator = locatorSequence[lineLocatorIndex];
|
|
@@ -440,7 +512,8 @@ export function finalizeSnapshotOutput(lines, nodes, shortRefMap) {
|
|
|
440
512
|
text += ':';
|
|
441
513
|
}
|
|
442
514
|
return text;
|
|
443
|
-
})
|
|
515
|
+
})
|
|
516
|
+
.join('\n');
|
|
444
517
|
let nodeLocatorIndex = 0;
|
|
445
518
|
const applyLocators = (items) => {
|
|
446
519
|
return items.map((item) => {
|
|
@@ -585,8 +658,8 @@ async function resolveFrame({ frame, page }) {
|
|
|
585
658
|
* await page.locator(selector).click()
|
|
586
659
|
* ```
|
|
587
660
|
*/
|
|
588
|
-
export async function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly = false, cdp }) {
|
|
589
|
-
const session = cdp || await getCDPSessionForPage({ page });
|
|
661
|
+
export async function getAriaSnapshot({ page, frame, locator, refFilter, interactiveOnly = false, cdp, }) {
|
|
662
|
+
const session = cdp || (await getCDPSessionForPage({ page }));
|
|
590
663
|
// Resolve FrameLocator to an actual Frame. FrameLocator (from locator.contentFrame())
|
|
591
664
|
// is a scoping helper without CDP access. We need the real Frame from page.frames()
|
|
592
665
|
// which has frameId() for OOPIF session attachment.
|
|
@@ -596,16 +669,16 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
596
669
|
let oopifSessionId = null;
|
|
597
670
|
const frameId = resolvedFrame?.frameId() ?? null;
|
|
598
671
|
if (frameId) {
|
|
599
|
-
const { targetInfos } = await session.send('Target.getTargets');
|
|
672
|
+
const { targetInfos } = (await session.send('Target.getTargets'));
|
|
600
673
|
const frameUrl = resolvedFrame.url();
|
|
601
674
|
const iframeTarget = targetInfos.find((t) => {
|
|
602
675
|
return t.type === 'iframe' && t.url === frameUrl;
|
|
603
676
|
});
|
|
604
677
|
if (iframeTarget) {
|
|
605
|
-
const { sessionId } = await session.send('Target.attachToTarget', {
|
|
678
|
+
const { sessionId } = (await session.send('Target.attachToTarget', {
|
|
606
679
|
targetId: iframeTarget.targetId,
|
|
607
680
|
flatten: true,
|
|
608
|
-
});
|
|
681
|
+
}));
|
|
609
682
|
oopifSessionId = sessionId;
|
|
610
683
|
await session.send('Runtime.runIfWaitingForDebugger', undefined, oopifSessionId);
|
|
611
684
|
}
|
|
@@ -623,7 +696,7 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
623
696
|
}, { attr: scopeAttr, value: scopeValue });
|
|
624
697
|
scopeApplied = true;
|
|
625
698
|
}
|
|
626
|
-
const { nodes: domNodes } = await session.send('DOM.getFlattenedDocument', { depth: -1, pierce: true }, oopifSessionId);
|
|
699
|
+
const { nodes: domNodes } = (await session.send('DOM.getFlattenedDocument', { depth: -1, pierce: true }, oopifSessionId));
|
|
627
700
|
const { domById, domByBackendId, childrenByParent } = buildDomIndex(domNodes);
|
|
628
701
|
let scopeRootNodeId = null;
|
|
629
702
|
let scopeRootBackendId = null;
|
|
@@ -636,11 +709,9 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
636
709
|
}
|
|
637
710
|
}
|
|
638
711
|
}
|
|
639
|
-
const allowedBackendIds = scopeRootNodeId
|
|
640
|
-
? buildBackendIdSet(scopeRootNodeId, childrenByParent, domById)
|
|
641
|
-
: null;
|
|
712
|
+
const allowedBackendIds = scopeRootNodeId ? buildBackendIdSet(scopeRootNodeId, childrenByParent, domById) : null;
|
|
642
713
|
const axParams = !oopifSessionId && frameId ? { frameId } : undefined;
|
|
643
|
-
const { nodes: axNodes } = await session.send('Accessibility.getFullAXTree', axParams, oopifSessionId);
|
|
714
|
+
const { nodes: axNodes } = (await session.send('Accessibility.getFullAXTree', axParams, oopifSessionId));
|
|
644
715
|
const axById = new Map();
|
|
645
716
|
for (const node of axNodes) {
|
|
646
717
|
axById.set(node.nodeId, node);
|
|
@@ -710,9 +781,11 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
710
781
|
const rootNode = axById.get(rootAxNodeId);
|
|
711
782
|
const rootRole = rootNode ? getAxRole(rootNode) : '';
|
|
712
783
|
const rawRoots = rootNode && (rootRole === 'rootwebarea' || rootRole === 'webarea') && rootNode.childIds
|
|
713
|
-
? rootNode.childIds
|
|
784
|
+
? rootNode.childIds
|
|
785
|
+
.map((childId) => {
|
|
714
786
|
return buildRawSnapshotTree({ nodeId: childId, axById, isNodeInScope });
|
|
715
|
-
})
|
|
787
|
+
})
|
|
788
|
+
.filter(isTruthy)
|
|
716
789
|
: [buildRawSnapshotTree({ nodeId: rootAxNodeId, axById, isNodeInScope })].filter(isTruthy);
|
|
717
790
|
const filtered = rawRoots.flatMap((rawNode) => {
|
|
718
791
|
if (interactiveOnly) {
|
|
@@ -791,7 +864,16 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
791
864
|
if (!target) {
|
|
792
865
|
return null;
|
|
793
866
|
}
|
|
794
|
-
const testIdAttrs = [
|
|
867
|
+
const testIdAttrs = [
|
|
868
|
+
'data-testid',
|
|
869
|
+
'data-test-id',
|
|
870
|
+
'data-test',
|
|
871
|
+
'data-cy',
|
|
872
|
+
'data-pw',
|
|
873
|
+
'data-qa',
|
|
874
|
+
'data-e2e',
|
|
875
|
+
'data-automation-id',
|
|
876
|
+
];
|
|
795
877
|
for (const attr of testIdAttrs) {
|
|
796
878
|
const value = target.getAttribute(attr);
|
|
797
879
|
if (value) {
|
|
@@ -874,7 +956,7 @@ function isTruthy(value) {
|
|
|
874
956
|
}
|
|
875
957
|
async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POSITION_CONCURRENCY, logger, cdp, }) {
|
|
876
958
|
const log = logger?.info ?? logger?.error ?? console.error;
|
|
877
|
-
const session = cdp || await getCDPSessionForPage({ page });
|
|
959
|
+
const session = cdp || (await getCDPSessionForPage({ page }));
|
|
878
960
|
const sema = new Sema(maxConcurrency);
|
|
879
961
|
const labelRefs = refs.filter((ref) => {
|
|
880
962
|
return Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role);
|
|
@@ -892,9 +974,13 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
|
|
|
892
974
|
await sema.acquire();
|
|
893
975
|
try {
|
|
894
976
|
const response = await Promise.race([
|
|
895
|
-
session.send('DOM.getBoxModel', {
|
|
977
|
+
session.send('DOM.getBoxModel', {
|
|
978
|
+
backendNodeId: ref.backendNodeId,
|
|
979
|
+
}),
|
|
896
980
|
new Promise((resolve) => {
|
|
897
|
-
setTimeout(() => {
|
|
981
|
+
setTimeout(() => {
|
|
982
|
+
resolve(null);
|
|
983
|
+
}, BOX_MODEL_TIMEOUT_MS);
|
|
898
984
|
}),
|
|
899
985
|
]);
|
|
900
986
|
completed++;
|
|
@@ -949,7 +1035,7 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
|
|
|
949
1035
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
950
1036
|
* ```
|
|
951
1037
|
*/
|
|
952
|
-
export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger }) {
|
|
1038
|
+
export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger, }) {
|
|
953
1039
|
const startTime = Date.now();
|
|
954
1040
|
const log = logger?.info ?? logger?.error ?? console.error;
|
|
955
1041
|
log(`[showAriaRefLabels] starting...`);
|
|
@@ -984,7 +1070,8 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
|
|
|
984
1070
|
}
|
|
985
1071
|
if (a11y?.computeA11ySnapshot) {
|
|
986
1072
|
const rootElement = root || document.body;
|
|
987
|
-
return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true })
|
|
1073
|
+
return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true })
|
|
1074
|
+
.labelCount;
|
|
988
1075
|
}
|
|
989
1076
|
throw new Error('a11y client not loaded');
|
|
990
1077
|
}, { entries: shortLabels, root: rootHandle, interactiveOnly });
|
|
@@ -1035,7 +1122,7 @@ export async function hideAriaRefLabels({ page }) {
|
|
|
1035
1122
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
1036
1123
|
* ```
|
|
1037
1124
|
*/
|
|
1038
|
-
export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger }) {
|
|
1125
|
+
export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger, }) {
|
|
1039
1126
|
const log = logger?.info ?? logger?.error;
|
|
1040
1127
|
const showLabelsStart = Date.now();
|
|
1041
1128
|
const { snapshot, labelCount } = await showAriaRefLabels({ page, locator, interactiveOnly, logger });
|
|
@@ -1053,15 +1140,12 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
|
|
|
1053
1140
|
}
|
|
1054
1141
|
const screenshotPath = path.join(tmpDir, filename);
|
|
1055
1142
|
// Get viewport size to clip screenshot to visible area
|
|
1056
|
-
const viewport = await page.evaluate('({ width: window.innerWidth, height: window.innerHeight })');
|
|
1057
|
-
// Max 1568px on any edge (larger gets auto-resized by Claude, adding latency)
|
|
1058
|
-
// Token formula: tokens = (width * height) / 750
|
|
1059
|
-
const MAX_DIMENSION = 1568;
|
|
1143
|
+
const viewport = (await page.evaluate('({ width: window.innerWidth, height: window.innerHeight })'));
|
|
1060
1144
|
// Check if sharp is available for resizing
|
|
1061
1145
|
const sharp = await sharpPromise;
|
|
1062
|
-
// Clip dimensions: if sharp unavailable, limit capture area to
|
|
1063
|
-
const clipWidth = sharp ? viewport.width : Math.min(viewport.width,
|
|
1064
|
-
const clipHeight = sharp ? viewport.height : Math.min(viewport.height,
|
|
1146
|
+
// Clip dimensions: if sharp unavailable, limit capture area to LLM_MAX_DIMENSION
|
|
1147
|
+
const clipWidth = sharp ? viewport.width : Math.min(viewport.width, LLM_MAX_DIMENSION);
|
|
1148
|
+
const clipHeight = sharp ? viewport.height : Math.min(viewport.height, LLM_MAX_DIMENSION);
|
|
1065
1149
|
// Take viewport screenshot with scale: 'css' to ignore device pixel ratio
|
|
1066
1150
|
const screenshotStart = Date.now();
|
|
1067
1151
|
const rawBuffer = await page.screenshot({
|
|
@@ -1073,23 +1157,16 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
|
|
|
1073
1157
|
if (log) {
|
|
1074
1158
|
log(`page.screenshot: ${Date.now() - screenshotStart}ms`);
|
|
1075
1159
|
}
|
|
1076
|
-
// Resize with
|
|
1160
|
+
// Resize with resizeImage if sharp available, otherwise use clipped raw buffer
|
|
1077
1161
|
const resizeStart = Date.now();
|
|
1078
1162
|
const buffer = await (async () => {
|
|
1079
1163
|
if (!sharp) {
|
|
1080
|
-
logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max',
|
|
1164
|
+
logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max', LLM_MAX_DIMENSION, 'px)');
|
|
1081
1165
|
return rawBuffer;
|
|
1082
1166
|
}
|
|
1083
1167
|
try {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
width: MAX_DIMENSION,
|
|
1087
|
-
height: MAX_DIMENSION,
|
|
1088
|
-
fit: 'inside', // Scale down to fit, preserving aspect ratio
|
|
1089
|
-
withoutEnlargement: true, // Don't upscale small images
|
|
1090
|
-
})
|
|
1091
|
-
.jpeg({ quality: 80 })
|
|
1092
|
-
.toBuffer();
|
|
1168
|
+
const result = await resizeImage({ input: rawBuffer });
|
|
1169
|
+
return result.buffer;
|
|
1093
1170
|
}
|
|
1094
1171
|
catch (err) {
|
|
1095
1172
|
logger?.error?.('[playwriter] sharp resize failed, using raw buffer:', err);
|