@monoes/monobrowse 1.0.25 → 1.0.27
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/src/__tests__/browser-launch.test.d.ts +3 -2
- package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
- package/dist/src/__tests__/browser-launch.test.js +71 -6
- package/dist/src/__tests__/browser-launch.test.js.map +1 -1
- package/dist/src/__tests__/launch-close-settle.test.d.ts +6 -0
- package/dist/src/__tests__/launch-close-settle.test.d.ts.map +1 -1
- package/dist/src/__tests__/launch-close-settle.test.js +29 -8
- package/dist/src/__tests__/launch-close-settle.test.js.map +1 -1
- package/dist/src/browser/actions-eval.d.ts +8 -0
- package/dist/src/browser/actions-eval.d.ts.map +1 -0
- package/dist/src/browser/actions-eval.js +72 -0
- package/dist/src/browser/actions-eval.js.map +1 -0
- package/dist/src/browser/actions-form.d.ts +10 -0
- package/dist/src/browser/actions-form.d.ts.map +1 -0
- package/dist/src/browser/actions-form.js +133 -0
- package/dist/src/browser/actions-form.js.map +1 -0
- package/dist/src/browser/actions-keyboard.d.ts +7 -0
- package/dist/src/browser/actions-keyboard.d.ts.map +1 -0
- package/dist/src/browser/actions-keyboard.js +131 -0
- package/dist/src/browser/actions-keyboard.js.map +1 -0
- package/dist/src/browser/actions-mouse.d.ts +11 -0
- package/dist/src/browser/actions-mouse.d.ts.map +1 -0
- package/dist/src/browser/actions-mouse.js +105 -0
- package/dist/src/browser/actions-mouse.js.map +1 -0
- package/dist/src/browser/actions.d.ts +12 -28
- package/dist/src/browser/actions.d.ts.map +1 -1
- package/dist/src/browser/actions.js +12 -434
- package/dist/src/browser/actions.js.map +1 -1
- package/dist/src/browser/browser-discovery.d.ts +26 -0
- package/dist/src/browser/browser-discovery.d.ts.map +1 -0
- package/dist/src/browser/browser-discovery.js +113 -0
- package/dist/src/browser/browser-discovery.js.map +1 -0
- package/dist/src/browser/browser-launch.d.ts +3 -0
- package/dist/src/browser/browser-launch.d.ts.map +1 -0
- package/dist/src/browser/browser-launch.js +324 -0
- package/dist/src/browser/browser-launch.js.map +1 -0
- package/dist/src/browser/browser-lifecycle.d.ts +52 -0
- package/dist/src/browser/browser-lifecycle.d.ts.map +1 -0
- package/dist/src/browser/browser-lifecycle.js +233 -0
- package/dist/src/browser/browser-lifecycle.js.map +1 -0
- package/dist/src/browser/browser-page.d.ts +13 -0
- package/dist/src/browser/browser-page.d.ts.map +1 -0
- package/dist/src/browser/browser-page.js +179 -0
- package/dist/src/browser/browser-page.js.map +1 -0
- package/dist/src/browser/browser-state.d.ts +7 -0
- package/dist/src/browser/browser-state.d.ts.map +1 -0
- package/dist/src/browser/browser-state.js +19 -0
- package/dist/src/browser/browser-state.js.map +1 -0
- package/dist/src/browser/browser.d.ts +5 -68
- package/dist/src/browser/browser.d.ts.map +1 -1
- package/dist/src/browser/browser.js +9 -794
- package/dist/src/browser/browser.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/__tests__/browser-launch.test.ts +78 -6
- package/src/__tests__/launch-close-settle.test.ts +32 -10
- package/src/browser/actions-eval.ts +118 -0
- package/src/browser/actions-form.ts +218 -0
- package/src/browser/actions-keyboard.ts +171 -0
- package/src/browser/actions-mouse.ts +212 -0
- package/src/browser/actions.ts +37 -712
- package/src/browser/browser-discovery.ts +116 -0
- package/src/browser/browser-launch.ts +358 -0
- package/src/browser/browser-lifecycle.ts +238 -0
- package/src/browser/browser-page.ts +213 -0
- package/src/browser/browser-state.ts +21 -0
- package/src/browser/browser.ts +17 -859
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { CdpClient } from './cdp.js';
|
|
2
|
+
|
|
3
|
+
export async function typeText(client: CdpClient, sessionId: string, text: string): Promise<void> {
|
|
4
|
+
// Cap to 100 KB to prevent OOM in CDP message serializer
|
|
5
|
+
const safeText = text.length > 102_400 ? text.slice(0, 102_400) : text;
|
|
6
|
+
await client.send('Input.insertText', { text: safeText }, sessionId);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function pressKeyCombo(
|
|
10
|
+
client: CdpClient,
|
|
11
|
+
sessionId: string,
|
|
12
|
+
key: string,
|
|
13
|
+
modifiers: number,
|
|
14
|
+
): Promise<void> {
|
|
15
|
+
const { text: _text, ...keyInfo } = resolveKey(key);
|
|
16
|
+
// rawKeyDown prevents Chrome from inserting the character text; only the shortcut fires
|
|
17
|
+
await client.send(
|
|
18
|
+
'Input.dispatchKeyEvent',
|
|
19
|
+
{ type: 'rawKeyDown', ...keyInfo, modifiers },
|
|
20
|
+
sessionId,
|
|
21
|
+
);
|
|
22
|
+
await client.send('Input.dispatchKeyEvent', { type: 'keyUp', ...keyInfo, modifiers }, sessionId);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function pressKey(client: CdpClient, sessionId: string, key: string): Promise<void> {
|
|
26
|
+
const { text, ...keyInfo } = resolveKey(key);
|
|
27
|
+
|
|
28
|
+
// rawKeyDown does not insert text; the explicit char event handles insertion
|
|
29
|
+
await client.send(
|
|
30
|
+
'Input.dispatchKeyEvent',
|
|
31
|
+
{
|
|
32
|
+
type: 'rawKeyDown',
|
|
33
|
+
...keyInfo,
|
|
34
|
+
},
|
|
35
|
+
sessionId,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (text) {
|
|
39
|
+
await client.send(
|
|
40
|
+
'Input.dispatchKeyEvent',
|
|
41
|
+
{
|
|
42
|
+
type: 'char',
|
|
43
|
+
text,
|
|
44
|
+
},
|
|
45
|
+
sessionId,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await client.send(
|
|
50
|
+
'Input.dispatchKeyEvent',
|
|
51
|
+
{
|
|
52
|
+
type: 'keyUp',
|
|
53
|
+
...keyInfo,
|
|
54
|
+
},
|
|
55
|
+
sessionId,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function resolveKey(key: string): {
|
|
60
|
+
key: string;
|
|
61
|
+
code: string;
|
|
62
|
+
text?: string;
|
|
63
|
+
windowsVirtualKeyCode?: number;
|
|
64
|
+
} {
|
|
65
|
+
const keyMap: Record<
|
|
66
|
+
string,
|
|
67
|
+
{ key: string; code: string; text?: string; windowsVirtualKeyCode?: number }
|
|
68
|
+
> = {
|
|
69
|
+
Enter: { key: 'Enter', code: 'Enter', text: '\r', windowsVirtualKeyCode: 13 },
|
|
70
|
+
Tab: { key: 'Tab', code: 'Tab', windowsVirtualKeyCode: 9 },
|
|
71
|
+
Escape: { key: 'Escape', code: 'Escape', windowsVirtualKeyCode: 27 },
|
|
72
|
+
Backspace: { key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 },
|
|
73
|
+
Delete: { key: 'Delete', code: 'Delete', windowsVirtualKeyCode: 46 },
|
|
74
|
+
ArrowUp: { key: 'ArrowUp', code: 'ArrowUp', windowsVirtualKeyCode: 38 },
|
|
75
|
+
ArrowDown: { key: 'ArrowDown', code: 'ArrowDown', windowsVirtualKeyCode: 40 },
|
|
76
|
+
ArrowLeft: { key: 'ArrowLeft', code: 'ArrowLeft', windowsVirtualKeyCode: 37 },
|
|
77
|
+
ArrowRight: { key: 'ArrowRight', code: 'ArrowRight', windowsVirtualKeyCode: 39 },
|
|
78
|
+
Home: { key: 'Home', code: 'Home', windowsVirtualKeyCode: 36 },
|
|
79
|
+
End: { key: 'End', code: 'End', windowsVirtualKeyCode: 35 },
|
|
80
|
+
PageUp: { key: 'PageUp', code: 'PageUp', windowsVirtualKeyCode: 33 },
|
|
81
|
+
PageDown: { key: 'PageDown', code: 'PageDown', windowsVirtualKeyCode: 34 },
|
|
82
|
+
Space: { key: ' ', code: 'Space', text: ' ', windowsVirtualKeyCode: 32 },
|
|
83
|
+
' ': { key: ' ', code: 'Space', text: ' ', windowsVirtualKeyCode: 32 },
|
|
84
|
+
Shift: { key: 'Shift', code: 'ShiftLeft', windowsVirtualKeyCode: 16 },
|
|
85
|
+
Control: { key: 'Control', code: 'ControlLeft', windowsVirtualKeyCode: 17 },
|
|
86
|
+
Alt: { key: 'Alt', code: 'AltLeft', windowsVirtualKeyCode: 18 },
|
|
87
|
+
Meta: { key: 'Meta', code: 'MetaLeft', windowsVirtualKeyCode: 91 },
|
|
88
|
+
F1: { key: 'F1', code: 'F1', windowsVirtualKeyCode: 112 },
|
|
89
|
+
F2: { key: 'F2', code: 'F2', windowsVirtualKeyCode: 113 },
|
|
90
|
+
F3: { key: 'F3', code: 'F3', windowsVirtualKeyCode: 114 },
|
|
91
|
+
F4: { key: 'F4', code: 'F4', windowsVirtualKeyCode: 115 },
|
|
92
|
+
F5: { key: 'F5', code: 'F5', windowsVirtualKeyCode: 116 },
|
|
93
|
+
F6: { key: 'F6', code: 'F6', windowsVirtualKeyCode: 117 },
|
|
94
|
+
F7: { key: 'F7', code: 'F7', windowsVirtualKeyCode: 118 },
|
|
95
|
+
F8: { key: 'F8', code: 'F8', windowsVirtualKeyCode: 119 },
|
|
96
|
+
F9: { key: 'F9', code: 'F9', windowsVirtualKeyCode: 120 },
|
|
97
|
+
F10: { key: 'F10', code: 'F10', windowsVirtualKeyCode: 121 },
|
|
98
|
+
F11: { key: 'F11', code: 'F11', windowsVirtualKeyCode: 122 },
|
|
99
|
+
F12: { key: 'F12', code: 'F12', windowsVirtualKeyCode: 123 },
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (keyMap[key]) return keyMap[key];
|
|
103
|
+
|
|
104
|
+
// Single printable character — windowsVirtualKeyCode required for rawKeyDown shortcut dispatch
|
|
105
|
+
if (key.length === 1) {
|
|
106
|
+
const charCode = key.charCodeAt(0);
|
|
107
|
+
if (charCode >= 48 && charCode <= 57) {
|
|
108
|
+
return { key, code: `Digit${key}`, text: key, windowsVirtualKeyCode: charCode };
|
|
109
|
+
}
|
|
110
|
+
if ((charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122)) {
|
|
111
|
+
return {
|
|
112
|
+
key,
|
|
113
|
+
code: `Key${key.toUpperCase()}`,
|
|
114
|
+
text: key,
|
|
115
|
+
windowsVirtualKeyCode: key.toUpperCase().charCodeAt(0),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Symbol keys: map to the physical key's code and Windows virtual key code
|
|
119
|
+
const symbolMap: Record<string, { code: string; windowsVirtualKeyCode: number }> = {
|
|
120
|
+
'!': { code: 'Digit1', windowsVirtualKeyCode: 49 },
|
|
121
|
+
'@': { code: 'Digit2', windowsVirtualKeyCode: 50 },
|
|
122
|
+
'#': { code: 'Digit3', windowsVirtualKeyCode: 51 },
|
|
123
|
+
$: { code: 'Digit4', windowsVirtualKeyCode: 52 },
|
|
124
|
+
'%': { code: 'Digit5', windowsVirtualKeyCode: 53 },
|
|
125
|
+
'^': { code: 'Digit6', windowsVirtualKeyCode: 54 },
|
|
126
|
+
'&': { code: 'Digit7', windowsVirtualKeyCode: 55 },
|
|
127
|
+
'*': { code: 'Digit8', windowsVirtualKeyCode: 56 },
|
|
128
|
+
'(': { code: 'Digit9', windowsVirtualKeyCode: 57 },
|
|
129
|
+
')': { code: 'Digit0', windowsVirtualKeyCode: 48 },
|
|
130
|
+
'-': { code: 'Minus', windowsVirtualKeyCode: 189 },
|
|
131
|
+
_: { code: 'Minus', windowsVirtualKeyCode: 189 },
|
|
132
|
+
'=': { code: 'Equal', windowsVirtualKeyCode: 187 },
|
|
133
|
+
'+': { code: 'Equal', windowsVirtualKeyCode: 187 },
|
|
134
|
+
'[': { code: 'BracketLeft', windowsVirtualKeyCode: 219 },
|
|
135
|
+
'{': { code: 'BracketLeft', windowsVirtualKeyCode: 219 },
|
|
136
|
+
']': { code: 'BracketRight', windowsVirtualKeyCode: 221 },
|
|
137
|
+
'}': { code: 'BracketRight', windowsVirtualKeyCode: 221 },
|
|
138
|
+
'\\': { code: 'Backslash', windowsVirtualKeyCode: 220 },
|
|
139
|
+
'|': { code: 'Backslash', windowsVirtualKeyCode: 220 },
|
|
140
|
+
';': { code: 'Semicolon', windowsVirtualKeyCode: 186 },
|
|
141
|
+
':': { code: 'Semicolon', windowsVirtualKeyCode: 186 },
|
|
142
|
+
"'": { code: 'Quote', windowsVirtualKeyCode: 222 },
|
|
143
|
+
'"': { code: 'Quote', windowsVirtualKeyCode: 222 },
|
|
144
|
+
'`': { code: 'Backquote', windowsVirtualKeyCode: 192 },
|
|
145
|
+
'~': { code: 'Backquote', windowsVirtualKeyCode: 192 },
|
|
146
|
+
',': { code: 'Comma', windowsVirtualKeyCode: 188 },
|
|
147
|
+
'<': { code: 'Comma', windowsVirtualKeyCode: 188 },
|
|
148
|
+
'.': { code: 'Period', windowsVirtualKeyCode: 190 },
|
|
149
|
+
'>': { code: 'Period', windowsVirtualKeyCode: 190 },
|
|
150
|
+
'/': { code: 'Slash', windowsVirtualKeyCode: 191 },
|
|
151
|
+
'?': { code: 'Slash', windowsVirtualKeyCode: 191 },
|
|
152
|
+
};
|
|
153
|
+
const sym = symbolMap[key];
|
|
154
|
+
if (sym)
|
|
155
|
+
return { key, code: sym.code, text: key, windowsVirtualKeyCode: sym.windowsVirtualKeyCode };
|
|
156
|
+
// Unknown/non-ASCII character — omit code since no valid DOM KeyboardEvent.code exists
|
|
157
|
+
return { key, code: '', text: key };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { key, code: key };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function keyDown(client: CdpClient, sessionId: string, key: string): Promise<void> {
|
|
164
|
+
const { text: _text, ...keyInfo } = resolveKey(key);
|
|
165
|
+
await client.send('Input.dispatchKeyEvent', { type: 'rawKeyDown', ...keyInfo }, sessionId);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export async function keyUp(client: CdpClient, sessionId: string, key: string): Promise<void> {
|
|
169
|
+
const { text: _text, ...keyInfo } = resolveKey(key);
|
|
170
|
+
await client.send('Input.dispatchKeyEvent', { type: 'keyUp', ...keyInfo }, sessionId);
|
|
171
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { CdpClient } from './cdp.js';
|
|
2
|
+
import { getElementBox } from './snapshot.js';
|
|
3
|
+
import type { ClickOptions, ElementRef } from './types.js';
|
|
4
|
+
|
|
5
|
+
export async function clickPoint(
|
|
6
|
+
client: CdpClient,
|
|
7
|
+
sessionId: string,
|
|
8
|
+
x: number,
|
|
9
|
+
y: number,
|
|
10
|
+
options: ClickOptions = {},
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
const button = options.button ?? 'left';
|
|
13
|
+
// Cap clickCount to prevent unbounded loop DoS
|
|
14
|
+
const clickCount = Math.min(Math.max(1, Math.floor(options.clickCount ?? 1)), 100);
|
|
15
|
+
const modifiers = options.modifiers ?? 0;
|
|
16
|
+
|
|
17
|
+
const shared = { x, y, button, modifiers };
|
|
18
|
+
const buttonsMask = button === 'right' ? 2 : button === 'middle' ? 4 : 1;
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < clickCount; i++) {
|
|
21
|
+
const count = i + 1;
|
|
22
|
+
await client.send(
|
|
23
|
+
'Input.dispatchMouseEvent',
|
|
24
|
+
{ ...shared, type: 'mousePressed', buttons: buttonsMask, clickCount: count },
|
|
25
|
+
sessionId,
|
|
26
|
+
);
|
|
27
|
+
await client.send(
|
|
28
|
+
'Input.dispatchMouseEvent',
|
|
29
|
+
{
|
|
30
|
+
...shared,
|
|
31
|
+
type: 'mouseReleased',
|
|
32
|
+
buttons: i < clickCount - 1 ? buttonsMask : 0,
|
|
33
|
+
clickCount: count,
|
|
34
|
+
},
|
|
35
|
+
sessionId,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function scrollElement(
|
|
41
|
+
client: CdpClient,
|
|
42
|
+
sessionId: string,
|
|
43
|
+
direction: 'up' | 'down' | 'left' | 'right',
|
|
44
|
+
amount = 300,
|
|
45
|
+
ref?: ElementRef,
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
// Cap scroll amount to prevent extreme delta values
|
|
48
|
+
amount = Math.min(Math.max(1, Math.floor(amount)), 100_000);
|
|
49
|
+
let x = 0;
|
|
50
|
+
let y = 0;
|
|
51
|
+
let deltaX = 0;
|
|
52
|
+
let deltaY = 0;
|
|
53
|
+
|
|
54
|
+
if (ref) {
|
|
55
|
+
const box = await getElementBox(client, sessionId, ref);
|
|
56
|
+
if (!box) throw new Error(`Cannot scroll: ref @${ref.ref} not found in DOM`);
|
|
57
|
+
x = box.x;
|
|
58
|
+
y = box.y;
|
|
59
|
+
} else {
|
|
60
|
+
// Center of viewport
|
|
61
|
+
const vp = await client.send<{ result: { value: string } }>(
|
|
62
|
+
'Runtime.evaluate',
|
|
63
|
+
{
|
|
64
|
+
expression: 'JSON.stringify({w: window.innerWidth, h: window.innerHeight})',
|
|
65
|
+
returnByValue: true,
|
|
66
|
+
},
|
|
67
|
+
sessionId,
|
|
68
|
+
);
|
|
69
|
+
const dims = JSON.parse(vp.result?.value ?? '{"w":1280,"h":720}');
|
|
70
|
+
x = dims.w / 2;
|
|
71
|
+
y = dims.h / 2;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
switch (direction) {
|
|
75
|
+
case 'down':
|
|
76
|
+
deltaY = amount;
|
|
77
|
+
break;
|
|
78
|
+
case 'up':
|
|
79
|
+
deltaY = -amount;
|
|
80
|
+
break;
|
|
81
|
+
case 'right':
|
|
82
|
+
deltaX = amount;
|
|
83
|
+
break;
|
|
84
|
+
case 'left':
|
|
85
|
+
deltaX = -amount;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
await client.send(
|
|
90
|
+
'Input.dispatchMouseEvent',
|
|
91
|
+
{
|
|
92
|
+
type: 'mouseWheel',
|
|
93
|
+
x,
|
|
94
|
+
y,
|
|
95
|
+
deltaX,
|
|
96
|
+
deltaY,
|
|
97
|
+
},
|
|
98
|
+
sessionId,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function hoverElement(
|
|
103
|
+
client: CdpClient,
|
|
104
|
+
sessionId: string,
|
|
105
|
+
ref: ElementRef,
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
const box = await getElementBox(client, sessionId, ref);
|
|
108
|
+
if (!box) throw new Error(`Cannot hover ref @${ref.ref}: element not found in DOM`);
|
|
109
|
+
|
|
110
|
+
await client.send(
|
|
111
|
+
'Input.dispatchMouseEvent',
|
|
112
|
+
{
|
|
113
|
+
type: 'mouseMoved',
|
|
114
|
+
x: box.x,
|
|
115
|
+
y: box.y,
|
|
116
|
+
},
|
|
117
|
+
sessionId,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function mouseMove(
|
|
122
|
+
client: CdpClient,
|
|
123
|
+
sessionId: string,
|
|
124
|
+
x: number,
|
|
125
|
+
y: number,
|
|
126
|
+
): Promise<void> {
|
|
127
|
+
await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y }, sessionId);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function mouseDown(
|
|
131
|
+
client: CdpClient,
|
|
132
|
+
sessionId: string,
|
|
133
|
+
x: number,
|
|
134
|
+
y: number,
|
|
135
|
+
button: 'left' | 'right' | 'middle' = 'left',
|
|
136
|
+
): Promise<void> {
|
|
137
|
+
const buttonsMask = button === 'right' ? 2 : button === 'middle' ? 4 : 1;
|
|
138
|
+
await client.send(
|
|
139
|
+
'Input.dispatchMouseEvent',
|
|
140
|
+
{ type: 'mousePressed', x, y, button, buttons: buttonsMask, clickCount: 1 },
|
|
141
|
+
sessionId,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function mouseUp(
|
|
146
|
+
client: CdpClient,
|
|
147
|
+
sessionId: string,
|
|
148
|
+
x: number,
|
|
149
|
+
y: number,
|
|
150
|
+
button: 'left' | 'right' | 'middle' = 'left',
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
await client.send(
|
|
153
|
+
'Input.dispatchMouseEvent',
|
|
154
|
+
{ type: 'mouseReleased', x, y, button, buttons: 0, clickCount: 1 },
|
|
155
|
+
sessionId,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function mouseWheel(
|
|
160
|
+
client: CdpClient,
|
|
161
|
+
sessionId: string,
|
|
162
|
+
x: number,
|
|
163
|
+
y: number,
|
|
164
|
+
deltaY: number,
|
|
165
|
+
deltaX = 0,
|
|
166
|
+
): Promise<void> {
|
|
167
|
+
await client.send(
|
|
168
|
+
'Input.dispatchMouseEvent',
|
|
169
|
+
{ type: 'mouseWheel', x, y, deltaX, deltaY },
|
|
170
|
+
sessionId,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export async function dragAndDrop(
|
|
175
|
+
client: CdpClient,
|
|
176
|
+
sessionId: string,
|
|
177
|
+
src: ElementRef,
|
|
178
|
+
tgt: ElementRef,
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
const srcBox = await getElementBox(client, sessionId, src);
|
|
181
|
+
const tgtBox = await getElementBox(client, sessionId, tgt);
|
|
182
|
+
if (!srcBox || !tgtBox) throw new Error('Cannot drag: one or both elements not found in DOM');
|
|
183
|
+
|
|
184
|
+
await client.send(
|
|
185
|
+
'Input.dispatchMouseEvent',
|
|
186
|
+
{ type: 'mousePressed', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1, clickCount: 1 },
|
|
187
|
+
sessionId,
|
|
188
|
+
);
|
|
189
|
+
await client.send(
|
|
190
|
+
'Input.dispatchMouseEvent',
|
|
191
|
+
{ type: 'mouseMoved', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1 },
|
|
192
|
+
sessionId,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// Move in steps for smooth drag
|
|
196
|
+
const steps = 10;
|
|
197
|
+
for (let i = 1; i <= steps; i++) {
|
|
198
|
+
const x = srcBox.x + (tgtBox.x - srcBox.x) * (i / steps);
|
|
199
|
+
const y = srcBox.y + (tgtBox.y - srcBox.y) * (i / steps);
|
|
200
|
+
await client.send(
|
|
201
|
+
'Input.dispatchMouseEvent',
|
|
202
|
+
{ type: 'mouseMoved', x, y, button: 'left', buttons: 1 },
|
|
203
|
+
sessionId,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
await client.send(
|
|
208
|
+
'Input.dispatchMouseEvent',
|
|
209
|
+
{ type: 'mouseReleased', x: tgtBox.x, y: tgtBox.y, button: 'left', buttons: 0, clickCount: 1 },
|
|
210
|
+
sessionId,
|
|
211
|
+
);
|
|
212
|
+
}
|