chrome-cdp-cli 1.0.2 → 1.2.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/README.md +364 -37
- package/dist/cli/CLIApplication.js +13 -1
- package/dist/cli/CLIInterface.js +20 -0
- package/dist/cli/CommandRouter.js +20 -1
- package/dist/handlers/GetConsoleMessageHandler.js +91 -0
- package/dist/handlers/GetNetworkRequestHandler.js +50 -0
- package/dist/handlers/InstallClaudeSkillHandler.js +423 -0
- package/dist/handlers/InstallCursorCommandHandler.js +280 -0
- package/dist/handlers/ListConsoleMessagesHandler.js +114 -0
- package/dist/handlers/ListNetworkRequestsHandler.js +51 -0
- package/dist/handlers/index.js +6 -0
- package/dist/monitors/ConsoleMonitor.js +121 -0
- package/dist/monitors/NetworkMonitor.js +162 -0
- package/dist/monitors/index.js +18 -0
- package/package.json +3 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetNetworkRequestHandler = void 0;
|
|
4
|
+
const NetworkMonitor_1 = require("../monitors/NetworkMonitor");
|
|
5
|
+
class GetNetworkRequestHandler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.name = 'get_network_request';
|
|
8
|
+
this.networkMonitor = null;
|
|
9
|
+
}
|
|
10
|
+
async execute(client, args) {
|
|
11
|
+
try {
|
|
12
|
+
const params = args;
|
|
13
|
+
if (!this.networkMonitor) {
|
|
14
|
+
this.networkMonitor = new NetworkMonitor_1.NetworkMonitor(client);
|
|
15
|
+
}
|
|
16
|
+
if (!this.networkMonitor.isActive()) {
|
|
17
|
+
await this.networkMonitor.startMonitoring();
|
|
18
|
+
}
|
|
19
|
+
const filter = params.filter ? {
|
|
20
|
+
methods: params.filter.methods,
|
|
21
|
+
urlPattern: params.filter.urlPattern,
|
|
22
|
+
statusCodes: params.filter.statusCodes,
|
|
23
|
+
} : undefined;
|
|
24
|
+
const latestRequest = this.networkMonitor.getLatestRequest(filter);
|
|
25
|
+
if (!latestRequest) {
|
|
26
|
+
return {
|
|
27
|
+
success: true,
|
|
28
|
+
data: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
data: latestRequest
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
getNetworkMonitor() {
|
|
44
|
+
return this.networkMonitor;
|
|
45
|
+
}
|
|
46
|
+
setNetworkMonitor(monitor) {
|
|
47
|
+
this.networkMonitor = monitor;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.GetNetworkRequestHandler = GetNetworkRequestHandler;
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.InstallClaudeSkillHandler = void 0;
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const logger_1 = require("../utils/logger");
|
|
41
|
+
class InstallClaudeSkillHandler {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.name = 'install_claude_skill';
|
|
44
|
+
}
|
|
45
|
+
async execute(_client, args) {
|
|
46
|
+
try {
|
|
47
|
+
const skillType = args.skillType || 'project';
|
|
48
|
+
const targetDir = args.targetDirectory || this.getDefaultSkillDirectory(skillType);
|
|
49
|
+
const skillDir = path.join(targetDir, 'cdp-cli');
|
|
50
|
+
if (!args.targetDirectory && !args.force) {
|
|
51
|
+
if (skillType === 'project') {
|
|
52
|
+
const claudeDirExists = await this.checkDirectoryExists('.claude');
|
|
53
|
+
if (!claudeDirExists) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: `Warning: No .claude directory found in current directory. This may not be a project root directory.
|
|
57
|
+
|
|
58
|
+
To install Claude skills:
|
|
59
|
+
1. Navigate to your project root directory (where .claude folder should be), or
|
|
60
|
+
2. Use --skill-type personal to install to your home directory, or
|
|
61
|
+
3. Use --target-directory to specify a custom location, or
|
|
62
|
+
4. Use --force to install anyway
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
chrome-cdp-cli install-claude-skill --skill-type personal
|
|
66
|
+
chrome-cdp-cli install-claude-skill --target-directory /path/to/.claude/skills
|
|
67
|
+
chrome-cdp-cli install-claude-skill --force`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
await this.ensureDirectory(skillDir);
|
|
73
|
+
const skillConfig = this.generateClaudeSkill();
|
|
74
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
75
|
+
await fs.writeFile(skillPath, this.generateSkillMarkdown(skillConfig), 'utf8');
|
|
76
|
+
logger_1.logger.info(`Created Claude skill: ${skillPath}`);
|
|
77
|
+
const createdFiles = ['SKILL.md'];
|
|
78
|
+
if (args.includeExamples) {
|
|
79
|
+
const examplesPath = path.join(skillDir, 'examples.md');
|
|
80
|
+
await fs.writeFile(examplesPath, this.generateExamplesMarkdown(), 'utf8');
|
|
81
|
+
createdFiles.push('examples.md');
|
|
82
|
+
logger_1.logger.info(`Created examples file: ${examplesPath}`);
|
|
83
|
+
}
|
|
84
|
+
if (args.includeReferences) {
|
|
85
|
+
const referencePath = path.join(skillDir, 'reference.md');
|
|
86
|
+
await fs.writeFile(referencePath, this.generateReferenceMarkdown(), 'utf8');
|
|
87
|
+
createdFiles.push('reference.md');
|
|
88
|
+
logger_1.logger.info(`Created reference file: ${referencePath}`);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
data: {
|
|
93
|
+
skillType,
|
|
94
|
+
directory: skillDir,
|
|
95
|
+
files: createdFiles,
|
|
96
|
+
skillName: skillConfig.name
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
logger_1.logger.error('Failed to install Claude skill:', error);
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async checkDirectoryExists(dirPath) {
|
|
109
|
+
try {
|
|
110
|
+
await fs.access(dirPath);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async ensureDirectory(dirPath) {
|
|
118
|
+
try {
|
|
119
|
+
await fs.access(dirPath);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
123
|
+
logger_1.logger.info(`Created directory: ${dirPath}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
getDefaultSkillDirectory(skillType) {
|
|
127
|
+
return skillType === 'personal'
|
|
128
|
+
? path.join(os.homedir(), '.claude', 'skills')
|
|
129
|
+
: '.claude/skills';
|
|
130
|
+
}
|
|
131
|
+
generateClaudeSkill() {
|
|
132
|
+
return {
|
|
133
|
+
name: 'cdp-cli',
|
|
134
|
+
description: 'Chrome browser automation and testing using DevTools Protocol. Use when user needs to control Chrome browser, execute JavaScript, take screenshots, monitor console/network, or perform web automation tasks.',
|
|
135
|
+
instructions: `# Chrome Browser Automation
|
|
136
|
+
|
|
137
|
+
## Instructions
|
|
138
|
+
Use this skill when the user needs to:
|
|
139
|
+
- Execute JavaScript code in Chrome browser
|
|
140
|
+
- Take screenshots of web pages
|
|
141
|
+
- Capture DOM snapshots with layout information
|
|
142
|
+
- Monitor console messages and network requests
|
|
143
|
+
- Perform web automation and testing
|
|
144
|
+
|
|
145
|
+
## Available Commands
|
|
146
|
+
1. **eval**: Execute JavaScript code in browser context
|
|
147
|
+
2. **screenshot**: Capture page screenshots
|
|
148
|
+
3. **snapshot**: Capture complete DOM snapshots
|
|
149
|
+
4. **get_console_message**: Get latest console message
|
|
150
|
+
5. **list_console_messages**: List all console messages
|
|
151
|
+
6. **get_network_request**: Get latest network request
|
|
152
|
+
7. **list_network_requests**: List all network requests
|
|
153
|
+
|
|
154
|
+
## Usage Examples
|
|
155
|
+
- Execute: chrome-cdp-cli eval "document.title"
|
|
156
|
+
- Screenshot: chrome-cdp-cli screenshot --filename page.png
|
|
157
|
+
- Console: chrome-cdp-cli get_console_message
|
|
158
|
+
- Network: chrome-cdp-cli list_network_requests
|
|
159
|
+
|
|
160
|
+
## Prerequisites
|
|
161
|
+
Chrome browser must be running with DevTools enabled:
|
|
162
|
+
chrome --remote-debugging-port=9222`,
|
|
163
|
+
allowedTools: ['Execute', 'Read', 'Write']
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
generateSkillMarkdown(skill) {
|
|
167
|
+
const frontmatter = `---
|
|
168
|
+
name: ${skill.name}
|
|
169
|
+
description: ${skill.description}
|
|
170
|
+
${skill.allowedTools ? `allowedTools: [${skill.allowedTools.map(t => `"${t}"`).join(', ')}]` : ''}
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
`;
|
|
174
|
+
return frontmatter + skill.instructions;
|
|
175
|
+
}
|
|
176
|
+
generateExamplesMarkdown() {
|
|
177
|
+
return `# Chrome Automation Examples
|
|
178
|
+
|
|
179
|
+
## Basic JavaScript Execution
|
|
180
|
+
|
|
181
|
+
### Get Page Information
|
|
182
|
+
\`\`\`bash
|
|
183
|
+
chrome-cdp-cli eval "document.title"
|
|
184
|
+
chrome-cdp-cli eval "window.location.href"
|
|
185
|
+
chrome-cdp-cli eval "document.querySelectorAll('a').length"
|
|
186
|
+
\`\`\`
|
|
187
|
+
|
|
188
|
+
### Interact with Elements
|
|
189
|
+
\`\`\`bash
|
|
190
|
+
chrome-cdp-cli eval "document.querySelector('#button').click()"
|
|
191
|
+
chrome-cdp-cli eval "document.querySelector('#input').value = 'Hello World'"
|
|
192
|
+
chrome-cdp-cli eval "document.querySelector('#form').submit()"
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
### Async Operations
|
|
196
|
+
\`\`\`bash
|
|
197
|
+
chrome-cdp-cli eval "fetch('/api/data').then(r => r.json())"
|
|
198
|
+
chrome-cdp-cli eval "new Promise(resolve => setTimeout(() => resolve('Done'), 1000))"
|
|
199
|
+
\`\`\`
|
|
200
|
+
|
|
201
|
+
## Visual Capture
|
|
202
|
+
|
|
203
|
+
### Screenshots
|
|
204
|
+
\`\`\`bash
|
|
205
|
+
chrome-cdp-cli screenshot --filename homepage.png
|
|
206
|
+
chrome-cdp-cli screenshot --filename fullpage.png --fullpage
|
|
207
|
+
\`\`\`
|
|
208
|
+
|
|
209
|
+
### DOM Snapshots
|
|
210
|
+
\`\`\`bash
|
|
211
|
+
chrome-cdp-cli snapshot --filename page-structure.json
|
|
212
|
+
\`\`\`
|
|
213
|
+
|
|
214
|
+
## Monitoring
|
|
215
|
+
|
|
216
|
+
### Console Messages
|
|
217
|
+
\`\`\`bash
|
|
218
|
+
chrome-cdp-cli get_console_message
|
|
219
|
+
chrome-cdp-cli list_console_messages --type error
|
|
220
|
+
\`\`\`
|
|
221
|
+
|
|
222
|
+
### Network Requests
|
|
223
|
+
\`\`\`bash
|
|
224
|
+
chrome-cdp-cli get_network_request
|
|
225
|
+
chrome-cdp-cli list_network_requests --method POST
|
|
226
|
+
\`\`\`
|
|
227
|
+
|
|
228
|
+
## Common Workflows
|
|
229
|
+
|
|
230
|
+
### Testing Form Submission
|
|
231
|
+
\`\`\`bash
|
|
232
|
+
# Fill form
|
|
233
|
+
chrome-cdp-cli eval "document.querySelector('#email').value = 'test@example.com'"
|
|
234
|
+
chrome-cdp-cli eval "document.querySelector('#password').value = 'password123'"
|
|
235
|
+
|
|
236
|
+
# Submit and capture
|
|
237
|
+
chrome-cdp-cli eval "document.querySelector('#submit').click()"
|
|
238
|
+
chrome-cdp-cli screenshot --filename after-submit.png
|
|
239
|
+
|
|
240
|
+
# Check for errors
|
|
241
|
+
chrome-cdp-cli list_console_messages --type error
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
### API Testing
|
|
245
|
+
\`\`\`bash
|
|
246
|
+
# Make API call
|
|
247
|
+
chrome-cdp-cli eval "fetch('/api/users', {method: 'POST', body: JSON.stringify({name: 'John'}), headers: {'Content-Type': 'application/json'}})"
|
|
248
|
+
|
|
249
|
+
# Monitor network
|
|
250
|
+
chrome-cdp-cli list_network_requests --method POST
|
|
251
|
+
|
|
252
|
+
# Check response
|
|
253
|
+
chrome-cdp-cli get_network_request
|
|
254
|
+
\`\`\`
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
generateReferenceMarkdown() {
|
|
258
|
+
return `# Chrome DevTools CLI Reference
|
|
259
|
+
|
|
260
|
+
## Command Reference
|
|
261
|
+
|
|
262
|
+
### eval
|
|
263
|
+
Execute JavaScript code in the browser context.
|
|
264
|
+
|
|
265
|
+
**Syntax:** \`chrome-cdp-cli eval <expression>\`
|
|
266
|
+
|
|
267
|
+
**Options:**
|
|
268
|
+
- \`--timeout <ms>\`: Execution timeout in milliseconds
|
|
269
|
+
- \`--await-promise\`: Wait for Promise resolution (default: true)
|
|
270
|
+
|
|
271
|
+
**Examples:**
|
|
272
|
+
- \`chrome-cdp-cli eval "document.title"\`
|
|
273
|
+
- \`chrome-cdp-cli eval "fetch('/api').then(r => r.text())"\`
|
|
274
|
+
|
|
275
|
+
### screenshot
|
|
276
|
+
Capture a screenshot of the current page.
|
|
277
|
+
|
|
278
|
+
**Syntax:** \`chrome-cdp-cli screenshot [options]\`
|
|
279
|
+
|
|
280
|
+
**Options:**
|
|
281
|
+
- \`--filename <path>\`: Output filename (default: screenshot.png)
|
|
282
|
+
- \`--fullpage\`: Capture full page instead of viewport
|
|
283
|
+
- \`--quality <0-100>\`: JPEG quality (default: 90)
|
|
284
|
+
|
|
285
|
+
### snapshot
|
|
286
|
+
Capture a complete DOM snapshot with layout information.
|
|
287
|
+
|
|
288
|
+
**Syntax:** \`chrome-cdp-cli snapshot [options]\`
|
|
289
|
+
|
|
290
|
+
**Options:**
|
|
291
|
+
- \`--filename <path>\`: Output filename (default: snapshot.json)
|
|
292
|
+
- \`--include-styles\`: Include computed styles (default: true)
|
|
293
|
+
- \`--include-layout\`: Include layout information (default: true)
|
|
294
|
+
|
|
295
|
+
### get_console_message
|
|
296
|
+
Get the latest console message.
|
|
297
|
+
|
|
298
|
+
**Syntax:** \`chrome-cdp-cli get_console_message [options]\`
|
|
299
|
+
|
|
300
|
+
**Options:**
|
|
301
|
+
- \`--type <log|info|warn|error>\`: Filter by message type
|
|
302
|
+
|
|
303
|
+
### list_console_messages
|
|
304
|
+
List all console messages.
|
|
305
|
+
|
|
306
|
+
**Syntax:** \`chrome-cdp-cli list_console_messages [options]\`
|
|
307
|
+
|
|
308
|
+
**Options:**
|
|
309
|
+
- \`--type <log|info|warn|error>\`: Filter by message type
|
|
310
|
+
- \`--limit <number>\`: Maximum number of messages to return
|
|
311
|
+
|
|
312
|
+
### get_network_request
|
|
313
|
+
Get the latest network request.
|
|
314
|
+
|
|
315
|
+
**Syntax:** \`chrome-cdp-cli get_network_request [options]\`
|
|
316
|
+
|
|
317
|
+
**Options:**
|
|
318
|
+
- \`--method <GET|POST|PUT|DELETE>\`: Filter by HTTP method
|
|
319
|
+
|
|
320
|
+
### list_network_requests
|
|
321
|
+
List all network requests.
|
|
322
|
+
|
|
323
|
+
**Syntax:** \`chrome-cdp-cli list_network_requests [options]\`
|
|
324
|
+
|
|
325
|
+
**Options:**
|
|
326
|
+
- \`--method <GET|POST|PUT|DELETE>\`: Filter by HTTP method
|
|
327
|
+
- \`--limit <number>\`: Maximum number of requests to return
|
|
328
|
+
|
|
329
|
+
## Global Options
|
|
330
|
+
|
|
331
|
+
- \`--host <hostname>\`: Chrome DevTools host (default: localhost)
|
|
332
|
+
- \`--port <number>\`: Chrome DevTools port (default: 9222)
|
|
333
|
+
- \`--output-format <json|text>\`: Output format (default: json)
|
|
334
|
+
- \`--verbose\`: Enable verbose logging
|
|
335
|
+
- \`--quiet\`: Suppress non-error output
|
|
336
|
+
- \`--timeout <ms>\`: Global timeout for operations
|
|
337
|
+
|
|
338
|
+
## Chrome Setup
|
|
339
|
+
|
|
340
|
+
### Starting Chrome with DevTools
|
|
341
|
+
\`\`\`bash
|
|
342
|
+
# Linux/Windows
|
|
343
|
+
chrome --remote-debugging-port=9222
|
|
344
|
+
|
|
345
|
+
# macOS
|
|
346
|
+
/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --remote-debugging-port=9222
|
|
347
|
+
|
|
348
|
+
# With additional options
|
|
349
|
+
chrome --remote-debugging-port=9222 --disable-web-security --user-data-dir=/tmp/chrome-debug
|
|
350
|
+
\`\`\`
|
|
351
|
+
|
|
352
|
+
### Headless Mode
|
|
353
|
+
\`\`\`bash
|
|
354
|
+
chrome --headless --remote-debugging-port=9222
|
|
355
|
+
\`\`\`
|
|
356
|
+
|
|
357
|
+
## Error Handling
|
|
358
|
+
|
|
359
|
+
### Common Errors
|
|
360
|
+
- **Connection refused**: Chrome is not running or DevTools port is incorrect
|
|
361
|
+
- **Target not found**: No active tab or page available
|
|
362
|
+
- **JavaScript error**: Syntax error or runtime exception in eval expression
|
|
363
|
+
- **Timeout**: Operation took longer than specified timeout
|
|
364
|
+
|
|
365
|
+
### Debugging Tips
|
|
366
|
+
- Use \`--verbose\` flag for detailed logging
|
|
367
|
+
- Check Chrome DevTools at \`http://localhost:9222\` for available targets
|
|
368
|
+
- Verify JavaScript syntax before executing with eval
|
|
369
|
+
- Use shorter timeouts for testing, longer for complex operations
|
|
370
|
+
|
|
371
|
+
## Integration Examples
|
|
372
|
+
|
|
373
|
+
### CI/CD Pipeline
|
|
374
|
+
\`\`\`yaml
|
|
375
|
+
# GitHub Actions example
|
|
376
|
+
- name: Test web application
|
|
377
|
+
run: |
|
|
378
|
+
# Start Chrome
|
|
379
|
+
google-chrome --headless --remote-debugging-port=9222 &
|
|
380
|
+
|
|
381
|
+
# Wait for Chrome to start
|
|
382
|
+
sleep 2
|
|
383
|
+
|
|
384
|
+
# Navigate to application
|
|
385
|
+
chrome-cdp-cli eval "window.location.href = 'http://localhost:3000'"
|
|
386
|
+
|
|
387
|
+
# Run tests
|
|
388
|
+
chrome-cdp-cli eval "document.querySelector('#test-button').click()"
|
|
389
|
+
chrome-cdp-cli screenshot --filename test-result.png
|
|
390
|
+
|
|
391
|
+
# Check for errors
|
|
392
|
+
chrome-cdp-cli list_console_messages --type error
|
|
393
|
+
\`\`\`
|
|
394
|
+
|
|
395
|
+
### Automated Testing
|
|
396
|
+
\`\`\`bash
|
|
397
|
+
#!/bin/bash
|
|
398
|
+
# test-script.sh
|
|
399
|
+
|
|
400
|
+
# Start Chrome in background
|
|
401
|
+
chrome --headless --remote-debugging-port=9222 &
|
|
402
|
+
CHROME_PID=$!
|
|
403
|
+
|
|
404
|
+
# Wait for Chrome to start
|
|
405
|
+
sleep 2
|
|
406
|
+
|
|
407
|
+
# Run tests
|
|
408
|
+
chrome-cdp-cli eval "window.location.href = 'http://localhost:3000'"
|
|
409
|
+
chrome-cdp-cli eval "document.querySelector('#login-form input[name=username]').value = 'testuser'"
|
|
410
|
+
chrome-cdp-cli eval "document.querySelector('#login-form input[name=password]').value = 'testpass'"
|
|
411
|
+
chrome-cdp-cli eval "document.querySelector('#login-form').submit()"
|
|
412
|
+
|
|
413
|
+
# Capture results
|
|
414
|
+
chrome-cdp-cli screenshot --filename login-test.png
|
|
415
|
+
chrome-cdp-cli list_console_messages --type error > errors.log
|
|
416
|
+
|
|
417
|
+
# Cleanup
|
|
418
|
+
kill $CHROME_PID
|
|
419
|
+
\`\`\`
|
|
420
|
+
`;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
exports.InstallClaudeSkillHandler = InstallClaudeSkillHandler;
|