@dyyz1993/agent-browser 0.25.0 → 0.26.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/dist/__tests__/e2e/utils/test-helpers.d.ts +2 -2
- package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -1
- package/dist/__tests__/e2e/utils/test-helpers.js +6 -4
- package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -1
- package/dist/actions/advanced.d.ts +73 -0
- package/dist/actions/advanced.d.ts.map +1 -0
- package/dist/actions/advanced.js +390 -0
- package/dist/actions/advanced.js.map +1 -0
- package/dist/actions/context.d.ts +36 -0
- package/dist/actions/context.d.ts.map +1 -0
- package/dist/actions/context.js +164 -0
- package/dist/actions/context.js.map +1 -0
- package/dist/actions/crawl.d.ts +8 -0
- package/dist/actions/crawl.d.ts.map +1 -0
- package/dist/actions/crawl.js +290 -0
- package/dist/actions/crawl.js.map +1 -0
- package/dist/actions/elements.d.ts +11 -0
- package/dist/actions/elements.d.ts.map +1 -0
- package/dist/actions/elements.js +78 -0
- package/dist/actions/elements.js.map +1 -0
- package/dist/actions/flow.d.ts +4 -0
- package/dist/actions/flow.d.ts.map +1 -0
- package/dist/actions/flow.js +170 -0
- package/dist/actions/flow.js.map +1 -0
- package/dist/actions/index.d.ts +7 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +323 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/interact.d.ts +4 -0
- package/dist/actions/interact.d.ts.map +1 -0
- package/dist/actions/interact.js +162 -0
- package/dist/actions/interact.js.map +1 -0
- package/dist/actions/interaction.d.ts +31 -0
- package/dist/actions/interaction.d.ts.map +1 -0
- package/dist/actions/interaction.js +477 -0
- package/dist/actions/interaction.js.map +1 -0
- package/dist/actions/locators.d.ts +14 -0
- package/dist/actions/locators.d.ts.map +1 -0
- package/dist/actions/locators.js +310 -0
- package/dist/actions/locators.js.map +1 -0
- package/dist/actions/map.d.ts +4 -0
- package/dist/actions/map.d.ts.map +1 -0
- package/dist/actions/map.js +79 -0
- package/dist/actions/map.js.map +1 -0
- package/dist/actions/meta.d.ts +44 -0
- package/dist/actions/meta.d.ts.map +1 -0
- package/dist/actions/meta.js +190 -0
- package/dist/actions/meta.js.map +1 -0
- package/dist/actions/mouse.d.ts +8 -0
- package/dist/actions/mouse.d.ts.map +1 -0
- package/dist/actions/mouse.js +52 -0
- package/dist/actions/mouse.js.map +1 -0
- package/dist/actions/recorder.d.ts +20 -0
- package/dist/actions/recorder.d.ts.map +1 -0
- package/dist/actions/recorder.js +231 -0
- package/dist/actions/recorder.js.map +1 -0
- package/dist/actions/recording.d.ts +6 -0
- package/dist/actions/recording.d.ts.map +1 -0
- package/dist/actions/recording.js +22 -0
- package/dist/actions/recording.js.map +1 -0
- package/dist/actions/scrape.d.ts +10 -0
- package/dist/actions/scrape.d.ts.map +1 -0
- package/dist/actions/scrape.js +39 -0
- package/dist/actions/scrape.js.map +1 -0
- package/dist/actions/screencast.d.ts +8 -0
- package/dist/actions/screencast.d.ts.map +1 -0
- package/dist/actions/screencast.js +56 -0
- package/dist/actions/screencast.js.map +1 -0
- package/dist/actions/search.d.ts +4 -0
- package/dist/actions/search.d.ts.map +1 -0
- package/dist/actions/search.js +129 -0
- package/dist/actions/search.js.map +1 -0
- package/dist/actions/storage.d.ts +14 -0
- package/dist/actions/storage.d.ts.map +1 -0
- package/dist/actions/storage.js +63 -0
- package/dist/actions/storage.js.map +1 -0
- package/dist/actions/tabs.d.ts +16 -0
- package/dist/actions/tabs.d.ts.map +1 -0
- package/dist/actions/tabs.js +47 -0
- package/dist/actions/tabs.js.map +1 -0
- package/dist/actions/utils.d.ts +15 -0
- package/dist/actions/utils.d.ts.map +1 -0
- package/dist/actions/utils.js +234 -0
- package/dist/actions/utils.js.map +1 -0
- package/dist/browser/browser-manager.d.ts +249 -0
- package/dist/browser/browser-manager.d.ts.map +1 -0
- package/dist/browser/browser-manager.js +1251 -0
- package/dist/browser/browser-manager.js.map +1 -0
- package/dist/browser/index.d.ts +3 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +2 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/network-tracker.d.ts +39 -0
- package/dist/browser/network-tracker.d.ts.map +1 -0
- package/dist/browser/network-tracker.js +287 -0
- package/dist/browser/network-tracker.js.map +1 -0
- package/dist/browser/providers.d.ts +27 -0
- package/dist/browser/providers.d.ts.map +1 -0
- package/dist/browser/providers.js +293 -0
- package/dist/browser/providers.js.map +1 -0
- package/dist/browser/recorder-manager.d.ts +69 -0
- package/dist/browser/recorder-manager.d.ts.map +1 -0
- package/dist/browser/recorder-manager.js +755 -0
- package/dist/browser/recorder-manager.js.map +1 -0
- package/dist/browser/recording-manager.d.ts +46 -0
- package/dist/browser/recording-manager.d.ts.map +1 -0
- package/dist/browser/recording-manager.js +156 -0
- package/dist/browser/recording-manager.js.map +1 -0
- package/dist/browser/screencast-manager.d.ts +49 -0
- package/dist/browser/screencast-manager.d.ts.map +1 -0
- package/dist/browser/screencast-manager.js +131 -0
- package/dist/browser/screencast-manager.js.map +1 -0
- package/dist/browser/types.d.ts +101 -0
- package/dist/browser/types.d.ts.map +1 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/browser-events.d.ts +25 -0
- package/dist/browser-events.d.ts.map +1 -0
- package/dist/browser-events.js +15 -0
- package/dist/browser-events.js.map +1 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +140 -1
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/connection.d.ts.map +1 -1
- package/dist/cli/connection.js +15 -22
- package/dist/cli/connection.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +153 -3
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +72 -0
- package/dist/cli/output.js.map +1 -1
- package/dist/cli.js +3 -4
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +12 -13
- package/dist/daemon.js.map +1 -1
- package/dist/flow/exporters/playwright.d.ts +23 -1
- package/dist/flow/exporters/playwright.d.ts.map +1 -1
- package/dist/flow/exporters/playwright.js +333 -85
- package/dist/flow/exporters/playwright.js.map +1 -1
- package/dist/flow/exporters/python.d.ts +22 -0
- package/dist/flow/exporters/python.d.ts.map +1 -1
- package/dist/flow/exporters/python.js +325 -74
- package/dist/flow/exporters/python.js.map +1 -1
- package/dist/flow/exporters/selenium.d.ts.map +1 -1
- package/dist/flow/exporters/selenium.js +0 -1
- package/dist/flow/exporters/selenium.js.map +1 -1
- package/dist/flow/flow-executor.d.ts +1 -1
- package/dist/flow/flow-executor.d.ts.map +1 -1
- package/dist/flow/flow-executor.js +11 -11
- package/dist/flow/flow-executor.js.map +1 -1
- package/dist/flow/output.js.map +1 -1
- package/dist/flow/plugin-system.d.ts +1 -1
- package/dist/flow/plugin-system.d.ts.map +1 -1
- package/dist/flow/plugin-system.js +2 -2
- package/dist/flow/plugin-system.js.map +1 -1
- package/dist/flow/plugins/logging-plugin.js +1 -1
- package/dist/flow/plugins/logging-plugin.js.map +1 -1
- package/dist/flow/presets/console-capture.js +33 -14
- package/dist/flow/presets/fetch-capture.js +52 -23
- package/dist/flow/presets/sse-stream.js +35 -17
- package/dist/flow/presets/xhr-only.js +22 -12
- package/dist/flow/recorder-to-flow.d.ts.map +1 -1
- package/dist/flow/recorder-to-flow.js +1 -3
- package/dist/flow/recorder-to-flow.js.map +1 -1
- package/dist/flow/site-manager.d.ts.map +1 -1
- package/dist/flow/site-manager.js +6 -2
- package/dist/flow/site-manager.js.map +1 -1
- package/dist/human-mouse.d.ts +1 -1
- package/dist/human-mouse.d.ts.map +1 -1
- package/dist/human-mouse.js +2 -2
- package/dist/human-mouse.js.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +90 -0
- package/dist/protocol.js.map +1 -1
- package/dist/rc-config.js +4 -4
- package/dist/rc-config.js.map +1 -1
- package/dist/recorder/inject.js +31 -5
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +3 -4
- package/dist/snapshot.js.map +1 -1
- package/dist/stream-server-standalone.d.ts +1 -1
- package/dist/stream-server-standalone.d.ts.map +1 -1
- package/dist/stream-server-standalone.js +42 -23
- package/dist/stream-server-standalone.js.map +1 -1
- package/dist/stream-server.d.ts +1 -1
- package/dist/stream-server.d.ts.map +1 -1
- package/dist/stream-server.js +26 -21
- package/dist/stream-server.js.map +1 -1
- package/dist/test-live.js +9 -3
- package/dist/test-live.js.map +1 -1
- package/dist/types.d.ts +122 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
- package/scripts/README.md +66 -0
- package/scripts/copy-flow-presets.js +25 -0
- package/scripts/douyin-flow-test.sh +72 -0
- package/scripts/douyin-test.sh +101 -0
- package/dist/actions.d.ts +0 -51
- package/dist/actions.d.ts.map +0 -1
- package/dist/actions.js +0 -2662
- package/dist/actions.js.map +0 -1
- package/dist/browser.d.ts +0 -651
- package/dist/browser.d.ts.map +0 -1
- package/dist/browser.js +0 -3088
- package/dist/browser.js.map +0 -1
- package/dist/ios-actions.d.ts +0 -11
- package/dist/ios-actions.d.ts.map +0 -1
- package/dist/ios-actions.js +0 -228
- package/dist/ios-actions.js.map +0 -1
- package/dist/ios-manager.d.ts +0 -266
- package/dist/ios-manager.d.ts.map +0 -1
- package/dist/ios-manager.js +0 -1076
- package/dist/ios-manager.js.map +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { successResponse } from '../protocol.js';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
async function executeStep(step, browser) {
|
|
5
|
+
const page = browser.getPage();
|
|
6
|
+
try {
|
|
7
|
+
switch (step.action) {
|
|
8
|
+
case 'navigate': {
|
|
9
|
+
await page.goto(step.url);
|
|
10
|
+
return { action: 'navigate', success: true };
|
|
11
|
+
}
|
|
12
|
+
case 'click': {
|
|
13
|
+
const locator = browser.getLocator(step.selector);
|
|
14
|
+
await locator.click();
|
|
15
|
+
return { action: 'click', success: true };
|
|
16
|
+
}
|
|
17
|
+
case 'fill': {
|
|
18
|
+
const locator = browser.getLocator(step.selector);
|
|
19
|
+
await locator.fill(step.value);
|
|
20
|
+
return { action: 'fill', success: true };
|
|
21
|
+
}
|
|
22
|
+
case 'type': {
|
|
23
|
+
const locator = browser.getLocator(step.selector);
|
|
24
|
+
await locator.type(step.text);
|
|
25
|
+
return { action: 'type', success: true };
|
|
26
|
+
}
|
|
27
|
+
case 'press': {
|
|
28
|
+
await page.keyboard.press(step.key);
|
|
29
|
+
return { action: 'press', success: true };
|
|
30
|
+
}
|
|
31
|
+
case 'get': {
|
|
32
|
+
let data;
|
|
33
|
+
switch (step.type) {
|
|
34
|
+
case 'url':
|
|
35
|
+
data = page.url();
|
|
36
|
+
break;
|
|
37
|
+
case 'title':
|
|
38
|
+
data = await page.title();
|
|
39
|
+
break;
|
|
40
|
+
case 'text':
|
|
41
|
+
if (step.selector) {
|
|
42
|
+
const locator = browser.getLocator(step.selector);
|
|
43
|
+
data = await locator.textContent();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
data = await page.textContent('body');
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case 'html':
|
|
50
|
+
if (step.selector) {
|
|
51
|
+
const locator = browser.getLocator(step.selector);
|
|
52
|
+
data = await locator.innerHTML();
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
data = await page.content();
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'value':
|
|
59
|
+
if (step.selector) {
|
|
60
|
+
const locator = browser.getLocator(step.selector);
|
|
61
|
+
data = await locator.inputValue();
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
return { action: 'get', success: true, data };
|
|
66
|
+
}
|
|
67
|
+
case 'wait': {
|
|
68
|
+
if (step.selector) {
|
|
69
|
+
const locator = browser.getLocator(step.selector);
|
|
70
|
+
await locator.waitFor({
|
|
71
|
+
state: step.state ?? 'attached',
|
|
72
|
+
timeout: step.timeout,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
await page.waitForTimeout(step.timeout ?? 1000);
|
|
77
|
+
}
|
|
78
|
+
return { action: 'wait', success: true };
|
|
79
|
+
}
|
|
80
|
+
case 'screenshot': {
|
|
81
|
+
const screenshotPath = step.path
|
|
82
|
+
? path.resolve(step.path)
|
|
83
|
+
: path.join(process.cwd(), `screenshot-${Date.now()}.png`);
|
|
84
|
+
await page.screenshot({
|
|
85
|
+
path: screenshotPath,
|
|
86
|
+
fullPage: step.fullPage ?? false,
|
|
87
|
+
});
|
|
88
|
+
return { action: 'screenshot', success: true, data: { path: screenshotPath } };
|
|
89
|
+
}
|
|
90
|
+
default:
|
|
91
|
+
return {
|
|
92
|
+
action: step.action,
|
|
93
|
+
success: false,
|
|
94
|
+
error: 'Unknown step action',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return {
|
|
100
|
+
action: step.action,
|
|
101
|
+
success: false,
|
|
102
|
+
error: error instanceof Error ? error.message : String(error),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export async function handleInteract(command, browser) {
|
|
107
|
+
if (!browser.isLaunched()) {
|
|
108
|
+
await browser.launch({
|
|
109
|
+
id: 'auto',
|
|
110
|
+
action: 'launch',
|
|
111
|
+
headless: command.headless ?? true,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
let steps;
|
|
116
|
+
if (command.file) {
|
|
117
|
+
const filePath = path.resolve(command.file);
|
|
118
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
119
|
+
steps = JSON.parse(content);
|
|
120
|
+
}
|
|
121
|
+
else if (command.steps) {
|
|
122
|
+
steps = command.steps;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
return {
|
|
126
|
+
id: command.id,
|
|
127
|
+
success: false,
|
|
128
|
+
error: 'No steps provided. Use --file <path> or pass steps as JSON',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const results = [];
|
|
132
|
+
let allSuccess = true;
|
|
133
|
+
for (const step of steps) {
|
|
134
|
+
const result = await executeStep(step, browser);
|
|
135
|
+
results.push(result);
|
|
136
|
+
if (!result.success) {
|
|
137
|
+
allSuccess = false;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const page = browser.getPage();
|
|
142
|
+
const interactResult = {
|
|
143
|
+
success: allSuccess,
|
|
144
|
+
steps: results,
|
|
145
|
+
finalUrl: page.url(),
|
|
146
|
+
finalTitle: await page.title(),
|
|
147
|
+
};
|
|
148
|
+
const lastResult = results[results.length - 1];
|
|
149
|
+
if (lastResult?.action === 'get' && lastResult.data) {
|
|
150
|
+
interactResult.output = lastResult.data;
|
|
151
|
+
}
|
|
152
|
+
return successResponse(command.id, interactResult);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
id: command.id,
|
|
157
|
+
success: false,
|
|
158
|
+
error: error instanceof Error ? error.message : String(error),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=interact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interact.js","sourceRoot":"","sources":["../../src/actions/interact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BrowserManager } from '../browser/index.js';
|
|
2
|
+
import type { Command, Response, NavigateCommand, NavigateData, ClickCommand, TypeCommand, PressCommand, ScreenshotCommand, ScreenshotData, EvaluateCommand, WaitCommand, ScrollCommand, SelectCommand, HoverCommand, ContentCommand, ContentData } from '../types.js';
|
|
3
|
+
import { type SnapshotData } from './utils.js';
|
|
4
|
+
export declare function handleLaunch(command: Command & {
|
|
5
|
+
action: 'launch';
|
|
6
|
+
}, browser: BrowserManager): Promise<Response>;
|
|
7
|
+
export declare function handleNavigate(command: NavigateCommand, browser: BrowserManager): Promise<Response<NavigateData>>;
|
|
8
|
+
export declare function handleClick(command: ClickCommand, browser: BrowserManager): Promise<Response>;
|
|
9
|
+
export declare function handleType(command: TypeCommand, browser: BrowserManager): Promise<Response>;
|
|
10
|
+
export declare function handlePress(command: PressCommand, browser: BrowserManager): Promise<Response>;
|
|
11
|
+
export declare function handleScreenshot(command: ScreenshotCommand, browser: BrowserManager): Promise<Response<ScreenshotData>>;
|
|
12
|
+
export declare function handleSnapshot(command: Command & {
|
|
13
|
+
action: 'snapshot';
|
|
14
|
+
interactive?: boolean;
|
|
15
|
+
cursor?: boolean;
|
|
16
|
+
maxDepth?: number;
|
|
17
|
+
compact?: boolean;
|
|
18
|
+
selector?: string;
|
|
19
|
+
inFrame?: string;
|
|
20
|
+
path?: boolean;
|
|
21
|
+
attrs?: boolean;
|
|
22
|
+
selectors?: boolean;
|
|
23
|
+
all?: boolean;
|
|
24
|
+
}, browser: BrowserManager): Promise<Response<SnapshotData>>;
|
|
25
|
+
export declare function handleEvaluate(command: EvaluateCommand, browser: BrowserManager): Promise<Response>;
|
|
26
|
+
export declare function handleWait(command: WaitCommand, browser: BrowserManager): Promise<Response>;
|
|
27
|
+
export declare function handleScroll(command: ScrollCommand, browser: BrowserManager): Promise<Response>;
|
|
28
|
+
export declare function handleSelect(command: SelectCommand, browser: BrowserManager): Promise<Response>;
|
|
29
|
+
export declare function handleHover(command: HoverCommand, browser: BrowserManager): Promise<Response>;
|
|
30
|
+
export declare function handleContent(command: ContentCommand, browser: BrowserManager): Promise<Response<ContentData>>;
|
|
31
|
+
//# sourceMappingURL=interaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../src/actions/interaction.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAc1D,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,cAAc,EACd,WAAW,EACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAA0C,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEvF,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,EACvC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAQnB;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAoBjC;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAwDnB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DjG;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CA+DnB;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CA4CnC;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,EACD,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAsDjC;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAiDnB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoCjG;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAgDnB;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CAuBnB;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,CA8CnB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAWhC"}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { mkdirSync, existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getInstanceId, getAppDir } from '../daemon.js';
|
|
4
|
+
import { performDiff } from '../diff.js';
|
|
5
|
+
import { detectMainContent, generateContentTips } from '../content-detection.js';
|
|
6
|
+
import { humanClick, humanType, humanWander, humanMoveTo, getHumanConfigFromEnv, } from '../human-mouse.js';
|
|
7
|
+
import { getViewerUrl } from '../rc-config.js';
|
|
8
|
+
import { successResponse, errorResponse } from '../protocol.js';
|
|
9
|
+
import { assertElementExists, toAIFriendlyError } from './utils.js';
|
|
10
|
+
export async function handleLaunch(command, browser) {
|
|
11
|
+
await browser.launch(command);
|
|
12
|
+
const instanceId = getInstanceId();
|
|
13
|
+
return successResponse(command.id, {
|
|
14
|
+
launched: true,
|
|
15
|
+
instanceId,
|
|
16
|
+
viewerUrl: getViewerUrl(instanceId),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export async function handleNavigate(command, browser) {
|
|
20
|
+
const page = browser.getPage();
|
|
21
|
+
if (command.headers && Object.keys(command.headers).length > 0) {
|
|
22
|
+
await browser.setScopedHeaders(command.url, command.headers);
|
|
23
|
+
}
|
|
24
|
+
await page.goto(command.url, {
|
|
25
|
+
waitUntil: command.waitUntil ?? 'domcontentloaded',
|
|
26
|
+
timeout: command.timeout ?? 30000,
|
|
27
|
+
});
|
|
28
|
+
if (browser.isRecordingSession()) {
|
|
29
|
+
await browser.injectRecorderIfNeeded();
|
|
30
|
+
}
|
|
31
|
+
return successResponse(command.id, {
|
|
32
|
+
url: page.url(),
|
|
33
|
+
title: await page.title(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function handleClick(command, browser) {
|
|
37
|
+
const locator = browser.getLocator(command.selector, command.inFrame);
|
|
38
|
+
const isRef = browser.isRef(command.selector);
|
|
39
|
+
await assertElementExists(locator, command.selector, isRef);
|
|
40
|
+
if (command.human?.enabled) {
|
|
41
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
42
|
+
try {
|
|
43
|
+
const page = browser.getPage();
|
|
44
|
+
const box = await locator.boundingBox();
|
|
45
|
+
if (!box) {
|
|
46
|
+
throw new Error(`Element not visible: ${command.selector}`);
|
|
47
|
+
}
|
|
48
|
+
const targetX = box.x + box.width / 2;
|
|
49
|
+
const targetY = box.y + box.height / 2;
|
|
50
|
+
await humanClick(page, targetX, targetY, command.human, {
|
|
51
|
+
button: command.button,
|
|
52
|
+
clickCount: command.clickCount,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw toAIFriendlyError(error, command.selector);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const result = { clicked: true, human: true };
|
|
60
|
+
if (diffResult) {
|
|
61
|
+
result.diff = diffResult.output;
|
|
62
|
+
result.diffScope = diffResult.diff.scope;
|
|
63
|
+
}
|
|
64
|
+
browser.recordCommand('click', command.selector, undefined, true);
|
|
65
|
+
return successResponse(command.id, result);
|
|
66
|
+
}
|
|
67
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
68
|
+
try {
|
|
69
|
+
await locator.click({
|
|
70
|
+
button: command.button,
|
|
71
|
+
clickCount: command.clickCount,
|
|
72
|
+
delay: command.delay,
|
|
73
|
+
timeout: command.timeout || 5000,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw toAIFriendlyError(error, command.selector);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const result = { clicked: true };
|
|
81
|
+
if (diffResult) {
|
|
82
|
+
result.diff = diffResult.output;
|
|
83
|
+
result.diffScope = diffResult.diff.scope;
|
|
84
|
+
}
|
|
85
|
+
browser.recordCommand('click', command.selector, undefined, true);
|
|
86
|
+
return successResponse(command.id, result);
|
|
87
|
+
}
|
|
88
|
+
export async function handleType(command, browser) {
|
|
89
|
+
const locator = browser.getLocator(command.selector, command.inFrame);
|
|
90
|
+
const isRef = browser.isRef(command.selector);
|
|
91
|
+
await assertElementExists(locator, command.selector, isRef);
|
|
92
|
+
if (command.human?.enabled) {
|
|
93
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
94
|
+
try {
|
|
95
|
+
const page = browser.getPage();
|
|
96
|
+
const box = await locator.boundingBox();
|
|
97
|
+
if (!box) {
|
|
98
|
+
throw new Error(`Element not visible: ${command.selector}`);
|
|
99
|
+
}
|
|
100
|
+
const targetX = box.x + box.width / 2;
|
|
101
|
+
const targetY = box.y + box.height / 2;
|
|
102
|
+
await humanClick(page, targetX, targetY, command.human);
|
|
103
|
+
await locator.focus();
|
|
104
|
+
await humanType(page, command.text, command.human);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw toAIFriendlyError(error, command.selector);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const result = { typed: true, human: true };
|
|
111
|
+
if (diffResult) {
|
|
112
|
+
result.diff = diffResult.output;
|
|
113
|
+
result.diffScope = diffResult.diff.scope;
|
|
114
|
+
}
|
|
115
|
+
browser.recordCommand('type', command.selector, command.text, true);
|
|
116
|
+
return successResponse(command.id, result);
|
|
117
|
+
}
|
|
118
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
119
|
+
try {
|
|
120
|
+
if (command.clear) {
|
|
121
|
+
await locator.fill('');
|
|
122
|
+
}
|
|
123
|
+
await locator.pressSequentially(command.text, {
|
|
124
|
+
delay: command.delay,
|
|
125
|
+
});
|
|
126
|
+
await locator.evaluate((el) => {
|
|
127
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw toAIFriendlyError(error, command.selector);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
const result = { typed: true };
|
|
135
|
+
if (diffResult) {
|
|
136
|
+
result.diff = diffResult.output;
|
|
137
|
+
result.diffScope = diffResult.diff.scope;
|
|
138
|
+
}
|
|
139
|
+
browser.recordCommand('type', command.selector, command.text, true);
|
|
140
|
+
return successResponse(command.id, result);
|
|
141
|
+
}
|
|
142
|
+
export async function handlePress(command, browser) {
|
|
143
|
+
const page = browser.getPage();
|
|
144
|
+
let locator = page.locator('body');
|
|
145
|
+
if (command.inFrame && command.selector) {
|
|
146
|
+
const frameLocator = browser.getFrame(command.inFrame);
|
|
147
|
+
locator = frameLocator.locator(command.selector);
|
|
148
|
+
}
|
|
149
|
+
else if (command.selector) {
|
|
150
|
+
locator = page.locator(command.selector);
|
|
151
|
+
}
|
|
152
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
153
|
+
if (command.inFrame && command.selector) {
|
|
154
|
+
const frameLocator = browser.getFrame(command.inFrame);
|
|
155
|
+
await frameLocator.locator(command.selector).press(command.key);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
if (command.selector) {
|
|
159
|
+
await page.press(command.selector, command.key);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
await page.keyboard.press(command.key);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
await page.evaluate((key) => {
|
|
166
|
+
const specialKeys = [
|
|
167
|
+
'Enter',
|
|
168
|
+
'Tab',
|
|
169
|
+
'Escape',
|
|
170
|
+
'Backspace',
|
|
171
|
+
'ArrowUp',
|
|
172
|
+
'ArrowDown',
|
|
173
|
+
'ArrowLeft',
|
|
174
|
+
'ArrowRight',
|
|
175
|
+
];
|
|
176
|
+
const keyParts = key.split('+');
|
|
177
|
+
const mainKey = keyParts[keyParts.length - 1];
|
|
178
|
+
const hasCtrl = keyParts.includes('Control') || keyParts.includes('Ctrl');
|
|
179
|
+
const hasMeta = keyParts.includes('Meta') || keyParts.includes('Command');
|
|
180
|
+
const hasAlt = keyParts.includes('Alt');
|
|
181
|
+
const hasShift = keyParts.includes('Shift');
|
|
182
|
+
if (specialKeys.includes(mainKey) || hasCtrl || hasMeta || hasAlt) {
|
|
183
|
+
const event = new KeyboardEvent('keydown', {
|
|
184
|
+
key: mainKey,
|
|
185
|
+
code: mainKey.length === 1 ? `Key${mainKey.toUpperCase()}` : mainKey,
|
|
186
|
+
ctrlKey: hasCtrl,
|
|
187
|
+
metaKey: hasMeta,
|
|
188
|
+
altKey: hasAlt,
|
|
189
|
+
shiftKey: hasShift,
|
|
190
|
+
bubbles: true,
|
|
191
|
+
});
|
|
192
|
+
document.activeElement?.dispatchEvent(event);
|
|
193
|
+
}
|
|
194
|
+
}, command.key);
|
|
195
|
+
});
|
|
196
|
+
const result = { pressed: true };
|
|
197
|
+
if (diffResult) {
|
|
198
|
+
result.diff = diffResult.output;
|
|
199
|
+
result.diffScope = diffResult.diff.scope;
|
|
200
|
+
}
|
|
201
|
+
return successResponse(command.id, result);
|
|
202
|
+
}
|
|
203
|
+
export async function handleScreenshot(command, browser) {
|
|
204
|
+
const page = browser.getPage();
|
|
205
|
+
const options = {
|
|
206
|
+
fullPage: command.fullPage,
|
|
207
|
+
type: command.format ?? 'png',
|
|
208
|
+
};
|
|
209
|
+
if (command.format === 'jpeg' && command.quality !== undefined) {
|
|
210
|
+
options.quality = command.quality;
|
|
211
|
+
}
|
|
212
|
+
let target = page;
|
|
213
|
+
if (command.inFrame) {
|
|
214
|
+
const frameLocator = browser.getFrame(command.inFrame);
|
|
215
|
+
if (command.selector) {
|
|
216
|
+
target = frameLocator.locator(command.selector);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
target = frameLocator.locator(':root');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (command.selector) {
|
|
223
|
+
target = browser.getLocator(command.selector);
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
let savePath = command.path;
|
|
227
|
+
if (!savePath) {
|
|
228
|
+
const ext = command.format === 'jpeg' ? 'jpg' : 'png';
|
|
229
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
230
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
231
|
+
const filename = `screenshot-${timestamp}-${random}.${ext}`;
|
|
232
|
+
const screenshotDir = path.join(getAppDir(), 'tmp', 'screenshots');
|
|
233
|
+
mkdirSync(screenshotDir, { recursive: true });
|
|
234
|
+
savePath = path.join(screenshotDir, filename);
|
|
235
|
+
}
|
|
236
|
+
await target.screenshot({ ...options, path: savePath });
|
|
237
|
+
return successResponse(command.id, { path: savePath });
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
if (command.selector) {
|
|
241
|
+
throw toAIFriendlyError(error, command.selector);
|
|
242
|
+
}
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
export async function handleSnapshot(command, browser) {
|
|
247
|
+
let effectiveSelector = command.selector;
|
|
248
|
+
let detectionResult = null;
|
|
249
|
+
if (!command.selector) {
|
|
250
|
+
const page = browser.getPage();
|
|
251
|
+
detectionResult = await detectMainContent(page);
|
|
252
|
+
effectiveSelector = detectionResult.selector;
|
|
253
|
+
}
|
|
254
|
+
const snapshot = await browser.getSnapshot({
|
|
255
|
+
interactive: command.interactive,
|
|
256
|
+
cursor: command.cursor,
|
|
257
|
+
maxDepth: command.maxDepth,
|
|
258
|
+
compact: command.compact,
|
|
259
|
+
selector: effectiveSelector,
|
|
260
|
+
framePath: command.inFrame,
|
|
261
|
+
path: command.path,
|
|
262
|
+
attrs: command.attrs,
|
|
263
|
+
selectors: command.selectors,
|
|
264
|
+
all: command.all,
|
|
265
|
+
});
|
|
266
|
+
const simpleRefs = {};
|
|
267
|
+
const refs = snapshot.refs || {};
|
|
268
|
+
for (const [ref, data] of Object.entries(refs)) {
|
|
269
|
+
simpleRefs[ref] = {
|
|
270
|
+
role: data.role,
|
|
271
|
+
name: data.name,
|
|
272
|
+
...(data.xpath && { xpath: data.xpath }),
|
|
273
|
+
...(data.cssPath && { cssPath: data.cssPath }),
|
|
274
|
+
...(data.attributes && { attributes: data.attributes }),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const tips = detectionResult ? generateContentTips(detectionResult) : undefined;
|
|
278
|
+
return successResponse(command.id, {
|
|
279
|
+
snapshot: snapshot.tree || 'Empty page',
|
|
280
|
+
refs: Object.keys(simpleRefs).length > 0 ? simpleRefs : undefined,
|
|
281
|
+
}, tips ?? undefined);
|
|
282
|
+
}
|
|
283
|
+
export async function handleEvaluate(command, browser) {
|
|
284
|
+
try {
|
|
285
|
+
let script;
|
|
286
|
+
if (command.file) {
|
|
287
|
+
const resolvedPath = path.resolve(command.file);
|
|
288
|
+
const cwd = process.cwd();
|
|
289
|
+
if (!resolvedPath.startsWith(cwd)) {
|
|
290
|
+
throw new Error(`Security: file path must be within project directory. Got: ${resolvedPath}`);
|
|
291
|
+
}
|
|
292
|
+
if (!existsSync(resolvedPath)) {
|
|
293
|
+
throw new Error(`Script file not found: ${resolvedPath}`);
|
|
294
|
+
}
|
|
295
|
+
script = readFileSync(resolvedPath, 'utf-8');
|
|
296
|
+
}
|
|
297
|
+
else if (command.script) {
|
|
298
|
+
script = command.script;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
throw new Error('Either script or file must be provided for evaluate command');
|
|
302
|
+
}
|
|
303
|
+
let result;
|
|
304
|
+
if (command.inFrame) {
|
|
305
|
+
const frameLocator = browser.getFrame(command.inFrame);
|
|
306
|
+
result = await frameLocator.locator(':root').evaluate(script);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
const page = browser.getPage();
|
|
310
|
+
result = await page.evaluate(script);
|
|
311
|
+
}
|
|
312
|
+
browser.recordCommand('eval', 'javascript', script.length > 200 ? script.substring(0, 200) + '...' : script, true);
|
|
313
|
+
return successResponse(command.id, { result });
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
const script = command.script || command.file || '';
|
|
317
|
+
browser.recordCommand('eval', 'javascript', script.length > 200 ? script.substring(0, 200) + '...' : script, false);
|
|
318
|
+
console.error('Error in handleEvaluate:', error);
|
|
319
|
+
return errorResponse(command.id, error instanceof Error ? error.message : String(error));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
export async function handleWait(command, browser) {
|
|
323
|
+
const humanConfig = getHumanConfigFromEnv();
|
|
324
|
+
const page = browser.getPage();
|
|
325
|
+
if (humanConfig.enabled && command.timeout && !command.selector) {
|
|
326
|
+
await humanWander(page, humanConfig, { duration: command.timeout });
|
|
327
|
+
return successResponse(command.id, { waited: true, wandered: true });
|
|
328
|
+
}
|
|
329
|
+
if (command.inFrame) {
|
|
330
|
+
const frame = browser.getFrame(command.inFrame);
|
|
331
|
+
if (command.selector) {
|
|
332
|
+
await frame.waitForSelector(command.selector, {
|
|
333
|
+
state: command.state ?? 'visible',
|
|
334
|
+
timeout: command.timeout,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
else if (command.timeout) {
|
|
338
|
+
await frame.waitForTimeout(command.timeout);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
await frame.waitForLoadState('load');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
const frame = browser.getFrame();
|
|
346
|
+
if (command.selector) {
|
|
347
|
+
await frame.waitForSelector(command.selector, {
|
|
348
|
+
state: command.state ?? 'visible',
|
|
349
|
+
timeout: command.timeout,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
else if (command.timeout) {
|
|
353
|
+
await frame.waitForTimeout(command.timeout);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
await frame.waitForLoadState('load');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return successResponse(command.id, { waited: true });
|
|
360
|
+
}
|
|
361
|
+
export async function handleScroll(command, browser) {
|
|
362
|
+
const page = browser.getPage();
|
|
363
|
+
if (command.selector) {
|
|
364
|
+
const element = page.locator(command.selector);
|
|
365
|
+
await element.scrollIntoViewIfNeeded();
|
|
366
|
+
if (command.x !== undefined || command.y !== undefined) {
|
|
367
|
+
await element.evaluate((el, { x, y }) => {
|
|
368
|
+
if ('scrollBy' in el) {
|
|
369
|
+
el.scrollBy(x ?? 0, y ?? 0);
|
|
370
|
+
}
|
|
371
|
+
}, { x: command.x, y: command.y });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
let deltaX = command.x ?? 0;
|
|
376
|
+
let deltaY = command.y ?? 0;
|
|
377
|
+
if (command.direction) {
|
|
378
|
+
const amount = command.amount ?? 100;
|
|
379
|
+
switch (command.direction) {
|
|
380
|
+
case 'up':
|
|
381
|
+
deltaY = -amount;
|
|
382
|
+
break;
|
|
383
|
+
case 'down':
|
|
384
|
+
deltaY = amount;
|
|
385
|
+
break;
|
|
386
|
+
case 'left':
|
|
387
|
+
deltaX = -amount;
|
|
388
|
+
break;
|
|
389
|
+
case 'right':
|
|
390
|
+
deltaX = amount;
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const safeDeltaX = Number(deltaX) || 0;
|
|
395
|
+
const safeDeltaY = Number(deltaY) || 0;
|
|
396
|
+
await page.evaluate(({ dx, dy }) => window.scrollBy(dx, dy), {
|
|
397
|
+
dx: safeDeltaX,
|
|
398
|
+
dy: safeDeltaY,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
return successResponse(command.id, { scrolled: true });
|
|
402
|
+
}
|
|
403
|
+
export async function handleSelect(command, browser) {
|
|
404
|
+
const values = Array.isArray(command.values) ? command.values : [command.values];
|
|
405
|
+
const locator = browser.getLocator(command.selector, command.inFrame);
|
|
406
|
+
const isRef = browser.isRef(command.selector);
|
|
407
|
+
await assertElementExists(locator, command.selector, isRef);
|
|
408
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
409
|
+
try {
|
|
410
|
+
await locator.selectOption(values);
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
throw toAIFriendlyError(error, command.selector);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
const result = { selected: values };
|
|
417
|
+
if (diffResult) {
|
|
418
|
+
result.diff = diffResult.output;
|
|
419
|
+
result.diffScope = diffResult.diff.scope;
|
|
420
|
+
}
|
|
421
|
+
browser.recordCommand('select', command.selector, values.join(','), true);
|
|
422
|
+
return successResponse(command.id, result);
|
|
423
|
+
}
|
|
424
|
+
export async function handleHover(command, browser) {
|
|
425
|
+
const locator = browser.getLocator(command.selector, command.inFrame);
|
|
426
|
+
const isRef = browser.isRef(command.selector);
|
|
427
|
+
await assertElementExists(locator, command.selector, isRef);
|
|
428
|
+
if (command.human?.enabled) {
|
|
429
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
430
|
+
try {
|
|
431
|
+
const page = browser.getPage();
|
|
432
|
+
const box = await locator.boundingBox();
|
|
433
|
+
if (!box) {
|
|
434
|
+
throw new Error(`Element not visible: ${command.selector}`);
|
|
435
|
+
}
|
|
436
|
+
const targetX = box.x + box.width / 2;
|
|
437
|
+
const targetY = box.y + box.height / 2;
|
|
438
|
+
await humanMoveTo(page, { x: targetX, y: targetY }, command.human);
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
throw toAIFriendlyError(error, command.selector);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
const result = { hovered: true, human: true };
|
|
445
|
+
if (diffResult) {
|
|
446
|
+
result.diff = diffResult.output;
|
|
447
|
+
result.diffScope = diffResult.diff.scope;
|
|
448
|
+
}
|
|
449
|
+
return successResponse(command.id, result);
|
|
450
|
+
}
|
|
451
|
+
const diffResult = await performDiff(locator, command.diffScope, async () => {
|
|
452
|
+
try {
|
|
453
|
+
await locator.hover();
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
throw toAIFriendlyError(error, command.selector);
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
const result = { hovered: true };
|
|
460
|
+
if (diffResult) {
|
|
461
|
+
result.diff = diffResult.output;
|
|
462
|
+
result.diffScope = diffResult.diff.scope;
|
|
463
|
+
}
|
|
464
|
+
return successResponse(command.id, result);
|
|
465
|
+
}
|
|
466
|
+
export async function handleContent(command, browser) {
|
|
467
|
+
const page = browser.getPage();
|
|
468
|
+
let html;
|
|
469
|
+
if (command.selector) {
|
|
470
|
+
html = await page.locator(command.selector).innerHTML();
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
html = await page.content();
|
|
474
|
+
}
|
|
475
|
+
return successResponse(command.id, { html });
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=interaction.js.map
|