playwriter 0.0.63 → 0.0.89
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/a11y-client.js +18 -8
- package/dist/aria-snapshot.d.ts +41 -3
- package/dist/aria-snapshot.d.ts.map +1 -1
- package/dist/aria-snapshot.js +134 -55
- 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 +492 -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 +297 -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 +287 -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 +450 -377
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/readability.js +16 -2
- 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 +45 -11
- package/dist/relay-client.js.map +1 -1
- package/dist/relay-core.test.d.ts.map +1 -1
- package/dist/relay-core.test.js +515 -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 +169 -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 +66 -4
- package/dist/screen-recording.d.ts.map +1 -1
- package/dist/screen-recording.js +150 -13
- package/dist/screen-recording.js.map +1 -1
- package/dist/screen-recording.test.d.ts +2 -0
- package/dist/screen-recording.test.d.ts.map +1 -0
- package/dist/screen-recording.test.js +102 -0
- package/dist/screen-recording.test.js.map +1 -0
- 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 +306 -117
- package/src/aria-snapshot.unit.test.ts +199 -141
- package/src/aria-snapshots/github-interactive.txt +2 -0
- package/src/aria-snapshots/github-raw.txt +5 -1
- package/src/aria-snapshots/hackernews-interactive.txt +238 -241
- package/src/aria-snapshots/hackernews-raw.txt +265 -269
- 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 +1059 -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 +374 -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 +369 -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 +113 -0
- package/src/recording-relay.ts +20 -12
- package/src/relay-client.ts +85 -18
- package/src/relay-core.test.ts +1117 -578
- package/src/relay-navigation.test.ts +648 -483
- 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.test.ts +111 -0
- package/src/screen-recording.ts +256 -31
- package/src/skill.md +476 -396
- package/src/snapshot-tools.test.ts +580 -528
- package/src/snapshots/shadcn-ui-accessibility-full.md +8 -8
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +8 -8
- 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/a11y-client.js
CHANGED
|
@@ -3,27 +3,37 @@
|
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
7
9
|
var __toCommonJS = (from) => {
|
|
8
|
-
var entry = __moduleCache.get(from), desc;
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
9
11
|
if (entry)
|
|
10
12
|
return entry;
|
|
11
13
|
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
17
22
|
__moduleCache.set(from, entry);
|
|
18
23
|
return entry;
|
|
19
24
|
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
20
30
|
var __export = (target, all) => {
|
|
21
31
|
for (var name in all)
|
|
22
32
|
__defProp(target, name, {
|
|
23
33
|
get: all[name],
|
|
24
34
|
enumerable: true,
|
|
25
35
|
configurable: true,
|
|
26
|
-
set: (
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
27
37
|
});
|
|
28
38
|
};
|
|
29
39
|
|
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) {
|
|
@@ -845,7 +927,9 @@ export async function getAriaSnapshot({ page, frame, locator, refFilter, interac
|
|
|
845
927
|
}, scopeAttr);
|
|
846
928
|
}
|
|
847
929
|
if (oopifSessionId) {
|
|
848
|
-
await session.send('Target.detachFromTarget', { sessionId: oopifSessionId }).catch(() => {
|
|
930
|
+
await session.send('Target.detachFromTarget', { sessionId: oopifSessionId }).catch((e) => {
|
|
931
|
+
console.error('[aria-snapshot] Failed to detach OOPIF session:', oopifSessionId, e);
|
|
932
|
+
});
|
|
849
933
|
}
|
|
850
934
|
if (!cdp) {
|
|
851
935
|
await session.detach();
|
|
@@ -874,7 +958,7 @@ function isTruthy(value) {
|
|
|
874
958
|
}
|
|
875
959
|
async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POSITION_CONCURRENCY, logger, cdp, }) {
|
|
876
960
|
const log = logger?.info ?? logger?.error ?? console.error;
|
|
877
|
-
const session = cdp || await getCDPSessionForPage({ page });
|
|
961
|
+
const session = cdp || (await getCDPSessionForPage({ page }));
|
|
878
962
|
const sema = new Sema(maxConcurrency);
|
|
879
963
|
const labelRefs = refs.filter((ref) => {
|
|
880
964
|
return Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role);
|
|
@@ -892,9 +976,13 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
|
|
|
892
976
|
await sema.acquire();
|
|
893
977
|
try {
|
|
894
978
|
const response = await Promise.race([
|
|
895
|
-
session.send('DOM.getBoxModel', {
|
|
979
|
+
session.send('DOM.getBoxModel', {
|
|
980
|
+
backendNodeId: ref.backendNodeId,
|
|
981
|
+
}),
|
|
896
982
|
new Promise((resolve) => {
|
|
897
|
-
setTimeout(() => {
|
|
983
|
+
setTimeout(() => {
|
|
984
|
+
resolve(null);
|
|
985
|
+
}, BOX_MODEL_TIMEOUT_MS);
|
|
898
986
|
}),
|
|
899
987
|
]);
|
|
900
988
|
completed++;
|
|
@@ -949,7 +1037,7 @@ async function getLabelBoxesForRefs({ page, refs, maxConcurrency = MAX_LABEL_POS
|
|
|
949
1037
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
950
1038
|
* ```
|
|
951
1039
|
*/
|
|
952
|
-
export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger }) {
|
|
1040
|
+
export async function showAriaRefLabels({ page, locator, interactiveOnly = true, logger, }) {
|
|
953
1041
|
const startTime = Date.now();
|
|
954
1042
|
const log = logger?.info ?? logger?.error ?? console.error;
|
|
955
1043
|
log(`[showAriaRefLabels] starting...`);
|
|
@@ -984,7 +1072,8 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
|
|
|
984
1072
|
}
|
|
985
1073
|
if (a11y?.computeA11ySnapshot) {
|
|
986
1074
|
const rootElement = root || document.body;
|
|
987
|
-
return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true })
|
|
1075
|
+
return a11y.computeA11ySnapshot({ root: rootElement, interactiveOnly: intOnly, renderLabels: true })
|
|
1076
|
+
.labelCount;
|
|
988
1077
|
}
|
|
989
1078
|
throw new Error('a11y client not loaded');
|
|
990
1079
|
}, { entries: shortLabels, root: rootHandle, interactiveOnly });
|
|
@@ -1035,7 +1124,7 @@ export async function hideAriaRefLabels({ page }) {
|
|
|
1035
1124
|
* await page.locator('[data-testid="submit-btn"]').click()
|
|
1036
1125
|
* ```
|
|
1037
1126
|
*/
|
|
1038
|
-
export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger }) {
|
|
1127
|
+
export async function screenshotWithAccessibilityLabels({ page, locator, interactiveOnly = true, collector, logger, }) {
|
|
1039
1128
|
const log = logger?.info ?? logger?.error;
|
|
1040
1129
|
const showLabelsStart = Date.now();
|
|
1041
1130
|
const { snapshot, labelCount } = await showAriaRefLabels({ page, locator, interactiveOnly, logger });
|
|
@@ -1053,15 +1142,12 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
|
|
|
1053
1142
|
}
|
|
1054
1143
|
const screenshotPath = path.join(tmpDir, filename);
|
|
1055
1144
|
// 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;
|
|
1145
|
+
const viewport = (await page.evaluate('({ width: window.innerWidth, height: window.innerHeight })'));
|
|
1060
1146
|
// Check if sharp is available for resizing
|
|
1061
1147
|
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,
|
|
1148
|
+
// Clip dimensions: if sharp unavailable, limit capture area to LLM_MAX_DIMENSION
|
|
1149
|
+
const clipWidth = sharp ? viewport.width : Math.min(viewport.width, LLM_MAX_DIMENSION);
|
|
1150
|
+
const clipHeight = sharp ? viewport.height : Math.min(viewport.height, LLM_MAX_DIMENSION);
|
|
1065
1151
|
// Take viewport screenshot with scale: 'css' to ignore device pixel ratio
|
|
1066
1152
|
const screenshotStart = Date.now();
|
|
1067
1153
|
const rawBuffer = await page.screenshot({
|
|
@@ -1073,23 +1159,16 @@ export async function screenshotWithAccessibilityLabels({ page, locator, interac
|
|
|
1073
1159
|
if (log) {
|
|
1074
1160
|
log(`page.screenshot: ${Date.now() - screenshotStart}ms`);
|
|
1075
1161
|
}
|
|
1076
|
-
// Resize with
|
|
1162
|
+
// Resize with resizeImage if sharp available, otherwise use clipped raw buffer
|
|
1077
1163
|
const resizeStart = Date.now();
|
|
1078
1164
|
const buffer = await (async () => {
|
|
1079
1165
|
if (!sharp) {
|
|
1080
|
-
logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max',
|
|
1166
|
+
logger?.error?.('[playwriter] sharp not available, using clipped screenshot (max', LLM_MAX_DIMENSION, 'px)');
|
|
1081
1167
|
return rawBuffer;
|
|
1082
1168
|
}
|
|
1083
1169
|
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();
|
|
1170
|
+
const result = await resizeImage({ input: rawBuffer });
|
|
1171
|
+
return result.buffer;
|
|
1093
1172
|
}
|
|
1094
1173
|
catch (err) {
|
|
1095
1174
|
logger?.error?.('[playwriter] sharp resize failed, using raw buffer:', err);
|