chrome-cdp-cli 1.2.2 → 1.3.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.
@@ -63,7 +63,7 @@ Examples:
63
63
  };
64
64
  }
65
65
  }
66
- await this.ensureDirectory(targetDir);
66
+ await this.ensureDirectoryPath(targetDir);
67
67
  const commands = this.generateCursorCommands();
68
68
  const createdFiles = [];
69
69
  for (const command of commands) {
@@ -109,89 +109,175 @@ Examples:
109
109
  logger_1.logger.info(`Created directory: ${dirPath}`);
110
110
  }
111
111
  }
112
+ async ensureDirectoryPath(targetPath) {
113
+ if (targetPath.includes('.cursor/commands') || targetPath.endsWith('.cursor/commands')) {
114
+ const cursorDir = targetPath.includes('.cursor/commands')
115
+ ? targetPath.substring(0, targetPath.indexOf('.cursor') + 7)
116
+ : path.dirname(targetPath);
117
+ await this.ensureDirectory(cursorDir);
118
+ const commandsDir = path.join(cursorDir, 'commands');
119
+ await this.ensureDirectory(commandsDir);
120
+ }
121
+ else {
122
+ await this.ensureDirectory(targetPath);
123
+ }
124
+ }
112
125
  generateCursorCommands() {
113
126
  return [
114
127
  {
115
128
  name: 'cdp-cli',
116
129
  description: 'Chrome DevTools Protocol CLI 工具',
117
- instructions: `通过 Chrome DevTools Protocol 控制 Chrome 浏览器,支持多种自动化操作。
118
-
119
- ## 功能列表
120
-
121
- ### 1. JavaScript 执行 (eval)
122
- 执行 JavaScript 代码并返回结果,支持异步代码和 Promise
123
-
124
- **用途:**
125
- - 获取页面信息(标题、URL、元素等)
126
- - 修改页面内容和样式
127
- - 执行复杂的 JavaScript 逻辑
128
- - 与页面元素交互
129
-
130
- **示例:**
131
- - \`chrome-cdp-cli eval "document.title"\`
132
- - \`chrome-cdp-cli eval "window.location.href"\`
133
- - \`chrome-cdp-cli eval "document.querySelector('#button').click()"\`
134
- - \`chrome-cdp-cli eval "fetch('/api/data').then(r => r.json())"\`
135
-
136
- ### 2. 页面截图 (screenshot)
137
- 捕获当前页面的截图并保存到指定文件。
138
-
139
- **功能:**
140
- - 指定文件名和路径
141
- - 全页面截图或视口截图
142
- - 自定义图片质量和格式
143
- - 输出 PNG 格式文件
144
-
145
- **示例:**
146
- - \`chrome-cdp-cli screenshot --filename screenshot.png\`
147
- - \`chrome-cdp-cli screenshot --filename fullpage.png --full-page\`
148
- - \`chrome-cdp-cli screenshot --filename reports/page-capture.png\`
149
-
150
- ### 3. DOM 快照 (snapshot)
151
- 捕获包含 DOM 结构、样式和布局信息的完整快照。
152
-
153
- **包含内容:**
154
- - 完整的 DOM 树结构
155
- - 计算后的 CSS 样式
156
- - 元素布局信息
157
- - 元素属性和文本内容
158
-
159
- **示例:**
160
- - \`chrome-cdp-cli snapshot --filename dom-snapshot.json\`
161
- - \`chrome-cdp-cli snapshot --filename page-structure.json\`
162
-
163
- ### 4. 控制台监控 (console)
164
- 获取浏览器控制台的消息,包括日志、警告和错误。
165
-
166
- **功能:**
167
- - 获取最新的控制台消息
168
- - 列出所有控制台消息
169
- - 按类型过滤消息(log、warn、error)
170
- - 调试和监控页面运行状态
171
-
172
- **示例:**
173
- - \`chrome-cdp-cli get_console_message\`
174
- - \`chrome-cdp-cli list_console_messages --type error\`
175
-
176
- ### 5. 网络请求监控 (network)
177
- 监控和获取页面的网络请求信息。
178
-
179
- **功能:**
180
- - 获取最新的网络请求
181
- - 列出所有网络请求
182
- - 按方法过滤请求(GET、POST 等)
183
- - 查看请求和响应详情
184
- - 分析页面的网络行为和 API 调用
185
-
186
- **示例:**
187
- - \`chrome-cdp-cli get_network_request\`
188
- - \`chrome-cdp-cli list_network_requests --method POST\`
130
+ instructions: `通过 Chrome DevTools Protocol 控制 Chrome 浏览器,支持完整的自动化操作。
131
+
132
+ ## 完整命令列表
133
+
134
+ ### 1. JavaScript 执行
135
+ - **eval** - 执行 JavaScript 代码并返回结果,支持异步代码和 Promise
136
+ \`chrome-cdp-cli eval "document.title"\`
137
+ \`chrome-cdp-cli eval "fetch('/api/data').then(r => r.json())"\`
138
+
139
+ ### 2. 页面截图和快照
140
+ - **screenshot** - 捕获页面截图并保存到文件
141
+ \`chrome-cdp-cli screenshot --filename page.png\`
142
+ \`chrome-cdp-cli screenshot --filename fullpage.png --full-page\`
143
+
144
+ - **snapshot** - 捕获完整 DOM 快照(包含结构、样式、布局)
145
+ \`chrome-cdp-cli snapshot --filename dom-snapshot.json\`
146
+
147
+ ### 3. 元素交互
148
+ - **click** - 点击页面元素
149
+ \`chrome-cdp-cli click "#submit-button"\`
150
+ \`chrome-cdp-cli click ".menu-item" --timeout 10000\`
151
+
152
+ - **hover** - 鼠标悬停在元素上
153
+ \`chrome-cdp-cli hover "#dropdown-trigger"\`
154
+
155
+ - **fill** - 填充表单字段
156
+ \`chrome-cdp-cli fill "#username" "john@example.com"\`
157
+ \`chrome-cdp-cli fill "input[name='password']" "secret123"\`
158
+
159
+ - **fill_form** - 批量填充表单
160
+ \`chrome-cdp-cli fill_form '{"#username": "john", "#password": "secret"}'\`
161
+
162
+ ### 4. 高级交互
163
+ - **drag** - 拖拽操作
164
+ \`chrome-cdp-cli drag "#draggable" "#dropzone"\`
165
+
166
+ - **press_key** - 模拟键盘输入
167
+ \`chrome-cdp-cli press_key "Enter"\`
168
+ \`chrome-cdp-cli press_key "a" --modifiers Ctrl --selector "#input"\`
169
+
170
+ - **upload_file** - 文件上传
171
+ \`chrome-cdp-cli upload_file "input[type='file']" "./document.pdf"\`
172
+
173
+ - **wait_for** - 等待元素出现或满足条件
174
+ \`chrome-cdp-cli wait_for "#loading" --condition hidden\`
175
+ \`chrome-cdp-cli wait_for "#submit-btn" --condition enabled\`
176
+
177
+ - **handle_dialog** - 处理浏览器对话框
178
+ \`chrome-cdp-cli handle_dialog accept\`
179
+ \`chrome-cdp-cli handle_dialog accept --text "user input"\`
180
+
181
+ ### 5. 监控功能
182
+ - **get_console_message** - 获取最新控制台消息
183
+ \`chrome-cdp-cli get_console_message\`
184
+
185
+ - **list_console_messages** - 列出所有控制台消息
186
+ \`chrome-cdp-cli list_console_messages --type error\`
187
+
188
+ - **get_network_request** - 获取最新网络请求
189
+ \`chrome-cdp-cli get_network_request\`
190
+
191
+ - **list_network_requests** - 列出所有网络请求
192
+ \`chrome-cdp-cli list_network_requests --method POST\`
193
+
194
+ ### 6. IDE 集成
195
+ - **install_cursor_command** - 安装 Cursor 命令
196
+ \`chrome-cdp-cli install_cursor_command\`
197
+
198
+ - **install_claude_skill** - 安装 Claude 技能
199
+ \`chrome-cdp-cli install_claude_skill --skill-type personal\`
200
+
201
+ ## 常用工作流程
202
+
203
+ ### 完整的表单测试流程
204
+ \`\`\`bash
205
+ # 1. 等待页面加载
206
+ chrome-cdp-cli wait_for "#login-form" --condition visible
207
+
208
+ # 2. 填写表单
209
+ chrome-cdp-cli fill "#email" "test@example.com"
210
+ chrome-cdp-cli fill "#password" "password123"
211
+
212
+ # 3. 提交表单
213
+ chrome-cdp-cli click "#submit-button"
214
+
215
+ # 4. 等待结果并截图
216
+ chrome-cdp-cli wait_for "#success-message" --condition visible
217
+ chrome-cdp-cli screenshot --filename login-success.png
218
+
219
+ # 5. 检查控制台错误
220
+ chrome-cdp-cli list_console_messages --type error
221
+ \`\`\`
222
+
223
+ ### 文件上传测试
224
+ \`\`\`bash
225
+ # 1. 点击上传按钮
226
+ chrome-cdp-cli click "#upload-trigger"
227
+
228
+ # 2. 上传文件
229
+ chrome-cdp-cli upload_file "input[type='file']" "./test-document.pdf"
230
+
231
+ # 3. 等待上传完成
232
+ chrome-cdp-cli wait_for ".upload-success" --condition visible
233
+
234
+ # 4. 验证结果
235
+ chrome-cdp-cli eval "document.querySelector('.file-name').textContent"
236
+ \`\`\`
237
+
238
+ ### 拖拽交互测试
239
+ \`\`\`bash
240
+ # 1. 等待元素可用
241
+ chrome-cdp-cli wait_for "#draggable-item" --condition visible
242
+ chrome-cdp-cli wait_for "#drop-zone" --condition visible
243
+
244
+ # 2. 执行拖拽
245
+ chrome-cdp-cli drag "#draggable-item" "#drop-zone"
246
+
247
+ # 3. 验证拖拽结果
248
+ chrome-cdp-cli eval "document.querySelector('#drop-zone').children.length"
249
+ \`\`\`
250
+
251
+ ### 键盘导航测试
252
+ \`\`\`bash
253
+ # 1. 聚焦到输入框
254
+ chrome-cdp-cli click "#search-input"
255
+
256
+ # 2. 输入文本
257
+ chrome-cdp-cli press_key "t"
258
+ chrome-cdp-cli press_key "e"
259
+ chrome-cdp-cli press_key "s"
260
+ chrome-cdp-cli press_key "t"
261
+
262
+ # 3. 使用快捷键
263
+ chrome-cdp-cli press_key "a" --modifiers Ctrl # 全选
264
+ chrome-cdp-cli press_key "Enter" # 提交
265
+
266
+ # 4. 处理可能的确认对话框
267
+ chrome-cdp-cli handle_dialog accept
268
+ \`\`\`
189
269
 
190
270
  命令会自动连接到运行在 localhost:9222 的 Chrome 实例。`,
191
271
  examples: [
192
272
  'chrome-cdp-cli eval "document.title"',
193
273
  'chrome-cdp-cli screenshot --filename page.png',
194
- 'chrome-cdp-cli snapshot --filename dom.json',
274
+ 'chrome-cdp-cli click "#submit-button"',
275
+ 'chrome-cdp-cli fill "#username" "test@example.com"',
276
+ 'chrome-cdp-cli drag "#item" "#target"',
277
+ 'chrome-cdp-cli press_key "Enter"',
278
+ 'chrome-cdp-cli upload_file "input[type=file]" "./doc.pdf"',
279
+ 'chrome-cdp-cli wait_for "#loading" --condition hidden',
280
+ 'chrome-cdp-cli handle_dialog accept',
195
281
  'chrome-cdp-cli get_console_message',
196
282
  'chrome-cdp-cli list_network_requests'
197
283
  ]
@@ -274,6 +360,54 @@ chrome-cdp-cli snapshot --filename page-analysis.json
274
360
  # 3. 检查控制台错误
275
361
  chrome-cdp-cli list_console_messages --type error
276
362
  \`\`\`
363
+ `;
364
+ }
365
+ getHelp() {
366
+ return `
367
+ install-cursor-command - Install Cursor IDE commands for Chrome browser automation
368
+
369
+ Usage:
370
+ install-cursor-command
371
+ install-cursor-command --target-directory /path/to/.cursor/commands
372
+ install-cursor-command --force
373
+
374
+ Arguments:
375
+ --target-directory <path> Custom installation directory (default: .cursor/commands)
376
+ --include-examples Include example usage (default: true)
377
+ --force Force installation without directory validation
378
+
379
+ Description:
380
+ Installs a unified Cursor command file (cdp-cli.md) that provides Chrome browser
381
+ automation capabilities directly within Cursor IDE. The command includes:
382
+
383
+ • JavaScript execution in browser context
384
+ • Screenshot capture and DOM snapshots
385
+ • Console and network monitoring
386
+ • Complete automation workflows
387
+ • Comprehensive examples and documentation
388
+
389
+ Directory Validation:
390
+ By default, the command checks for a .cursor directory to ensure you're in a
391
+ Cursor project root. Use --force to bypass this validation or --target-directory
392
+ to specify a custom location.
393
+
394
+ Examples:
395
+ # Install in current project (requires .cursor directory)
396
+ install-cursor-command
397
+
398
+ # Install with custom directory
399
+ install-cursor-command --target-directory /path/to/.cursor/commands
400
+
401
+ # Force install without validation
402
+ install-cursor-command --force
403
+
404
+ # After installation, use in Cursor with:
405
+ /cdp-cli
406
+
407
+ Note:
408
+ The installed command provides powerful browser automation through the eval
409
+ approach, which is ideal for LLM-assisted development as it allows writing
410
+ and testing JavaScript automation scripts quickly and flexibly.
277
411
  `;
278
412
  }
279
413
  }
@@ -0,0 +1,337 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PressKeyHandler = void 0;
4
+ class PressKeyHandler {
5
+ constructor() {
6
+ this.name = 'press_key';
7
+ }
8
+ async execute(client, args) {
9
+ const keyArgs = args;
10
+ if (!keyArgs.key) {
11
+ return {
12
+ success: false,
13
+ error: 'Key is required for press_key command'
14
+ };
15
+ }
16
+ if (typeof keyArgs.key !== 'string') {
17
+ return {
18
+ success: false,
19
+ error: 'Key must be a string'
20
+ };
21
+ }
22
+ try {
23
+ await client.send('Runtime.enable');
24
+ const timeout = keyArgs.timeout || 5000;
25
+ const waitForElement = keyArgs.waitForElement !== false;
26
+ if (keyArgs.selector) {
27
+ if (waitForElement) {
28
+ const elementFound = await this.waitForElement(client, keyArgs.selector, timeout);
29
+ if (!elementFound) {
30
+ return {
31
+ success: false,
32
+ error: `Element with selector "${keyArgs.selector}" not found within ${timeout}ms`
33
+ };
34
+ }
35
+ }
36
+ const focusResult = await this.focusElement(client, keyArgs.selector);
37
+ if (!focusResult.success) {
38
+ return focusResult;
39
+ }
40
+ }
41
+ const result = await this.pressKeyViaEval(client, keyArgs.key, keyArgs.modifiers || [], keyArgs.selector);
42
+ return result;
43
+ }
44
+ catch (error) {
45
+ return {
46
+ success: false,
47
+ error: error instanceof Error ? error.message : String(error)
48
+ };
49
+ }
50
+ }
51
+ async waitForElement(client, selector, timeout) {
52
+ const startTime = Date.now();
53
+ while (Date.now() - startTime < timeout) {
54
+ try {
55
+ const result = await client.send('Runtime.evaluate', {
56
+ expression: `document.querySelector('${selector.replace(/'/g, "\\'")}') !== null`,
57
+ returnByValue: true
58
+ });
59
+ if (result.result.value) {
60
+ return true;
61
+ }
62
+ await new Promise(resolve => setTimeout(resolve, 100));
63
+ }
64
+ catch (error) {
65
+ await new Promise(resolve => setTimeout(resolve, 100));
66
+ }
67
+ }
68
+ return false;
69
+ }
70
+ async focusElement(client, selector) {
71
+ try {
72
+ const escapedSelector = selector.replace(/'/g, "\\'").replace(/"/g, '\\"');
73
+ const expression = `
74
+ (function() {
75
+ const element = document.querySelector('${escapedSelector}');
76
+ if (!element) {
77
+ throw new Error('Element with selector "${escapedSelector}" not found');
78
+ }
79
+
80
+ element.focus();
81
+
82
+ return {
83
+ success: true,
84
+ tagName: element.tagName,
85
+ id: element.id,
86
+ className: element.className
87
+ };
88
+ })()
89
+ `;
90
+ const response = await client.send('Runtime.evaluate', {
91
+ expression: expression,
92
+ returnByValue: true,
93
+ userGesture: true
94
+ });
95
+ if (response.exceptionDetails) {
96
+ return {
97
+ success: false,
98
+ error: response.exceptionDetails.exception?.description || response.exceptionDetails.text
99
+ };
100
+ }
101
+ return {
102
+ success: true,
103
+ data: response.result.value
104
+ };
105
+ }
106
+ catch (error) {
107
+ return {
108
+ success: false,
109
+ error: `Focus failed: ${error instanceof Error ? error.message : String(error)}`
110
+ };
111
+ }
112
+ }
113
+ async pressKeyViaEval(client, key, modifiers, selector) {
114
+ try {
115
+ const escapedKey = key.replace(/'/g, "\\'").replace(/"/g, '\\"');
116
+ const modifierFlags = {
117
+ ctrlKey: modifiers.includes('Ctrl') || modifiers.includes('Control'),
118
+ altKey: modifiers.includes('Alt'),
119
+ shiftKey: modifiers.includes('Shift'),
120
+ metaKey: modifiers.includes('Meta') || modifiers.includes('Cmd')
121
+ };
122
+ const expression = `
123
+ (function() {
124
+ const key = '${escapedKey}';
125
+ const modifiers = ${JSON.stringify(modifierFlags)};
126
+
127
+ // Determine target element
128
+ let targetElement = document.activeElement;
129
+ ${selector ? `
130
+ const specifiedElement = document.querySelector('${selector.replace(/'/g, "\\'")}');
131
+ if (specifiedElement) {
132
+ targetElement = specifiedElement;
133
+ }
134
+ ` : ''}
135
+
136
+ if (!targetElement) {
137
+ targetElement = document.body;
138
+ }
139
+
140
+ // Create keyboard event options
141
+ const eventOptions = {
142
+ key: key,
143
+ code: key.length === 1 ? 'Key' + key.toUpperCase() : key,
144
+ bubbles: true,
145
+ cancelable: true,
146
+ view: window,
147
+ ctrlKey: modifiers.ctrlKey,
148
+ altKey: modifiers.altKey,
149
+ shiftKey: modifiers.shiftKey,
150
+ metaKey: modifiers.metaKey
151
+ };
152
+
153
+ // Handle special keys
154
+ const specialKeys = {
155
+ 'Enter': { code: 'Enter', keyCode: 13 },
156
+ 'Escape': { code: 'Escape', keyCode: 27 },
157
+ 'Tab': { code: 'Tab', keyCode: 9 },
158
+ 'Backspace': { code: 'Backspace', keyCode: 8 },
159
+ 'Delete': { code: 'Delete', keyCode: 46 },
160
+ 'ArrowUp': { code: 'ArrowUp', keyCode: 38 },
161
+ 'ArrowDown': { code: 'ArrowDown', keyCode: 40 },
162
+ 'ArrowLeft': { code: 'ArrowLeft', keyCode: 37 },
163
+ 'ArrowRight': { code: 'ArrowRight', keyCode: 39 },
164
+ 'Home': { code: 'Home', keyCode: 36 },
165
+ 'End': { code: 'End', keyCode: 35 },
166
+ 'PageUp': { code: 'PageUp', keyCode: 33 },
167
+ 'PageDown': { code: 'PageDown', keyCode: 34 },
168
+ 'Space': { code: 'Space', keyCode: 32, key: ' ' }
169
+ };
170
+
171
+ if (specialKeys[key]) {
172
+ eventOptions.code = specialKeys[key].code;
173
+ eventOptions.keyCode = specialKeys[key].keyCode;
174
+ if (specialKeys[key].key) {
175
+ eventOptions.key = specialKeys[key].key;
176
+ }
177
+ }
178
+
179
+ // Create and dispatch keydown event
180
+ const keydownEvent = new KeyboardEvent('keydown', eventOptions);
181
+ targetElement.dispatchEvent(keydownEvent);
182
+
183
+ // Create and dispatch keypress event (for printable characters)
184
+ if (key.length === 1 || key === 'Enter' || key === 'Space') {
185
+ const keypressEvent = new KeyboardEvent('keypress', eventOptions);
186
+ targetElement.dispatchEvent(keypressEvent);
187
+ }
188
+
189
+ // Create and dispatch keyup event
190
+ const keyupEvent = new KeyboardEvent('keyup', eventOptions);
191
+ targetElement.dispatchEvent(keyupEvent);
192
+
193
+ // For input elements, also trigger input event if it's a printable character
194
+ if ((targetElement.tagName === 'INPUT' || targetElement.tagName === 'TEXTAREA') &&
195
+ key.length === 1 && !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey) {
196
+ // Add character to input value
197
+ const currentValue = targetElement.value || '';
198
+ const cursorPos = targetElement.selectionStart || currentValue.length;
199
+ const newValue = currentValue.slice(0, cursorPos) + key + currentValue.slice(cursorPos);
200
+ targetElement.value = newValue;
201
+ targetElement.selectionStart = targetElement.selectionEnd = cursorPos + 1;
202
+
203
+ // Trigger input and change events
204
+ targetElement.dispatchEvent(new Event('input', { bubbles: true }));
205
+ targetElement.dispatchEvent(new Event('change', { bubbles: true }));
206
+ }
207
+
208
+ return {
209
+ success: true,
210
+ key: key,
211
+ modifiers: modifiers,
212
+ target: {
213
+ tagName: targetElement.tagName,
214
+ id: targetElement.id,
215
+ className: targetElement.className,
216
+ value: targetElement.value || null
217
+ }
218
+ };
219
+ })()
220
+ `;
221
+ const response = await client.send('Runtime.evaluate', {
222
+ expression: expression,
223
+ returnByValue: true,
224
+ userGesture: true
225
+ });
226
+ if (response.exceptionDetails) {
227
+ return {
228
+ success: false,
229
+ error: response.exceptionDetails.exception?.description || response.exceptionDetails.text
230
+ };
231
+ }
232
+ return {
233
+ success: true,
234
+ data: {
235
+ key: key,
236
+ modifiers: modifiers,
237
+ selector: selector,
238
+ result: response.result.value
239
+ }
240
+ };
241
+ }
242
+ catch (error) {
243
+ return {
244
+ success: false,
245
+ error: `Key press failed: ${error instanceof Error ? error.message : String(error)}`
246
+ };
247
+ }
248
+ }
249
+ validateArgs(args) {
250
+ if (typeof args !== 'object' || args === null) {
251
+ return false;
252
+ }
253
+ const keyArgs = args;
254
+ if (!keyArgs.key || typeof keyArgs.key !== 'string') {
255
+ return false;
256
+ }
257
+ if (keyArgs.selector !== undefined && typeof keyArgs.selector !== 'string') {
258
+ return false;
259
+ }
260
+ if (keyArgs.modifiers !== undefined && !Array.isArray(keyArgs.modifiers)) {
261
+ return false;
262
+ }
263
+ if (keyArgs.modifiers && !keyArgs.modifiers.every(mod => typeof mod === 'string')) {
264
+ return false;
265
+ }
266
+ if (keyArgs.waitForElement !== undefined && typeof keyArgs.waitForElement !== 'boolean') {
267
+ return false;
268
+ }
269
+ if (keyArgs.timeout !== undefined && typeof keyArgs.timeout !== 'number') {
270
+ return false;
271
+ }
272
+ return true;
273
+ }
274
+ getHelp() {
275
+ return `
276
+ press_key - Simulate keyboard input
277
+
278
+ Usage:
279
+ press_key <key>
280
+ press_key <key> --selector <selector>
281
+ press_key <key> --modifiers Ctrl,Shift
282
+ press_key "Enter" --selector "#input-field"
283
+
284
+ Arguments:
285
+ <key> Key to press (e.g., 'Enter', 'Escape', 'a', 'ArrowDown')
286
+
287
+ Options:
288
+ --selector <selector> CSS selector to focus element first
289
+ --modifiers <list> Comma-separated modifiers: Ctrl, Alt, Shift, Meta
290
+ --wait-for-element Wait for element to be available if selector provided (default: true)
291
+ --no-wait Don't wait for element
292
+ --timeout <ms> Timeout for waiting for element (default: 5000ms)
293
+
294
+ Examples:
295
+ # Press Enter key
296
+ press_key "Enter"
297
+
298
+ # Press Enter in a specific input field
299
+ press_key "Enter" --selector "#search-input"
300
+
301
+ # Press Ctrl+A to select all
302
+ press_key "a" --modifiers Ctrl
303
+
304
+ # Press Escape key
305
+ press_key "Escape"
306
+
307
+ # Press arrow keys for navigation
308
+ press_key "ArrowDown"
309
+ press_key "ArrowUp"
310
+
311
+ # Type a character in focused element
312
+ press_key "a"
313
+
314
+ # Press Tab to navigate
315
+ press_key "Tab"
316
+
317
+ # Press with multiple modifiers
318
+ press_key "s" --modifiers Ctrl,Shift
319
+
320
+ Supported Keys:
321
+ - Letters: a-z, A-Z
322
+ - Numbers: 0-9
323
+ - Special: Enter, Escape, Tab, Backspace, Delete, Space
324
+ - Arrows: ArrowUp, ArrowDown, ArrowLeft, ArrowRight
325
+ - Navigation: Home, End, PageUp, PageDown
326
+ - Modifiers: Ctrl, Alt, Shift, Meta
327
+
328
+ Note:
329
+ - Uses JavaScript KeyboardEvent simulation
330
+ - Dispatches keydown, keypress (for printable chars), and keyup events
331
+ - For input fields, automatically updates value and triggers input/change events
332
+ - If selector is provided, focuses the element first
333
+ - Works with keyboard event listeners and form validation
334
+ `;
335
+ }
336
+ }
337
+ exports.PressKeyHandler = PressKeyHandler;