From 51eac46940835f3a06b0d99b6504ff3048c767ce Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 09:03:44 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 14 + README.md | 3 + agents/chrome-devtools.md | 255 ++++++ plugin.lock.json | 193 +++++ .../mcp-chrome-devtools/.skill-metadata.json | 12 + skills/mcp-chrome-devtools/SKILL.md | 159 ++++ .../reference/advanced-examples.md | 737 +++++++++++++++++ .../reference/all-tools.md | 772 ++++++++++++++++++ .../reference/troubleshooting.md | 743 +++++++++++++++++ skills/mcp-chrome-devtools/scripts/click.js | 45 + .../mcp-chrome-devtools/scripts/close_page.js | 42 + skills/mcp-chrome-devtools/scripts/drag.js | 49 ++ skills/mcp-chrome-devtools/scripts/emulate.js | 39 + .../scripts/evaluate_script.js | 55 ++ skills/mcp-chrome-devtools/scripts/fill.js | 49 ++ .../mcp-chrome-devtools/scripts/fill_form.js | 41 + .../scripts/get_console_message.js | 42 + .../scripts/get_network_request.js | 35 + .../scripts/handle_dialog.js | 45 + skills/mcp-chrome-devtools/scripts/hover.js | 41 + .../scripts/list_console_messages.js | 47 ++ .../scripts/list_network_requests.js | 47 ++ .../mcp-chrome-devtools/scripts/list_pages.js | 31 + .../mcp-chrome-devtools/scripts/mcp_client.js | 79 ++ .../scripts/navigate_page.js | 47 ++ .../mcp-chrome-devtools/scripts/new_page.js | 45 + .../mcp-chrome-devtools/scripts/package.json | 18 + .../scripts/performance_analyze_insight.js | 49 ++ .../scripts/performance_start_trace.js | 49 ++ .../scripts/performance_stop_trace.js | 31 + .../mcp-chrome-devtools/scripts/press_key.js | 41 + .../scripts/resize_page.js | 51 ++ .../scripts/select_page.js | 42 + .../scripts/take_screenshot.js | 51 ++ .../scripts/take_snapshot.js | 41 + .../scripts/upload_file.js | 49 ++ .../mcp-chrome-devtools/scripts/wait_for.js | 45 + .../workflows/element-interaction.md | 310 +++++++ .../workflows/inspection-debugging.md | 326 ++++++++ .../workflows/page-management.md | 218 +++++ .../workflows/performance-analysis.md | 383 +++++++++ 41 files changed, 5371 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 agents/chrome-devtools.md create mode 100644 plugin.lock.json create mode 100644 skills/mcp-chrome-devtools/.skill-metadata.json create mode 100644 skills/mcp-chrome-devtools/SKILL.md create mode 100644 skills/mcp-chrome-devtools/reference/advanced-examples.md create mode 100644 skills/mcp-chrome-devtools/reference/all-tools.md create mode 100644 skills/mcp-chrome-devtools/reference/troubleshooting.md create mode 100755 skills/mcp-chrome-devtools/scripts/click.js create mode 100755 skills/mcp-chrome-devtools/scripts/close_page.js create mode 100755 skills/mcp-chrome-devtools/scripts/drag.js create mode 100755 skills/mcp-chrome-devtools/scripts/emulate.js create mode 100755 skills/mcp-chrome-devtools/scripts/evaluate_script.js create mode 100755 skills/mcp-chrome-devtools/scripts/fill.js create mode 100755 skills/mcp-chrome-devtools/scripts/fill_form.js create mode 100755 skills/mcp-chrome-devtools/scripts/get_console_message.js create mode 100755 skills/mcp-chrome-devtools/scripts/get_network_request.js create mode 100755 skills/mcp-chrome-devtools/scripts/handle_dialog.js create mode 100755 skills/mcp-chrome-devtools/scripts/hover.js create mode 100755 skills/mcp-chrome-devtools/scripts/list_console_messages.js create mode 100755 skills/mcp-chrome-devtools/scripts/list_network_requests.js create mode 100755 skills/mcp-chrome-devtools/scripts/list_pages.js create mode 100644 skills/mcp-chrome-devtools/scripts/mcp_client.js create mode 100755 skills/mcp-chrome-devtools/scripts/navigate_page.js create mode 100755 skills/mcp-chrome-devtools/scripts/new_page.js create mode 100644 skills/mcp-chrome-devtools/scripts/package.json create mode 100755 skills/mcp-chrome-devtools/scripts/performance_analyze_insight.js create mode 100755 skills/mcp-chrome-devtools/scripts/performance_start_trace.js create mode 100755 skills/mcp-chrome-devtools/scripts/performance_stop_trace.js create mode 100755 skills/mcp-chrome-devtools/scripts/press_key.js create mode 100755 skills/mcp-chrome-devtools/scripts/resize_page.js create mode 100755 skills/mcp-chrome-devtools/scripts/select_page.js create mode 100755 skills/mcp-chrome-devtools/scripts/take_screenshot.js create mode 100755 skills/mcp-chrome-devtools/scripts/take_snapshot.js create mode 100755 skills/mcp-chrome-devtools/scripts/upload_file.js create mode 100755 skills/mcp-chrome-devtools/scripts/wait_for.js create mode 100644 skills/mcp-chrome-devtools/workflows/element-interaction.md create mode 100644 skills/mcp-chrome-devtools/workflows/inspection-debugging.md create mode 100644 skills/mcp-chrome-devtools/workflows/page-management.md create mode 100644 skills/mcp-chrome-devtools/workflows/performance-analysis.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..9baf912 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,14 @@ +{ + "name": "chrome-devtools-plugin", + "description": "Browser automation and DevTools control. Navigate pages, interact with elements, inspect network/console, analyze performance, and capture screenshots for web testing and automation tasks.", + "version": "0.5.1", + "author": { + "name": "ulasbilgen" + }, + "skills": [ + "./skills" + ], + "agents": [ + "./agents" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b0876fa --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# chrome-devtools-plugin + +Browser automation and DevTools control. Navigate pages, interact with elements, inspect network/console, analyze performance, and capture screenshots for web testing and automation tasks. diff --git a/agents/chrome-devtools.md b/agents/chrome-devtools.md new file mode 100644 index 0000000..864f27f --- /dev/null +++ b/agents/chrome-devtools.md @@ -0,0 +1,255 @@ +--- +name: chrome-devtools +description: Browser automation specialist using Chrome DevTools Protocol. Use when users need to automate Chrome browser tasks, test web applications, fill forms, debug frontend issues, analyze web performance, or capture screenshots. Expert at using mcp-chrome-devtools tools for comprehensive browser automation. +skills: mcp-chrome-devtools +model: sonnet +tools: Bash, Read, Write, Edit, Grep, Glob +--- + +# Chrome DevTools Agent + +You are a specialist in browser automation using the Chrome DevTools Protocol through the mcp-chrome-devtools skill. You help users automate web browser tasks, test web applications, extract data, debug frontend issues, and analyze performance. + +## When to Use This Agent + +Use this agent when users need to: +- **Automate browser interactions:** Fill forms, click buttons, navigate pages +- **Test web applications:** End-to-end testing, regression testing, form validation +- **Web scraping:** Extract data from websites, monitor content changes +- **Debug frontend issues:** Inspect console errors, analyze network requests +- **Performance analysis:** Measure Core Web Vitals (LCP, FID, CLS), analyze page speed +- **Visual regression testing:** Capture screenshots for comparison +- **Multi-tab workflows:** Manage multiple browser pages simultaneously + +## Available Capabilities + +This skill provides 26 tools organized into 4 groups: + +### 1. Page Management (6 tools) +Browser window and tab operations for creating pages, navigation, and switching contexts. +- **new_page:** Open new browser pages +- **list_pages:** List all open tabs +- **close_page:** Close specific tabs +- **navigate_page:** Navigate, reload, go back/forward +- **select_page:** Switch between tabs +- **resize_page:** Set viewport dimensions + +### 2. Element Interaction (7 tools) +User input simulation for clicking, typing, form filling, and drag & drop. +- **click:** Click on elements (single or double-click) +- **fill:** Type text into inputs or select dropdown options +- **fill_form:** Fill multiple form fields at once +- **hover:** Hover over elements +- **drag:** Drag and drop elements +- **upload_file:** Upload files through file inputs +- **press_key:** Press keys or keyboard shortcuts + +### 3. Inspection & Debugging (6 tools) +Monitoring and debugging with snapshots, screenshots, console logs, and network requests. +- **take_snapshot:** Get page structure with element UIDs (prefer this over screenshots) +- **take_screenshot:** Capture visual screenshots +- **list_console_messages:** List console logs/warnings/errors +- **get_console_message:** Get specific console message details +- **list_network_requests:** List all network requests +- **get_network_request:** Get specific request details + +### 4. Performance Analysis (7 tools) +Advanced tools for JavaScript execution, performance tracing, and device emulation. +- **evaluate_script:** Execute JavaScript in page context +- **wait_for:** Wait for specific text to appear +- **handle_dialog:** Handle browser alerts/confirms/prompts +- **emulate:** Simulate network conditions and CPU throttling +- **performance_start_trace:** Start performance recording +- **performance_stop_trace:** Stop recording and get metrics +- **performance_analyze_insight:** Analyze specific performance insights + +## How to Use This Skill + +### Prerequisites Check +Always verify at the start of any workflow: +1. **MCP server is running:** The chrome-devtools MCP server must be active +2. **Chrome browser is available:** Chrome/Chromium installed on system +3. **Script dependencies:** Node.js 18+ with npm packages installed + +You can check server status by attempting to use a tool - errors will indicate if the server is not available. + +### Standard Workflow + +**Basic browser automation pattern:** + +1. **Open a page:** + ```bash + node skills/mcp-chrome-devtools/scripts/new_page.js --url https://example.com + ``` + +2. **Take a snapshot to identify elements:** + ```bash + node skills/mcp-chrome-devtools/scripts/take_snapshot.js + ``` + - Snapshot shows page structure with element UIDs + - **Always use UIDs from the most recent snapshot** (they regenerate each time) + +3. **Interact with elements using UIDs:** + ```bash + node skills/mcp-chrome-devtools/scripts/click.js --uid button_submit_abc123 + node skills/mcp-chrome-devtools/scripts/fill.js --uid input_email_xyz --value user@example.com + ``` + +4. **Wait for dynamic content:** + ```bash + node skills/mcp-chrome-devtools/scripts/wait_for.js --text "Success" --timeout 10000 + ``` + +5. **Verify results:** + ```bash + node skills/mcp-chrome-devtools/scripts/take_screenshot.js --filePath result.png + ``` + +### Critical Best Practices + +1. **Always snapshot before interaction:** + - Element UIDs are dynamic and regenerate on each snapshot + - Never reuse UIDs from old snapshots + - Pattern: snapshot → interact → snapshot again + +2. **Use wait_for for dynamic content:** + - Don't assume instant page loads + - Wait for specific text to appear before interacting + - Use appropriate timeouts (default: 30 seconds) + +3. **Handle state persistence:** + - Browser instance stays open between commands + - Page context persists until explicitly changed + - Console/network data accumulates since last navigation + +4. **Check for errors:** + - Use `list_console_messages.js --types error` to debug issues + - Monitor network requests with `list_network_requests.js` + - Take screenshots to verify visual state + +5. **Multi-page workflows:** + - Use `list_pages.js` to see all tabs + - Use `select_page.js` to switch context before interacting + - Close unused pages to avoid index confusion + +## Common Workflows + +### Automated Form Submission +1. Open page with form +2. Take snapshot to get element UIDs +3. Fill form fields using `fill.js` or `fill_form.js` +4. Submit form with `click.js` +5. Wait for success message with `wait_for.js` +6. Verify with screenshot + +### Web Scraping +1. Navigate to target page +2. Wait for content to load +3. Take snapshot or use `evaluate_script.js` to extract data +4. List network requests to capture API responses +5. Extract structured data using JavaScript evaluation + +### Performance Testing +1. Open target page +2. Start performance trace with `performance_start_trace.js` +3. Wait for page to fully load +4. Stop trace with `performance_stop_trace.js` +5. Review Core Web Vitals (LCP, FID, CLS) +6. Analyze specific insights with `performance_analyze_insight.js` + +### E2E Testing +1. Open application +2. Execute test steps (fill forms, click buttons, navigate) +3. Verify expected outcomes at each step +4. Check console for errors +5. Capture screenshots for evidence +6. Monitor network requests for API calls + +## Script Execution + +All tools are available as JavaScript scripts in the skill directory: + +```bash +# General pattern +node skills/mcp-chrome-devtools/scripts/{tool-name}.js [arguments] + +# Get help for any tool +node skills/mcp-chrome-devtools/scripts/{tool-name}.js --help + +# Examples +node skills/mcp-chrome-devtools/scripts/new_page.js --url https://example.com +node skills/mcp-chrome-devtools/scripts/take_snapshot.js --verbose true +node skills/mcp-chrome-devtools/scripts/click.js --uid button_xyz +``` + +**Always use the Bash tool to execute these scripts.** + +## Troubleshooting + +### Common Issues + +**"Element UID not found"** +- UIDs regenerate on each snapshot +- Take a fresh snapshot before every interaction +- Never reuse old UIDs + +**"Click doesn't trigger action"** +- Wait for page to fully load first +- Try hovering before clicking +- Check if element is visible (not hidden) + +**"Screenshot is blank"** +- Wait for page to render with `wait_for.js` +- Try `--fullPage true` for full page capture +- Verify page loaded correctly with snapshot + +**"Navigation timeout"** +- Increase timeout value: `--timeout 60000` +- Check network connectivity +- Verify URL is correct + +**"Console messages not showing"** +- Messages accumulate since last navigation +- Reload page if needed to clear +- Use `--includePreservedMessages true` for older messages + +### Debug Checklist + +When encountering issues: +1. Check console errors: `list_console_messages.js --types error` +2. Check network requests: `list_network_requests.js` +3. Take snapshot to verify page state +4. Take screenshot for visual debugging +5. Verify correct page is selected: `list_pages.js` + +## Important Notes + +- The skill documentation is auto-loaded into your context +- Refer to SKILL.md for quick reference and workflows +- Check `workflows/` directory for detailed examples by category: + - `page-management.md` - Browser window/tab operations + - `element-interaction.md` - User input simulation + - `inspection-debugging.md` - Monitoring and debugging + - `performance-analysis.md` - Advanced tools and performance +- Review `reference/troubleshooting.md` for comprehensive problem-solving +- See `reference/all-tools.md` for complete alphabetical tool listing +- Check `reference/advanced-examples.md` for production-ready patterns + +## File Paths + +**Important:** Always use forward slashes in file paths (not backslashes): +- ✓ Good: `/Users/username/screenshots/page.png` +- ✗ Bad: `C:\Users\username\screenshots\page.png` + +Use absolute paths for file operations (screenshots, uploads, snapshots with --filePath). + +## Response Format + +When executing browser automation tasks: +1. Explain what you're going to do +2. Execute the necessary scripts using Bash tool +3. Interpret the output for the user +4. Provide next steps or verification +5. Capture evidence (screenshots/snapshots) when appropriate + +Always be clear about what succeeded and what failed, and provide actionable next steps. diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..351b7b9 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,193 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:ulasbilgen/mcp-skills-plugins:chrome-devtools-plugin", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "502dab22ad042ea991085a3673b9ecbdd35d305b", + "treeHash": "7979765503369809085dfea1d2db08959c3acb0b341b77f02560638906fdaf97", + "generatedAt": "2025-11-28T10:28:50.339255Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "chrome-devtools-plugin", + "description": "Browser automation and DevTools control. Navigate pages, interact with elements, inspect network/console, analyze performance, and capture screenshots for web testing and automation tasks.", + "version": "0.5.1" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "953b515d30a77b60ea84b0581537f0c0e7f205e2d7a8e3ca49533fae05e8c177" + }, + { + "path": "agents/chrome-devtools.md", + "sha256": "48941c9efa75aef265c914917890620dce129e84e1e12955cdf072b6b6a1d220" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "483a62cd72f24854119e4b71df400079a69728c8c04653b3a7b643d8d10812d0" + }, + { + "path": "skills/mcp-chrome-devtools/.skill-metadata.json", + "sha256": "d77cdd7bdf1b23ab3d389dc1d1af08f4b72a519133758cd805e589cfa94f253d" + }, + { + "path": "skills/mcp-chrome-devtools/SKILL.md", + "sha256": "a40d88bbfba3a954d48c6dd60913afac1379991d22742bf3e53f64476802e5c9" + }, + { + "path": "skills/mcp-chrome-devtools/workflows/element-interaction.md", + "sha256": "848eeb1c4e907373e42627b448e553af9820a92b4a4f0f0c477c4eafeca92810" + }, + { + "path": "skills/mcp-chrome-devtools/workflows/performance-analysis.md", + "sha256": "e05942b2d3c2c625d815ec32784fd47236342624ce3101e4c0205c3bfd4aaa84" + }, + { + "path": "skills/mcp-chrome-devtools/workflows/page-management.md", + "sha256": "0e78fd8ab50cca49c718d143234723b5248e31d58820b1476882467ca6f5978f" + }, + { + "path": "skills/mcp-chrome-devtools/workflows/inspection-debugging.md", + "sha256": "b4289356869ea5581d46f03cf6df4ddde32f7a37b15fe59e269005df23fd2ba2" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/list_pages.js", + "sha256": "d48f31f904e5d7172d093127f64a0c1612d03be9bcf9c6176fb3d1df6d888b1c" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/take_snapshot.js", + "sha256": "4c9f359513a0f1b44bbec0b29e5ddea348ffce222e60b80bcdab0886c16f1c28" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/list_console_messages.js", + "sha256": "ac31009d2e4f556a879615a85e075ce934c847c12d1abfbb47489ddcf794259d" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/drag.js", + "sha256": "a325e5c37046297aca92ca33da1cbb1db328e839bfb36a766f22a079ec6243f6" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/resize_page.js", + "sha256": "4f93c00d6b9645f65cf90baeeda9e13b6d7ca73755cd9980d0043adcc13833c9" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/performance_stop_trace.js", + "sha256": "8bf6b20ad49fe634dbf83eb4eca541bb652de308b2387be7e1573cc703cde2c2" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/get_network_request.js", + "sha256": "ab52969d002cd9ba20d46b3b7610d19db089f5edfd859134c692d1e061359cd6" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/new_page.js", + "sha256": "cfbc0c0d03cf13473e33407646f23b5c15e9bd4dd1c4f6c2dc4f585f5f6f1692" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/click.js", + "sha256": "0f77da76fb0473f5ff33310b4f0b229882575cae0867c2ec26c334379ae36358" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/evaluate_script.js", + "sha256": "3c90cf32aaea03b9edad9f43e6fa6e095f43ea23d6e2bcde190d3d7afdbde8ec" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/take_screenshot.js", + "sha256": "e151bafd86cb2347071794ac4315cbe2355c4640a5c5986abbc7105436bfcea9" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/fill.js", + "sha256": "a2bc29b1cfc5a9e110b4c9e0cf7b05749f437dae0a1f8e4e2c0ce498dd0100b4" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/select_page.js", + "sha256": "b658b2ca3f364b460cba6e75355ac506ecd91e813d9c1d65c6326ac9e8a2fee1" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/list_network_requests.js", + "sha256": "c7dfde8256df7f611df414776dc3141152b3d7e7e61e4fb46f980103631b2dae" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/wait_for.js", + "sha256": "e0a7baaa9e60382f78820ea3629b92d9bb6a3dab326ce951c94121f5f2fcdde0" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/hover.js", + "sha256": "69cae5cd5b66cec14727f5f1e5150fd8f77fd32dc62d8acdd6752e83c56cbb60" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/press_key.js", + "sha256": "cf81e73b11721e1e3bb1b06e1b9620c51de4af6a3e1b82d14c5691434042796e" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/get_console_message.js", + "sha256": "749a4b9bfa2c12d513376d111793e28eb2a1b62be663eb4359f27bbe7f3f4eec" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/navigate_page.js", + "sha256": "8f44d0f49b19275fbe54448cc3d5182ecc819561151fb3ae3b48630cd1fe8dc2" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/package.json", + "sha256": "7c23741d908a6a5c3f8363b3f68697104c9fa5c00e15fbd16868531bf6634075" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/handle_dialog.js", + "sha256": "f200f3c85b86f52e5d4f0e098defafdeb42dd424cd6b497272952e8ed85e79a4" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/mcp_client.js", + "sha256": "03b1ed6dd038d59e8a4b114b7ab0898f837e123e736d33923134000917ac1aa5" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/close_page.js", + "sha256": "174e2bf275c22b1904371ed853c2d3d59a9152ea7e32645b1a6f0f211bbcbd5e" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/performance_start_trace.js", + "sha256": "c7f7e48de686756688fb275c6a5a86f23b250f2f03b968fe421ab221c8fe7906" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/emulate.js", + "sha256": "9f3c1517fe8cc9fd523cba49be7b06d9e0dfce42de9fbf2b8a44c1792bf93f27" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/fill_form.js", + "sha256": "a68614e5d192721752fac5ceffe33050e84de74596e5c254b87cd82e263a48d7" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/upload_file.js", + "sha256": "e7e4e3934f4bbb3a0826a908b903e2cccc57fbc3a4fc3cbeb2057b1714d0d96e" + }, + { + "path": "skills/mcp-chrome-devtools/scripts/performance_analyze_insight.js", + "sha256": "f3c60a7d745b7030b4fa35e6f21b0f90f52c6d74f564ecbdab566cd3255e967c" + }, + { + "path": "skills/mcp-chrome-devtools/reference/troubleshooting.md", + "sha256": "8074a7eeab7b5250d0ce9e7b76b9f7b33a309bac6db10fd19481999ca4336b09" + }, + { + "path": "skills/mcp-chrome-devtools/reference/all-tools.md", + "sha256": "4b4ea8090520382865e4c2846441f0a70bd0ff56dfa4b0f225496d71e64c7cbc" + }, + { + "path": "skills/mcp-chrome-devtools/reference/advanced-examples.md", + "sha256": "b9e7ac7060ca8a8e57b1a2624623c16580cca0ae287074219f1c8e8d249ae84e" + } + ], + "dirSha256": "7979765503369809085dfea1d2db08959c3acb0b341b77f02560638906fdaf97" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/mcp-chrome-devtools/.skill-metadata.json b/skills/mcp-chrome-devtools/.skill-metadata.json new file mode 100644 index 0000000..84d33c9 --- /dev/null +++ b/skills/mcp-chrome-devtools/.skill-metadata.json @@ -0,0 +1,12 @@ +{ + "serverName": "chrome-devtools", + "serverVersion": "0.10.2", + "serverVersionInfo": { + "name": "chrome_devtools", + "title": "Chrome DevTools MCP server", + "version": "0.10.2" + }, + "generatedAt": "2025-11-23T22:51:09.827Z", + "mcp2scriptsVersion": "0.3.1", + "mcp2restUrl": "http://localhost:28888" +} \ No newline at end of file diff --git a/skills/mcp-chrome-devtools/SKILL.md b/skills/mcp-chrome-devtools/SKILL.md new file mode 100644 index 0000000..a1856ce --- /dev/null +++ b/skills/mcp-chrome-devtools/SKILL.md @@ -0,0 +1,159 @@ +--- +name: mcp-chrome-devtools +description: Automate Chrome browser via DevTools Protocol. Navigate pages, interact with elements, inspect network/console, analyze performance, and capture screenshots for web testing and automation tasks. +server-version: 0.10.2 +--- + +# Chrome DevTools Skill + +Control Chrome browser programmatically using the Chrome DevTools Protocol. This skill provides 26 tools for browser automation, web scraping, testing, and performance analysis. + +## Prerequisites + +- Node.js 18+ installed +- mcp2rest running on http://localhost:28888 +- chrome-devtools server loaded in mcp2rest +- Package: `chrome-devtools-mcp@latest` +- Dependencies installed (already done during generation) + +## Quick Start + +Launch a browser, navigate to a page, and interact with elements: + +```bash +# 1. Open a new page +node scripts/new_page.js --url https://example.com + +# 2. Take a text snapshot to identify elements +node scripts/take_snapshot.js + +# 3. Click a button (use UID from snapshot output) +node scripts/click.js --uid button_submit_abc123 +``` + +**Expected Output:** +- Page opens in Chrome browser +- Snapshot shows page structure with element UIDs +- Button is clicked and any action triggers + +## Tool Groups + +This skill provides 26 tools organized into 4 groups: + +### 1. Page Management +Browser window and tab operations: creating pages, navigation, switching contexts. + +**Tools:** new_page, list_pages, close_page, navigate_page, select_page, resize_page + +See: @workflows/page-management.md for detailed workflows + +### 2. Element Interaction +User input simulation: clicking, typing, form filling, drag & drop. + +**Tools:** click, fill, fill_form, hover, drag, upload_file, press_key + +See: @workflows/element-interaction.md for detailed workflows + +### 3. Inspection & Debugging +Monitoring and debugging: snapshots, screenshots, console logs, network requests. + +**Tools:** take_snapshot, take_screenshot, list_console_messages, get_console_message, list_network_requests, get_network_request + +See: @workflows/inspection-debugging.md for detailed workflows + +### 4. Performance Analysis +Scripting and performance tools: JavaScript execution, performance tracing, device emulation. + +**Tools:** evaluate_script, wait_for, handle_dialog, emulate, performance_start_trace, performance_stop_trace, performance_analyze_insight + +See: @workflows/performance-analysis.md for detailed workflows + +## Common Workflows + +### Workflow: Automated Form Submission + +Complete end-to-end form filling and submission: + +- [ ] **Open page:** `node scripts/new_page.js --url https://example.com/login` +- [ ] **Get structure:** `node scripts/take_snapshot.js` (identify UIDs) +- [ ] **Fill email:** `node scripts/fill.js --uid email_input_xyz --value test@example.com` +- [ ] **Fill password:** `node scripts/fill.js --uid pass_input_abc --value mypassword` +- [ ] **Submit form:** `node scripts/click.js --uid submit_btn_def` +- [ ] **Verify:** `node scripts/wait_for.js --text "Welcome" --timeout 5000` +- [ ] **Capture result:** `node scripts/take_screenshot.js --format png --filePath result.png` + +**Input Example:** +``` +Email field UID: input_email_1a2b3c +Password field UID: input_password_4d5e6f +Submit button UID: button_submit_7g8h9i +``` + +**Expected Output:** +Form submitted successfully, redirected to dashboard, screenshot saved. + +### Workflow: Web Scraping with Network Monitoring + +Capture page data and network activity: + +- [ ] **Start monitoring:** `node scripts/new_page.js --url https://example.com/data` +- [ ] **Wait for load:** `node scripts/wait_for.js --text "Data loaded" --timeout 10000` +- [ ] **Get page snapshot:** `node scripts/take_snapshot.js --verbose true --filePath snapshot.txt` +- [ ] **List network calls:** `node scripts/list_network_requests.js --resourceTypes fetch,xhr` +- [ ] **Get specific request:** `node scripts/get_network_request.js --reqid request_123` +- [ ] **Extract via script:** `node scripts/evaluate_script.js --function "() => document.querySelector('.data').textContent"` + +**Expected Output:** +Page data extracted, network requests logged, specific API responses captured. + +### Workflow: Performance Testing + +Analyze page performance and Core Web Vitals: + +- [ ] **Open page:** `node scripts/new_page.js --url https://example.com` +- [ ] **Start tracing:** `node scripts/performance_start_trace.js --reload true --autoStop false` +- [ ] **Wait for page:** `node scripts/wait_for.js --text "Content loaded" --timeout 15000` +- [ ] **Stop tracing:** `node scripts/performance_stop_trace.js` +- [ ] **Review insights:** Check trace output for performance metrics and CWV scores +- [ ] **Analyze specific insight:** `node scripts/performance_analyze_insight.js --insightSetId set_123 --insightName LargestContentfulPaint` + +**Expected Output:** +Performance trace with metrics, CWV scores (LCP, FID, CLS), actionable insights. + +### Workflow: Multi-Page Session Management + +Work with multiple browser tabs: + +- [ ] **List current pages:** `node scripts/list_pages.js` +- [ ] **Open new tab:** `node scripts/new_page.js --url https://example.com/page1` +- [ ] **Open another tab:** `node scripts/new_page.js --url https://example.com/page2` +- [ ] **List all pages:** `node scripts/list_pages.js` (note page indices) +- [ ] **Switch to page 0:** `node scripts/select_page.js --pageIdx 0` +- [ ] **Interact with page 0:** `node scripts/take_snapshot.js` +- [ ] **Switch to page 1:** `node scripts/select_page.js --pageIdx 1` +- [ ] **Close page 1:** `node scripts/close_page.js --pageIdx 1` + +**Expected Output:** +Multiple tabs managed, context switching works, specific pages closed. + +## State Persistence + +This server maintains state between script calls: +- Browser instance stays open across multiple commands +- Page context persists until explicitly changed with `select_page.js` +- Console messages and network requests accumulate since last navigation +- State resets when mcp2rest server restarts + +## Reference + +- **Complete tool listing:** @reference/all-tools.md +- **Troubleshooting guide:** @reference/troubleshooting.md +- **Advanced examples:** @reference/advanced-examples.md + +## Quick Tips + +1. **Always take snapshots first:** Use `take_snapshot.js` to get element UIDs before interaction +2. **Use wait_for for dynamic content:** Don't assume instant loading +3. **Handle dialogs proactively:** Use `handle_dialog.js` if alerts/confirms appear +4. **Check console for errors:** Use `list_console_messages.js` to debug issues +5. **Monitor network for API calls:** Use `list_network_requests.js` to track backend communication diff --git a/skills/mcp-chrome-devtools/reference/advanced-examples.md b/skills/mcp-chrome-devtools/reference/advanced-examples.md new file mode 100644 index 0000000..3a6b42c --- /dev/null +++ b/skills/mcp-chrome-devtools/reference/advanced-examples.md @@ -0,0 +1,737 @@ +# Advanced Examples + +Complex workflows and advanced usage patterns for chrome-devtools. + +## Table of Contents + +- [E2E Testing Workflows](#e2e-testing-workflows) +- [Web Scraping Patterns](#web-scraping-patterns) +- [Performance Optimization](#performance-optimization) +- [CI/CD Integration](#cicd-integration) +- [Cross-Browser Testing Simulation](#cross-browser-testing-simulation) +- [Advanced JavaScript Extraction](#advanced-javascript-extraction) + +--- + +## E2E Testing Workflows + +### Complete User Registration Flow + +Test full registration process with validation: + +```bash +#!/bin/bash +# test_registration.sh + +echo "Starting registration flow test..." + +# 1. Open registration page +node scripts/new_page.js --url https://example.com/register + +# 2. Wait for page load +node scripts/wait_for.js --text "Create Account" --timeout 10000 + +# 3. Get form structure +node scripts/take_snapshot.js --filePath registration_form.txt + +# 4. Fill registration form (update UIDs from snapshot) +node scripts/fill_form.js --elements '[ + {"uid":"input_firstname","value":"John"}, + {"uid":"input_lastname","value":"Doe"}, + {"uid":"input_email","value":"john.doe@example.com"}, + {"uid":"input_password","value":"SecurePass123!"}, + {"uid":"input_password_confirm","value":"SecurePass123!"}, + {"uid":"select_country","value":"United States"} +]' + +# 5. Screenshot before submission +node scripts/take_screenshot.js --filePath before_submit.png + +# 6. Accept terms checkbox +node scripts/click.js --uid checkbox_terms + +# 7. Submit form +node scripts/click.js --uid button_register + +# 8. Wait for success message +if node scripts/wait_for.js --text "Registration successful" --timeout 15000; then + echo "✓ Registration succeeded" + + # 9. Capture success state + node scripts/take_screenshot.js --filePath registration_success.png + node scripts/take_snapshot.js --filePath success_page.txt + + # 10. Check for welcome email notification + node scripts/wait_for.js --text "Verification email sent" --timeout 5000 + + echo "✓ Test passed: Registration flow complete" + exit 0 +else + echo "✗ Registration failed" + + # Capture error state + node scripts/take_screenshot.js --filePath registration_error.png + node scripts/list_console_messages.js --types error > console_errors.txt + + echo "✗ Test failed: See error screenshots and logs" + exit 1 +fi +``` + +### Shopping Cart Checkout Flow + +Test complete e-commerce checkout: + +```bash +#!/bin/bash +# test_checkout.sh + +echo "Testing checkout flow..." + +# 1. Navigate to product page +node scripts/new_page.js --url https://example.com/products/widget-123 + +# 2. Wait and verify product loads +node scripts/wait_for.js --text "Add to Cart" --timeout 10000 +node scripts/take_snapshot.js > product_page.txt + +# 3. Add to cart +node scripts/click.js --uid button_add_to_cart +node scripts/wait_for.js --text "Added to cart" --timeout 5000 + +# 4. Go to cart +node scripts/click.js --uid link_view_cart +node scripts/wait_for.js --text "Shopping Cart" --timeout 5000 + +# 5. Verify cart contents +node scripts/take_snapshot.js --filePath cart_contents.txt +node scripts/evaluate_script.js --function "() => document.querySelector('.cart-total').textContent" > cart_total.txt + +# 6. Proceed to checkout +node scripts/click.js --uid button_checkout +node scripts/wait_for.js --text "Shipping Information" --timeout 10000 + +# 7. Fill shipping info +node scripts/fill_form.js --elements '[ + {"uid":"input_address","value":"123 Main Street"}, + {"uid":"input_city","value":"San Francisco"}, + {"uid":"input_state","value":"CA"}, + {"uid":"input_zip","value":"94102"} +]' + +# 8. Continue to payment +node scripts/click.js --uid button_continue +node scripts/wait_for.js --text "Payment Method" --timeout 10000 + +# 9. Select payment method +node scripts/click.js --uid radio_credit_card + +# 10. Fill payment info (test mode) +node scripts/fill_form.js --elements '[ + {"uid":"input_card_number","value":"4242424242424242"}, + {"uid":"input_card_expiry","value":"12/25"}, + {"uid":"input_card_cvc","value":"123"} +]' + +# 11. Place order +node scripts/click.js --uid button_place_order +node scripts/wait_for.js --text "Order Confirmed" --timeout 20000 + +# 12. Capture confirmation +node scripts/take_screenshot.js --filePath order_confirmation.png +node scripts/evaluate_script.js --function "() => ({orderNumber: document.querySelector('.order-number').textContent, total: document.querySelector('.order-total').textContent})" > order_details.json + +echo "✓ Checkout flow completed successfully" +``` + +--- + +## Web Scraping Patterns + +### Multi-Page Data Extraction + +Scrape data across paginated results: + +```bash +#!/bin/bash +# scrape_listings.sh + +BASE_URL="https://example.com/listings" +OUTPUT_FILE="all_listings.json" +MAX_PAGES=10 + +echo "[" > $OUTPUT_FILE + +for page in $(seq 1 $MAX_PAGES); do + echo "Scraping page $page..." + + # Navigate to page + if [ $page -eq 1 ]; then + node scripts/new_page.js --url "$BASE_URL" + else + node scripts/navigate_page.js --url "$BASE_URL?page=$page" + fi + + # Wait for listings to load + node scripts/wait_for.js --text "listings found" --timeout 10000 + + # Extract listings data + LISTINGS=$(node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.listing')).map(item => ({ + title: item.querySelector('.title').textContent.trim(), + price: item.querySelector('.price').textContent.trim(), + location: item.querySelector('.location').textContent.trim(), + url: item.querySelector('a').href + }))") + + # Append to output (remove outer brackets) + echo "$LISTINGS" | jq '.[]' >> $OUTPUT_FILE + + # Check if there's a next page + HAS_NEXT=$(node scripts/evaluate_script.js --function "() => document.querySelector('.pagination .next') !== null") + + if [ "$HAS_NEXT" != "true" ]; then + echo "Reached last page at page $page" + break + fi + + # Add comma separator + if [ $page -lt $MAX_PAGES ]; then + echo "," >> $OUTPUT_FILE + fi + + # Be polite: wait between requests + sleep 2 +done + +echo "]" >> $OUTPUT_FILE + +echo "✓ Scraped listings saved to $OUTPUT_FILE" + +# Summary statistics +TOTAL=$(cat $OUTPUT_FILE | jq 'length') +echo "Total listings extracted: $TOTAL" +``` + +### Dynamic Content Scraping with Infinite Scroll + +Extract data from infinite scroll pages: + +```bash +#!/bin/bash +# scrape_infinite_scroll.sh + +echo "Scraping infinite scroll content..." + +# Open page +node scripts/new_page.js --url https://example.com/feed + +# Wait for initial content +node scripts/wait_for.js --text "Post" --timeout 10000 + +# Initialize +PREVIOUS_COUNT=0 +SCROLL_ATTEMPTS=0 +MAX_SCROLLS=20 +OUTPUT_FILE="feed_items.json" + +while [ $SCROLL_ATTEMPTS -lt $MAX_SCROLLS ]; do + # Count current items + CURRENT_COUNT=$(node scripts/evaluate_script.js --function "() => document.querySelectorAll('.feed-item').length") + + echo "Scroll $SCROLL_ATTEMPTS: Found $CURRENT_COUNT items" + + # Check if we got new items + if [ "$CURRENT_COUNT" -eq "$PREVIOUS_COUNT" ]; then + echo "No new items loaded, reached end" + break + fi + + PREVIOUS_COUNT=$CURRENT_COUNT + + # Scroll to bottom + node scripts/evaluate_script.js --function "() => window.scrollTo(0, document.body.scrollHeight)" + + # Wait for new content to load + sleep 2 + + SCROLL_ATTEMPTS=$((SCROLL_ATTEMPTS + 1)) +done + +# Extract all items +echo "Extracting all $CURRENT_COUNT items..." + +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.feed-item')).map(item => ({ + author: item.querySelector('.author').textContent.trim(), + content: item.querySelector('.content').textContent.trim(), + timestamp: item.querySelector('.timestamp').textContent.trim(), + likes: item.querySelector('.likes').textContent.trim() +}))" > $OUTPUT_FILE + +echo "✓ Extracted $CURRENT_COUNT items to $OUTPUT_FILE" +``` + +--- + +## Performance Optimization + +### Automated Performance Regression Testing + +Compare performance across builds: + +```bash +#!/bin/bash +# performance_regression_test.sh + +BASELINE_URL="https://staging.example.com" +CURRENT_URL="https://production.example.com" + +echo "Running performance regression tests..." + +# Test baseline (staging) +echo "Testing baseline: $BASELINE_URL" + +node scripts/new_page.js --url "$BASELINE_URL" +node scripts/performance_start_trace.js --reload true --autoStop false +node scripts/wait_for.js --text "Ready" --timeout 30000 +node scripts/performance_stop_trace.js > baseline_trace.json + +BASELINE_LCP=$(cat baseline_trace.json | jq -r '.metrics.LCP.value') +BASELINE_FID=$(cat baseline_trace.json | jq -r '.metrics.FID.value') +BASELINE_CLS=$(cat baseline_trace.json | jq -r '.metrics.CLS.value') + +echo "Baseline: LCP=$BASELINE_LCP, FID=$BASELINE_FID, CLS=$BASELINE_CLS" + +# Test current (production) +echo "Testing current: $CURRENT_URL" + +node scripts/navigate_page.js --url "$CURRENT_URL" +node scripts/performance_start_trace.js --reload true --autoStop false +node scripts/wait_for.js --text "Ready" --timeout 30000 +node scripts/performance_stop_trace.js > current_trace.json + +CURRENT_LCP=$(cat current_trace.json | jq -r '.metrics.LCP.value') +CURRENT_FID=$(cat current_trace.json | jq -r '.metrics.FID.value') +CURRENT_CLS=$(cat current_trace.json | jq -r '.metrics.CLS.value') + +echo "Current: LCP=$CURRENT_LCP, FID=$CURRENT_FID, CLS=$CURRENT_CLS" + +# Compare (allow 10% regression threshold) +THRESHOLD=1.1 +FAILED=false + +LCP_RATIO=$(echo "scale=2; $CURRENT_LCP / $BASELINE_LCP" | bc) +if (( $(echo "$LCP_RATIO > $THRESHOLD" | bc -l) )); then + echo "✗ LCP regression detected: ${CURRENT_LCP}ms vs ${BASELINE_LCP}ms" + FAILED=true +else + echo "✓ LCP within threshold" +fi + +FID_RATIO=$(echo "scale=2; $CURRENT_FID / $BASELINE_FID" | bc) +if (( $(echo "$FID_RATIO > $THRESHOLD" | bc -l) )); then + echo "✗ FID regression detected: ${CURRENT_FID}ms vs ${BASELINE_FID}ms" + FAILED=true +else + echo "✓ FID within threshold" +fi + +CLS_RATIO=$(echo "scale=2; $CURRENT_CLS / $BASELINE_CLS" | bc) +if (( $(echo "$CLS_RATIO > $THRESHOLD" | bc -l) )); then + echo "✗ CLS regression detected: ${CURRENT_CLS} vs ${BASELINE_CLS}" + FAILED=true +else + echo "✓ CLS within threshold" +fi + +if [ "$FAILED" = true ]; then + echo "Performance regression test FAILED" + exit 1 +else + echo "Performance regression test PASSED" + exit 0 +fi +``` + +### Network Performance Testing Matrix + +Test performance across network conditions: + +```bash +#!/bin/bash +# network_performance_matrix.sh + +URL="https://example.com" +OUTPUT_DIR="performance_results" + +mkdir -p $OUTPUT_DIR + +# Define network profiles +declare -A NETWORKS +NETWORKS["fast"]='{"downloadThroughput":10000000,"uploadThroughput":10000000,"latency":10}' +NETWORKS["4g"]='{"downloadThroughput":1600000,"uploadThroughput":750000,"latency":150}' +NETWORKS["3g"]='{"downloadThroughput":180000,"uploadThroughput":84000,"latency":562}' +NETWORKS["slow-3g"]='{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}' + +echo "Testing performance across network conditions..." + +# Open page once +node scripts/new_page.js --url "$URL" + +for profile in "${!NETWORKS[@]}"; do + echo "Testing network profile: $profile" + + # Apply network emulation + node scripts/emulate.js --networkConditions "${NETWORKS[$profile]}" + + # Run performance trace + node scripts/performance_start_trace.js --reload true --autoStop false + node scripts/wait_for.js --text "Ready" --timeout 60000 + node scripts/performance_stop_trace.js > "$OUTPUT_DIR/${profile}_trace.json" + + # Extract key metrics + LCP=$(cat "$OUTPUT_DIR/${profile}_trace.json" | jq -r '.metrics.LCP.value') + FID=$(cat "$OUTPUT_DIR/${profile}_trace.json" | jq -r '.metrics.FID.value') + CLS=$(cat "$OUTPUT_DIR/${profile}_trace.json" | jq -r '.metrics.CLS.value') + + echo "$profile: LCP=${LCP}ms, FID=${FID}ms, CLS=$CLS" + + # Capture screenshot + node scripts/take_screenshot.js --filePath "$OUTPUT_DIR/${profile}_loaded.png" +done + +# Reset to normal +node scripts/emulate.js --cpuThrottlingRate 1 + +echo "✓ Performance testing complete. Results in $OUTPUT_DIR/" +``` + +--- + +## CI/CD Integration + +### GitHub Actions Workflow + +```yaml +# .github/workflows/e2e-tests.yml +name: E2E Tests + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +jobs: + e2e-tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install mcp2skill-tools + run: | + npm install -g mcp2skill-tools + + - name: Start mcp2rest + run: | + mcp2rest start + mcp2rest add chrome-devtools + + - name: Install skill dependencies + run: | + cd ~/.claude/skills/mcp-chrome-devtools/scripts + npm install + + - name: Run E2E tests + run: | + cd tests + bash test_registration.sh + bash test_checkout.sh + bash test_search.sh + + - name: Upload test artifacts + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-results + path: | + **/*.png + **/*.txt + **/*.json + + - name: Stop mcp2rest + if: always() + run: mcp2rest stop +``` + +### Jenkins Pipeline + +```groovy +// Jenkinsfile +pipeline { + agent any + + environment { + NODE_VERSION = '18' + } + + stages { + stage('Setup') { + steps { + sh 'npm install -g mcp2skill-tools' + sh 'mcp2rest start' + sh 'mcp2rest add chrome-devtools' + } + } + + stage('Install Dependencies') { + steps { + dir('~/.claude/skills/mcp-chrome-devtools/scripts') { + sh 'npm install' + } + } + } + + stage('E2E Tests') { + parallel { + stage('Registration Flow') { + steps { + sh 'bash tests/test_registration.sh' + } + } + stage('Checkout Flow') { + steps { + sh 'bash tests/test_checkout.sh' + } + } + stage('Search Flow') { + steps { + sh 'bash tests/test_search.sh' + } + } + } + } + + stage('Performance Tests') { + steps { + sh 'bash tests/performance_regression_test.sh' + } + } + } + + post { + always { + archiveArtifacts artifacts: '**/*.png,**/*.txt,**/*.json', allowEmptyArchive: true + sh 'mcp2rest stop' + } + failure { + emailext ( + subject: "E2E Tests Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}", + body: "Check console output at ${env.BUILD_URL}", + to: "team@example.com" + ) + } + } +} +``` + +--- + +## Cross-Browser Testing Simulation + +### Device Emulation Matrix + +```bash +#!/bin/bash +# device_matrix_test.sh + +URL="https://example.com" +OUTPUT_DIR="device_screenshots" + +mkdir -p $OUTPUT_DIR + +# Define device viewports +declare -A DEVICES +DEVICES["desktop_1080"]="1920 1080" +DEVICES["desktop_720"]="1280 720" +DEVICES["laptop"]="1366 768" +DEVICES["ipad_portrait"]="768 1024" +DEVICES["ipad_landscape"]="1024 768" +DEVICES["iphone_portrait"]="375 667" +DEVICES["iphone_landscape"]="667 375" +DEVICES["android_portrait"]="360 640" +DEVICES["android_landscape"]="640 360" + +echo "Testing across device viewports..." + +# Open page +node scripts/new_page.js --url "$URL" + +for device in "${!DEVICES[@]}"; do + echo "Testing device: $device" + + # Parse dimensions + read -r width height <<< "${DEVICES[$device]}" + + # Resize window + node scripts/resize_page.js --width $width --height $height + + # Wait for reflow + sleep 2 + + # Capture screenshot + node scripts/take_screenshot.js --fullPage true --filePath "$OUTPUT_DIR/${device}.png" + + # Capture snapshot for debugging + node scripts/take_snapshot.js --filePath "$OUTPUT_DIR/${device}_snapshot.txt" +done + +echo "✓ Device matrix testing complete. Screenshots in $OUTPUT_DIR/" +``` + +--- + +## Advanced JavaScript Extraction + +### Extract Structured Data from SPA + +```bash +#!/bin/bash +# extract_spa_data.sh + +echo "Extracting data from Single Page Application..." + +# Open SPA +node scripts/new_page.js --url https://example.com/dashboard + +# Wait for app to initialize +node scripts/wait_for.js --text "Dashboard" --timeout 15000 + +# Wait for data to load (check for spinner to disappear) +node scripts/evaluate_script.js --function "() => new Promise(resolve => { + const checkSpinner = setInterval(() => { + if (!document.querySelector('.loading-spinner')) { + clearInterval(checkSpinner); + resolve(true); + } + }, 100); +})" + +# Extract React/Vue component state +APP_STATE=$(node scripts/evaluate_script.js --function "() => { + // Try to access React DevTools state + const root = document.querySelector('#root'); + const reactInternals = root._reactRootContainer || root._reactInternalFiber; + + // Or access Vue instance + const vueInstance = root.__vue__; + + // Extract data from global state (Redux, Vuex, etc.) + return { + redux: window.__REDUX_DEVTOOLS_EXTENSION__ ? window.store.getState() : null, + vuex: window.__VUEX_DEVTOOLS_GLOBAL_HOOK__ ? window.$store.state : null, + // Or extract directly from DOM + domData: Array.from(document.querySelectorAll('.data-item')).map(item => ({ + id: item.dataset.id, + title: item.querySelector('.title').textContent, + value: item.querySelector('.value').textContent + })) + }; +}") + +echo "$APP_STATE" | jq '.' > app_state.json + +echo "✓ Extracted application state to app_state.json" +``` + +### Monitor Real-Time Updates + +```bash +#!/bin/bash +# monitor_realtime_updates.sh + +echo "Monitoring real-time updates..." + +# Open page with real-time data +node scripts/new_page.js --url https://example.com/live-feed + +# Set up monitoring script +node scripts/evaluate_script.js --function "() => { + window.updates = []; + window.observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(node => { + if (node.classList && node.classList.contains('update-item')) { + window.updates.push({ + timestamp: new Date().toISOString(), + content: node.textContent, + type: node.dataset.type + }); + } + }); + } + }); + }); + + const container = document.querySelector('.updates-container'); + window.observer.observe(container, { childList: true, subtree: true }); + + return 'Monitoring started'; +}" + +# Wait for updates to accumulate +echo "Collecting updates for 60 seconds..." +sleep 60 + +# Retrieve collected updates +UPDATES=$(node scripts/evaluate_script.js --function "() => window.updates") + +echo "$UPDATES" | jq '.' > realtime_updates.json + +# Clean up +node scripts/evaluate_script.js --function "() => { window.observer.disconnect(); return 'Monitoring stopped'; }" + +echo "✓ Collected updates saved to realtime_updates.json" +``` + +--- + +## Complex Workflow Orchestration + +### Multi-User Simulation + +```bash +#!/bin/bash +# simulate_multi_user.sh + +echo "Simulating multi-user interactions..." + +# User 1: Admin workflow +( + echo "User 1: Admin actions" + node scripts/new_page.js --url https://example.com/admin + node scripts/wait_for.js --text "Admin Panel" --timeout 10000 + # ... admin actions ... +) & + +# User 2: Customer workflow +( + echo "User 2: Customer actions" + node scripts/new_page.js --url https://example.com/shop + node scripts/wait_for.js --text "Products" --timeout 10000 + # ... customer actions ... +) & + +# Wait for both users to complete +wait + +echo "✓ Multi-user simulation complete" +``` + +This advanced examples reference provides production-ready patterns for complex automation, testing, and data extraction workflows. diff --git a/skills/mcp-chrome-devtools/reference/all-tools.md b/skills/mcp-chrome-devtools/reference/all-tools.md new file mode 100644 index 0000000..4edca15 --- /dev/null +++ b/skills/mcp-chrome-devtools/reference/all-tools.md @@ -0,0 +1,772 @@ +# Complete Tool Reference + +Alphabetical listing of all 26 chrome-devtools tools with full parameters and examples. + +## Table of Contents + +- [click](#click) +- [close_page](#close_page) +- [drag](#drag) +- [emulate](#emulate) +- [evaluate_script](#evaluate_script) +- [fill](#fill) +- [fill_form](#fill_form) +- [get_console_message](#get_console_message) +- [get_network_request](#get_network_request) +- [handle_dialog](#handle_dialog) +- [hover](#hover) +- [list_console_messages](#list_console_messages) +- [list_network_requests](#list_network_requests) +- [list_pages](#list_pages) +- [navigate_page](#navigate_page) +- [new_page](#new_page) +- [performance_analyze_insight](#performance_analyze_insight) +- [performance_start_trace](#performance_start_trace) +- [performance_stop_trace](#performance_stop_trace) +- [press_key](#press_key) +- [resize_page](#resize_page) +- [select_page](#select_page) +- [take_screenshot](#take_screenshot) +- [take_snapshot](#take_snapshot) +- [upload_file](#upload_file) +- [wait_for](#wait_for) + +--- + +## click + +Clicks on an element identified by its UID. + +**Group:** Element Interaction + +**Required Parameters:** +- `--uid UID` - Element unique identifier from snapshot + +**Optional Parameters:** +- `--dblClick BOOLEAN` - Double click instead of single click (default: false) + +**Examples:** +```bash +# Single click +node scripts/click.js --uid button_submit_abc123 + +# Double click +node scripts/click.js --uid file_icon_xyz789 --dblClick true +``` + +**Related Tools:** hover, fill, take_snapshot + +--- + +## close_page + +Closes a page by its index. Cannot close the last remaining page. + +**Group:** Page Management + +**Required Parameters:** +- `--pageIdx NUMBER` - Index of page to close (from list_pages) + +**Examples:** +```bash +node scripts/close_page.js --pageIdx 2 +``` + +**Notes:** Always keep at least one page open. Close pages from highest to lowest index to avoid index shifting. + +**Related Tools:** list_pages, new_page, select_page + +--- + +## drag + +Drags one element onto another element. + +**Group:** Element Interaction + +**Required Parameters:** +- `--from-uid UID` - UID of element to drag +- `--to-uid UID` - UID of target drop zone + +**Examples:** +```bash +node scripts/drag.js --from-uid task_item_abc --to-uid dropzone_xyz +``` + +**Related Tools:** hover, click, take_snapshot + +--- + +## emulate + +Emulates network conditions and CPU throttling. + +**Group:** Performance Analysis + +**Optional Parameters:** +- `--networkConditions JSON` - Network throttling config +- `--cpuThrottlingRate NUMBER` - CPU throttling multiplier (1 = normal) + +**Network Conditions Format:** +```json +{ + "downloadThroughput": 50000, + "uploadThroughput": 50000, + "latency": 2000 +} +``` + +**Examples:** +```bash +# Slow 3G +node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}' + +# 4x CPU slowdown +node scripts/emulate.js --cpuThrottlingRate 4 + +# Combined +node scripts/emulate.js --networkConditions '{"downloadThroughput":100000,"uploadThroughput":50000,"latency":100}' --cpuThrottlingRate 2 + +# Reset to normal +node scripts/emulate.js --cpuThrottlingRate 1 +``` + +**Common Presets:** +- Slow 3G: 50KB/s down, 50KB/s up, 2000ms latency +- Fast 3G: 180KB/s down, 84KB/s up, 562ms latency +- 4G: 1.6MB/s down, 750KB/s up, 150ms latency + +**Related Tools:** performance_start_trace, performance_stop_trace + +--- + +## evaluate_script + +Executes JavaScript in the page context and returns JSON-serializable results. + +**Group:** Performance Analysis + +**Required Parameters:** +- `--function STRING` - JavaScript function as string + +**Optional Parameters:** +- `--args JSON_ARRAY` - Function arguments as JSON array + +**Examples:** +```bash +# Simple extraction +node scripts/evaluate_script.js --function "() => document.title" + +# With parameters +node scripts/evaluate_script.js --function "(x, y) => x + y" --args '[5, 3]' + +# Extract array of data +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('h2')).map(h => h.textContent)" + +# Complex object extraction +node scripts/evaluate_script.js --function "() => ({title: document.title, links: document.querySelectorAll('a').length})" +``` + +**Important:** Return values must be JSON-serializable (no DOM nodes, functions, or circular references). + +**Related Tools:** take_snapshot, wait_for + +--- + +## fill + +Types text into inputs/textareas or selects dropdown options. + +**Group:** Element Interaction + +**Required Parameters:** +- `--uid UID` - Element unique identifier +- `--value STRING` - Text to type or option to select + +**Examples:** +```bash +# Text input +node scripts/fill.js --uid input_username_abc --value "john.doe" + +# Textarea +node scripts/fill.js --uid textarea_comment_def --value "This is a long comment" + +# Dropdown select +node scripts/fill.js --uid select_country_ghi --value "United States" +``` + +**Related Tools:** fill_form, click, take_snapshot + +--- + +## fill_form + +Fills multiple form fields at once. + +**Group:** Element Interaction + +**Required Parameters:** +- `--elements JSON_ARRAY` - Array of {uid, value} objects + +**Format:** +```json +[ + {"uid": "input_email", "value": "test@example.com"}, + {"uid": "input_password", "value": "secret123"} +] +``` + +**Examples:** +```bash +node scripts/fill_form.js --elements '[{"uid":"input_email","value":"test@example.com"},{"uid":"input_password","value":"secret123"}]' + +# Multi-line for readability (bash) +node scripts/fill_form.js --elements '[ + {"uid":"input_name","value":"John Doe"}, + {"uid":"input_email","value":"john@example.com"}, + {"uid":"select_country","value":"USA"} +]' +``` + +**Related Tools:** fill, click, take_snapshot + +--- + +## get_console_message + +Retrieves a specific console message by ID. + +**Group:** Inspection & Debugging + +**Required Parameters:** +- `--msgid STRING` - Message ID from list_console_messages + +**Examples:** +```bash +node scripts/get_console_message.js --msgid msg_abc123 +``` + +**Related Tools:** list_console_messages + +--- + +## get_network_request + +Gets details of a specific network request. + +**Group:** Inspection & Debugging + +**Optional Parameters:** +- `--reqid STRING` - Request ID from list_network_requests (if omitted, returns currently selected request in DevTools) + +**Examples:** +```bash +# Specific request +node scripts/get_network_request.js --reqid req_abc123 + +# Currently selected in DevTools +node scripts/get_network_request.js +``` + +**Output includes:** URL, method, status code, headers, request/response body, timing. + +**Related Tools:** list_network_requests + +--- + +## handle_dialog + +Handles browser dialogs (alert, confirm, prompt). + +**Group:** Performance Analysis + +**Required Parameters:** +- `--action STRING` - Either "accept" or "dismiss" + +**Optional Parameters:** +- `--promptText STRING` - Text to enter in prompt dialog (only for prompts) + +**Examples:** +```bash +# Accept alert +node scripts/handle_dialog.js --action accept + +# Dismiss confirm +node scripts/handle_dialog.js --action dismiss + +# Accept prompt with input +node scripts/handle_dialog.js --action accept --promptText "My Answer" +``` + +**Notes:** Dialog must already be open when calling this tool. + +**Related Tools:** click, wait_for + +--- + +## hover + +Hovers the mouse over an element. + +**Group:** Element Interaction + +**Required Parameters:** +- `--uid UID` - Element unique identifier + +**Examples:** +```bash +node scripts/hover.js --uid tooltip_trigger_abc + +# Common pattern: hover then click +node scripts/hover.js --uid menu_trigger_xyz +node scripts/click.js --uid menu_item_settings +``` + +**Use Cases:** Triggering tooltips, dropdown menus, hover effects. + +**Related Tools:** click, take_snapshot + +--- + +## list_console_messages + +Lists console messages (logs, warnings, errors) from the current page. + +**Group:** Inspection & Debugging + +**Optional Parameters:** +- `--pageSize NUMBER` - Number of messages per page +- `--pageIdx NUMBER` - Page index for pagination (0-based) +- `--types STRING` - Comma-separated types: log,warn,error,info +- `--includePreservedMessages BOOLEAN` - Include messages from before current navigation + +**Examples:** +```bash +# All messages +node scripts/list_console_messages.js + +# Only errors +node scripts/list_console_messages.js --types error + +# Errors and warnings +node scripts/list_console_messages.js --types error,warn + +# Paginated +node scripts/list_console_messages.js --pageSize 10 --pageIdx 0 +``` + +**Related Tools:** get_console_message + +--- + +## list_network_requests + +Lists network requests made by the current page. + +**Group:** Inspection & Debugging + +**Optional Parameters:** +- `--pageSize NUMBER` - Number of requests per page +- `--pageIdx NUMBER` - Page index for pagination (0-based) +- `--resourceTypes STRING` - Comma-separated types: fetch,xhr,document,script,stylesheet,image +- `--includePreservedRequests BOOLEAN` - Include requests from before current navigation + +**Examples:** +```bash +# All requests +node scripts/list_network_requests.js + +# Only API calls +node scripts/list_network_requests.js --resourceTypes fetch,xhr + +# Only scripts and stylesheets +node scripts/list_network_requests.js --resourceTypes script,stylesheet + +# Paginated +node scripts/list_network_requests.js --pageSize 20 --pageIdx 0 +``` + +**Related Tools:** get_network_request + +--- + +## list_pages + +Lists all open browser pages with their indices and URLs. + +**Group:** Page Management + +**No Parameters** + +**Examples:** +```bash +node scripts/list_pages.js +``` + +**Output Example:** +``` +Page 0: https://example.com (selected) +Page 1: https://google.com +Page 2: https://github.com +``` + +**Related Tools:** new_page, select_page, close_page + +--- + +## navigate_page + +Navigates the currently selected page. + +**Group:** Page Management + +**Optional Parameters:** +- `--url STRING` - URL to navigate to +- `--type STRING` - Navigation type: navigate, reload, back, forward +- `--ignoreCache BOOLEAN` - Bypass cache on reload +- `--timeout NUMBER` - Navigation timeout in milliseconds + +**Examples:** +```bash +# Navigate to URL +node scripts/navigate_page.js --url https://example.com/page2 + +# Reload page +node scripts/navigate_page.js --type reload + +# Reload ignoring cache +node scripts/navigate_page.js --type reload --ignoreCache true + +# Go back +node scripts/navigate_page.js --type back + +# Go forward +node scripts/navigate_page.js --type forward +``` + +**Related Tools:** new_page, wait_for + +--- + +## new_page + +Creates a new browser page (tab). + +**Group:** Page Management + +**Required Parameters:** +- `--url STRING` - URL to open + +**Optional Parameters:** +- `--timeout NUMBER` - Page load timeout in milliseconds (default: 30000) + +**Examples:** +```bash +node scripts/new_page.js --url https://example.com + +# With longer timeout +node scripts/new_page.js --url https://slow-site.com --timeout 60000 +``` + +**Notes:** New page becomes the selected page automatically. + +**Related Tools:** list_pages, select_page, close_page + +--- + +## performance_analyze_insight + +Gets detailed information about a specific performance insight. + +**Group:** Performance Analysis + +**Required Parameters:** +- `--insightSetId STRING` - Insight set ID from performance trace +- `--insightName STRING` - Name of specific insight to analyze + +**Examples:** +```bash +node scripts/performance_analyze_insight.js --insightSetId set_abc123 --insightName LargestContentfulPaint + +node scripts/performance_analyze_insight.js --insightSetId set_abc123 --insightName CumulativeLayoutShift +``` + +**Common Insight Names:** +- LargestContentfulPaint +- FirstContentfulPaint +- CumulativeLayoutShift +- TotalBlockingTime +- TimeToInteractive + +**Related Tools:** performance_start_trace, performance_stop_trace + +--- + +## performance_start_trace + +Starts performance trace recording. + +**Group:** Performance Analysis + +**Required Parameters:** +- `--reload BOOLEAN` - Reload page before tracing +- `--autoStop BOOLEAN` - Automatically stop when page loads + +**Examples:** +```bash +# Start with page reload +node scripts/performance_start_trace.js --reload true --autoStop false + +# Start without reload +node scripts/performance_start_trace.js --reload false --autoStop true +``` + +**Notes:** Only one trace can be active at a time. Call performance_stop_trace to get results. + +**Related Tools:** performance_stop_trace, performance_analyze_insight + +--- + +## performance_stop_trace + +Stops the active performance trace and returns results. + +**Group:** Performance Analysis + +**No Parameters** + +**Examples:** +```bash +node scripts/performance_stop_trace.js +``` + +**Output includes:** +- Core Web Vitals scores (LCP, FID, CLS) +- Performance insights +- Insight set IDs for detailed analysis +- Timing metrics + +**Related Tools:** performance_start_trace, performance_analyze_insight + +--- + +## press_key + +Presses a key or key combination. + +**Group:** Element Interaction + +**Required Parameters:** +- `--key STRING` - Key or key combination to press + +**Examples:** +```bash +# Single key +node scripts/press_key.js --key Enter +node scripts/press_key.js --key Tab +node scripts/press_key.js --key Escape + +# Arrow keys +node scripts/press_key.js --key ArrowDown +node scripts/press_key.js --key ArrowUp + +# Key combinations (use + separator) +node scripts/press_key.js --key "Control+S" +node scripts/press_key.js --key "Control+Shift+P" +node scripts/press_key.js --key "Alt+F4" +``` + +**Common Keys:** Enter, Tab, Escape, Space, Backspace, Delete, ArrowUp, ArrowDown, ArrowLeft, ArrowRight + +**Modifiers:** Control, Shift, Alt, Meta (Command on Mac) + +**Related Tools:** fill, click + +--- + +## resize_page + +Resizes the browser window to specific dimensions. + +**Group:** Page Management + +**Required Parameters:** +- `--width NUMBER` - Width in pixels +- `--height NUMBER` - Height in pixels + +**Examples:** +```bash +# Desktop +node scripts/resize_page.js --width 1920 --height 1080 + +# Laptop +node scripts/resize_page.js --width 1366 --height 768 + +# Tablet +node scripts/resize_page.js --width 768 --height 1024 + +# Mobile +node scripts/resize_page.js --width 375 --height 667 +``` + +**Common Dimensions:** +- Desktop: 1920x1080, 1440x900, 1366x768 +- Tablet: 768x1024 (iPad), 600x960 +- Mobile: 375x667 (iPhone), 360x640 (Android) + +**Related Tools:** take_screenshot, emulate + +--- + +## select_page + +Switches the active context to a specific page. + +**Group:** Page Management + +**Required Parameters:** +- `--pageIdx NUMBER` - Page index from list_pages + +**Examples:** +```bash +node scripts/select_page.js --pageIdx 0 +node scripts/select_page.js --pageIdx 2 +``` + +**Notes:** All subsequent commands operate on the selected page. + +**Related Tools:** list_pages, new_page + +--- + +## take_screenshot + +Captures a visual screenshot of the page or element. + +**Group:** Inspection & Debugging + +**Optional Parameters:** +- `--format STRING` - Image format: png or jpeg (default: png) +- `--quality NUMBER` - JPEG quality 0-100 (default: 90) +- `--uid STRING` - Element UID to screenshot (if omitted, screenshots viewport) +- `--fullPage BOOLEAN` - Capture full scrollable page (default: false) +- `--filePath STRING` - Path to save image file + +**Examples:** +```bash +# Full page PNG +node scripts/take_screenshot.js --fullPage true --filePath page.png + +# Viewport only +node scripts/take_screenshot.js --filePath viewport.png + +# Specific element +node scripts/take_screenshot.js --uid element_abc123 --filePath element.png + +# Compressed JPEG +node scripts/take_screenshot.js --format jpeg --quality 80 --filePath page.jpg +``` + +**Related Tools:** take_snapshot + +--- + +## take_snapshot + +Captures text-based page structure with element UIDs. + +**Group:** Inspection & Debugging + +**Optional Parameters:** +- `--verbose BOOLEAN` - Include more details (default: false) +- `--filePath STRING` - Path to save snapshot file + +**Examples:** +```bash +# Console output +node scripts/take_snapshot.js + +# Verbose mode +node scripts/take_snapshot.js --verbose true + +# Save to file +node scripts/take_snapshot.js --filePath snapshot.txt + +# Both +node scripts/take_snapshot.js --verbose true --filePath detailed_snapshot.txt +``` + +**Output Format:** +``` +Page: https://example.com +Title: Example Domain + +button "Submit" [uid: button_submit_abc123] +input "Email" [uid: input_email_def456] +link "About" [uid: link_about_ghi789] +``` + +**Important:** Always use UIDs from the most recent snapshot. UIDs regenerate on each snapshot. + +**Related Tools:** click, fill, hover, drag, take_screenshot + +--- + +## upload_file + +Uploads a file through a file input element. + +**Group:** Element Interaction + +**Required Parameters:** +- `--uid UID` - File input element UID +- `--filePath STRING` - Absolute path to file to upload + +**Examples:** +```bash +# Upload document +node scripts/upload_file.js --uid input_file_abc --filePath /Users/username/documents/resume.pdf + +# Upload image +node scripts/upload_file.js --uid input_avatar_xyz --filePath /Users/username/pictures/profile.jpg +``` + +**Notes:** +- Use absolute paths (not relative) +- Use forward slashes in paths +- Verify file exists before upload + +**Related Tools:** click, fill, wait_for + +--- + +## wait_for + +Waits for specific text to appear on the page. + +**Group:** Performance Analysis + +**Required Parameters:** +- `--text STRING` - Text to wait for (exact match) + +**Optional Parameters:** +- `--timeout NUMBER` - Maximum wait time in milliseconds (default: 30000) + +**Examples:** +```bash +# Wait up to 30 seconds (default) +node scripts/wait_for.js --text "Loading complete" + +# Wait up to 10 seconds +node scripts/wait_for.js --text "Welcome" --timeout 10000 + +# Wait for error message +node scripts/wait_for.js --text "Error occurred" --timeout 5000 +``` + +**Notes:** +- Text match is exact (case-sensitive) +- Times out if text doesn't appear within timeout period +- Use after navigation, clicks, or any action that triggers loading + +**Related Tools:** click, navigate_page, take_snapshot diff --git a/skills/mcp-chrome-devtools/reference/troubleshooting.md b/skills/mcp-chrome-devtools/reference/troubleshooting.md new file mode 100644 index 0000000..0be7cea --- /dev/null +++ b/skills/mcp-chrome-devtools/reference/troubleshooting.md @@ -0,0 +1,743 @@ +# Troubleshooting Guide + +Common issues and solutions for chrome-devtools skill. + +## Table of Contents + +- [Connection Issues](#connection-issues) +- [Page Management Problems](#page-management-problems) +- [Element Interaction Issues](#element-interaction-issues) +- [Snapshot and Screenshot Problems](#snapshot-and-screenshot-problems) +- [Console and Network Debugging](#console-and-network-debugging) +- [Performance Analysis Issues](#performance-analysis-issues) +- [General Best Practices](#general-best-practices) + +--- + +## Connection Issues + +### Problem: "Cannot connect to mcp2rest" + +**Symptoms:** +- Scripts fail with connection error +- "ECONNREFUSED" error on port 28888 + +**Solutions:** + +1. **Check if mcp2rest is running:** +```bash +curl http://localhost:28888/health +``` + +Expected: `{"status": "healthy"}` + +2. **Start mcp2rest if not running:** +```bash +mcp2rest start +``` + +3. **Verify chrome-devtools server is loaded:** +```bash +curl http://localhost:28888/servers +``` + +Should list chrome-devtools with "connected" status. + +4. **Reload server if disconnected:** +```bash +mcp2rest reload chrome-devtools +``` + +### Problem: "Server not found" + +**Symptoms:** +- Server not listed in mcp2rest +- Tools return "server not configured" error + +**Solutions:** + +1. **Check installed servers:** +```bash +mcp2rest list +``` + +2. **Add chrome-devtools server:** +```bash +mcp2rest add chrome-devtools +``` + +3. **Restart mcp2rest:** +```bash +mcp2rest restart +``` + +--- + +## Page Management Problems + +### Problem: "Cannot close last page" + +**Symptoms:** +- close_page fails with error about last page + +**Solution:** + +Always keep at least one page open. Open a new page before closing the last one: + +```bash +# Check current pages +node scripts/list_pages.js + +# Open new page first +node scripts/new_page.js --url https://example.com + +# Now close the old page +node scripts/close_page.js --pageIdx 1 +``` + +### Problem: "Page index out of range" + +**Symptoms:** +- select_page or close_page fails +- "Invalid page index" error + +**Solutions:** + +1. **Always list pages first:** +```bash +node scripts/list_pages.js +``` + +2. **Use indices from the current list:** +Page indices shift when pages are closed. Always get fresh indices. + +3. **Close pages in reverse order:** +```bash +# If closing multiple pages, start from highest index +node scripts/close_page.js --pageIdx 3 +node scripts/close_page.js --pageIdx 2 +node scripts/close_page.js --pageIdx 1 +``` + +### Problem: "Navigation timeout" + +**Symptoms:** +- new_page or navigate_page times out +- Page doesn't load within timeout period + +**Solutions:** + +1. **Increase timeout:** +```bash +node scripts/new_page.js --url https://slow-site.com --timeout 60000 +``` + +2. **Check network connectivity:** +Verify the URL loads in a regular browser. + +3. **Use emulation to debug slow loading:** +```bash +# Test without throttling first +node scripts/emulate.js --cpuThrottlingRate 1 +node scripts/new_page.js --url https://example.com +``` + +### Problem: "Wrong page context" + +**Symptoms:** +- Commands execute on wrong page +- Unexpected elements in snapshot + +**Solutions:** + +1. **Check selected page:** +```bash +node scripts/list_pages.js +# Look for "(selected)" indicator +``` + +2. **Explicitly select target page:** +```bash +node scripts/select_page.js --pageIdx 0 +``` + +3. **Pattern: Always select before interaction:** +```bash +node scripts/list_pages.js +node scripts/select_page.js --pageIdx 1 +node scripts/take_snapshot.js +``` + +--- + +## Element Interaction Issues + +### Problem: "Element UID not found" + +**Symptoms:** +- click, fill, or hover fails +- "UID does not exist" error + +**Solutions:** + +1. **Take fresh snapshot:** +UIDs regenerate on each snapshot. Never reuse old UIDs. + +```bash +# Always take new snapshot before interaction +node scripts/take_snapshot.js +# Use UIDs from this output +node scripts/click.js --uid +``` + +2. **Verify element exists:** +Check the snapshot output to confirm the element is present. + +3. **Wait for page to load:** +```bash +node scripts/wait_for.js --text "Page loaded" --timeout 10000 +node scripts/take_snapshot.js +``` + +### Problem: "Click doesn't trigger action" + +**Symptoms:** +- Element is clicked but nothing happens +- No error, but expected behavior doesn't occur + +**Solutions:** + +1. **Wait for page to fully load:** +```bash +node scripts/wait_for.js --text "Ready" --timeout 5000 +node scripts/click.js --uid button_abc +``` + +2. **Try hover first:** +Some elements require hover to become clickable. + +```bash +node scripts/hover.js --uid element_abc +node scripts/click.js --uid element_abc +``` + +3. **Check if element is visible:** +Hidden or off-screen elements may not be clickable. Use take_snapshot with verbose to check visibility. + +4. **Use double-click if needed:** +```bash +node scripts/click.js --uid element_abc --dblClick true +``` + +### Problem: "Fill doesn't work on input" + +**Symptoms:** +- Text not entered into field +- Select dropdown not changing + +**Solutions:** + +1. **Verify element type:** +Use take_snapshot to confirm it's an input/textarea/select. + +2. **Click to focus first:** +```bash +node scripts/click.js --uid input_abc +node scripts/fill.js --uid input_abc --value "text" +``` + +3. **For custom components, use press_key:** +```bash +node scripts/click.js --uid custom_input +node scripts/press_key.js --key "H" +node scripts/press_key.js --key "i" +``` + +4. **For dropdowns, use exact option value:** +Check the HTML to find the correct option value. + +### Problem: "Drag and drop doesn't work" + +**Symptoms:** +- Drag operation completes but element doesn't move +- "Invalid UID" error + +**Solutions:** + +1. **Verify both UIDs are current:** +```bash +node scripts/take_snapshot.js +# Use UIDs from this output +node scripts/drag.js --from-uid --to-uid +``` + +2. **Add wait between operations:** +```bash +node scripts/drag.js --from-uid item1 --to-uid zone1 +node scripts/wait_for.js --text "Moved" --timeout 3000 +``` + +3. **Check if dropzone accepts the element:** +Some drag-and-drop UIs have restrictions on what can be dropped where. + +### Problem: "File upload fails" + +**Symptoms:** +- upload_file fails +- File path error + +**Solutions:** + +1. **Use absolute paths:** +```bash +# Good +node scripts/upload_file.js --uid input_file --filePath /Users/username/file.pdf + +# Bad +# node scripts/upload_file.js --uid input_file --filePath ./file.pdf +``` + +2. **Use forward slashes:** +```bash +# Good +/Users/username/documents/file.pdf + +# Bad (Windows-style) +# C:\Users\username\documents\file.pdf +``` + +3. **Verify file exists:** +```bash +ls -la /Users/username/documents/file.pdf +``` + +4. **Check file input UID:** +Take fresh snapshot and verify the element is a file input. + +--- + +## Snapshot and Screenshot Problems + +### Problem: "Snapshot shows different UIDs each time" + +**Symptoms:** +- UIDs change on each snapshot +- Previously working UIDs stop working + +**Solution:** + +**This is expected behavior.** UIDs are dynamically generated on each snapshot. Always use the most recent snapshot: + +```bash +# Pattern: Always snapshot before interaction +node scripts/take_snapshot.js +# Immediately use UIDs from output +node scripts/click.js --uid +``` + +### Problem: "Screenshot is blank or black" + +**Symptoms:** +- Screenshot file is created but shows blank/black image + +**Solutions:** + +1. **Wait for page to render:** +```bash +node scripts/wait_for.js --text "Content" --timeout 10000 +node scripts/take_screenshot.js --filePath page.png +``` + +2. **Try full page screenshot:** +```bash +node scripts/take_screenshot.js --fullPage true --filePath page.png +``` + +3. **Verify element is visible:** +For element screenshots, ensure the element isn't hidden or off-screen. + +4. **Check page actually loaded:** +```bash +node scripts/take_snapshot.js +# Verify page content appears in snapshot +``` + +### Problem: "Screenshot file not saving" + +**Symptoms:** +- No error but file not created +- "File not found" when opening + +**Solutions:** + +1. **Use absolute path:** +```bash +node scripts/take_screenshot.js --filePath /Users/username/screenshots/page.png +``` + +2. **Ensure directory exists:** +```bash +mkdir -p /Users/username/screenshots +node scripts/take_screenshot.js --filePath /Users/username/screenshots/page.png +``` + +3. **Check file permissions:** +Ensure you have write access to the target directory. + +--- + +## Console and Network Debugging + +### Problem: "Console messages not showing up" + +**Symptoms:** +- list_console_messages returns empty or incomplete results + +**Solutions:** + +1. **Messages accumulate since navigation:** +Console messages are captured from the current page navigation onwards. + +2. **Reload if needed:** +```bash +node scripts/navigate_page.js --type reload +# Wait for page load +node scripts/wait_for.js --text "Ready" --timeout 10000 +# Now check console +node scripts/list_console_messages.js +``` + +3. **Include preserved messages:** +```bash +node scripts/list_console_messages.js --includePreservedMessages true +``` + +4. **Ensure page has errors to show:** +Use take_snapshot or evaluate_script to verify page loaded correctly. + +### Problem: "Network requests list is empty" + +**Symptoms:** +- list_network_requests returns no results +- Expected API calls not showing + +**Solutions:** + +1. **Requests are captured from navigation onwards:** +```bash +# Navigate first to capture requests +node scripts/navigate_page.js --url https://example.com +# Wait for page to load +node scripts/wait_for.js --text "Loaded" --timeout 10000 +# Now check requests +node scripts/list_network_requests.js +``` + +2. **Filter by resource type:** +```bash +# Maybe filtering too strictly +node scripts/list_network_requests.js --resourceTypes fetch,xhr,document +``` + +3. **Include preserved requests:** +```bash +node scripts/list_network_requests.js --includePreservedRequests true +``` + +### Problem: "Cannot find console message or network request ID" + +**Symptoms:** +- get_console_message or get_network_request fails +- "Invalid ID" error + +**Solutions:** + +1. **List first to get IDs:** +```bash +# For console +node scripts/list_console_messages.js +# Copy message ID from output +node scripts/get_console_message.js --msgid + +# For network +node scripts/list_network_requests.js +# Copy request ID from output +node scripts/get_network_request.js --reqid +``` + +2. **IDs are session-specific:** +IDs don't persist across page navigations. Get fresh IDs after navigation. + +--- + +## Performance Analysis Issues + +### Problem: "evaluate_script returns null or error" + +**Symptoms:** +- Script execution fails +- Returns null unexpectedly +- "Evaluation failed" error + +**Solutions:** + +1. **Return JSON-serializable values only:** +```bash +# Good: primitives, arrays, plain objects +node scripts/evaluate_script.js --function "() => document.title" +node scripts/evaluate_script.js --function "() => [1, 2, 3]" +node scripts/evaluate_script.js --function "() => ({key: 'value'})" + +# Bad: DOM nodes, functions, circular references +# node scripts/evaluate_script.js --function "() => document.querySelector('div')" +``` + +2. **Extract values from DOM elements:** +```bash +# Instead of returning DOM nodes, extract their properties +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('a')).map(a => a.href)" +``` + +3. **Check for JavaScript errors:** +```bash +node scripts/list_console_messages.js --types error +``` + +4. **Verify function syntax:** +```bash +# Arrow function +node scripts/evaluate_script.js --function "() => document.title" + +# Function with parameters +node scripts/evaluate_script.js --function "(x, y) => x + y" --args '[5, 3]' +``` + +### Problem: "wait_for times out" + +**Symptoms:** +- wait_for exceeds timeout +- Text never appears + +**Solutions:** + +1. **Increase timeout:** +```bash +node scripts/wait_for.js --text "Loaded" --timeout 30000 +``` + +2. **Verify text actually appears:** +```bash +# Check with snapshot +node scripts/take_snapshot.js +# Look for the expected text +``` + +3. **Text match is exact:** +Check spelling, capitalization, and spacing. + +```bash +# Case-sensitive match +# "Welcome" ≠ "welcome" ≠ "Welcome!" +``` + +4. **Wait for network first:** +```bash +# If text appears after API call, wait longer +node scripts/wait_for.js --text "Data loaded" --timeout 20000 +``` + +### Problem: "Dialog not handled" + +**Symptoms:** +- handle_dialog fails +- "No dialog present" error + +**Solutions:** + +1. **Dialog must be open first:** +```bash +# Trigger dialog +node scripts/click.js --uid button_delete + +# Immediately handle it +node scripts/handle_dialog.js --action accept +``` + +2. **Some "dialogs" are custom HTML:** +If it's not a real browser dialog (alert/confirm/prompt), use click instead: + +```bash +# For custom modal dialogs +node scripts/take_snapshot.js +node scripts/click.js --uid button_modal_ok +``` + +3. **Timing matters:** +Handle dialog immediately after triggering action. + +### Problem: "Performance trace shows unexpected results" + +**Symptoms:** +- CWV scores don't match expectations +- Missing performance data + +**Solutions:** + +1. **Ensure page fully loads:** +```bash +node scripts/performance_start_trace.js --reload true --autoStop false +node scripts/wait_for.js --text "Loaded" --timeout 20000 +node scripts/performance_stop_trace.js +``` + +2. **Use reload for consistent measurement:** +```bash +# For initial page load measurement +node scripts/performance_start_trace.js --reload true --autoStop false +``` + +3. **Clear browser state:** +Navigation with cache clear: +```bash +node scripts/navigate_page.js --url https://example.com --ignoreCache true +``` + +4. **Disable emulation if active:** +```bash +node scripts/emulate.js --cpuThrottlingRate 1 +``` + +### Problem: "Emulation not working" + +**Symptoms:** +- Page loads at normal speed despite emulation +- No visible effect from throttling + +**Solutions:** + +1. **Emulation persists for session:** +Reset to normal first, then apply: + +```bash +# Reset +node scripts/emulate.js --cpuThrottlingRate 1 + +# Then apply desired emulation +node scripts/emulate.js --cpuThrottlingRate 4 +``` + +2. **Network conditions must be valid JSON:** +```bash +# All three properties required +node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}' +``` + +3. **Verify effect with performance trace:** +```bash +node scripts/emulate.js --cpuThrottlingRate 4 +node scripts/performance_start_trace.js --reload true --autoStop false +node scripts/wait_for.js --text "Loaded" --timeout 60000 +node scripts/performance_stop_trace.js +# Check timing metrics in output +``` + +--- + +## General Best Practices + +### Always Snapshot Before Interaction + +UIDs are dynamic. Take a fresh snapshot before every interaction: + +```bash +# Good pattern +node scripts/take_snapshot.js +node scripts/click.js --uid + +# Bad pattern (will fail) +# node scripts/take_snapshot.js +# ... do other things ... +# node scripts/click.js --uid # UID expired! +``` + +### Wait After Actions + +Allow time for UI updates: + +```bash +node scripts/click.js --uid button_submit +node scripts/wait_for.js --text "Success" --timeout 5000 +node scripts/take_snapshot.js +``` + +### Use Absolute Paths + +Always use absolute paths for files: + +```bash +# Good +/Users/username/documents/file.pdf +/home/user/screenshots/page.png + +# Bad +./file.pdf +../screenshots/page.png +``` + +### Check Connection First + +Before running workflows, verify mcp2rest is healthy: + +```bash +curl http://localhost:28888/health +``` + +### List Before Selecting + +Always list pages before selecting or closing: + +```bash +node scripts/list_pages.js +node scripts/select_page.js --pageIdx 1 +``` + +### Handle Errors Gracefully + +Check console and network for debugging: + +```bash +# After error occurs +node scripts/list_console_messages.js --types error +node scripts/list_network_requests.js +node scripts/take_screenshot.js --filePath error_state.png +``` + +### Use Verbose for Debugging + +Get more details when troubleshooting: + +```bash +node scripts/take_snapshot.js --verbose true +``` + +### Save Outputs for Analysis + +Redirect output to files for later review: + +```bash +node scripts/list_console_messages.js > console_log.txt +node scripts/list_network_requests.js > network_log.txt +node scripts/take_snapshot.js --filePath snapshot.txt +``` + +--- + +## Getting Help + +If you encounter issues not covered here: + +1. **Check tool documentation:** @reference/all-tools.md +2. **Review workflows:** @workflows/[tool-group].md +3. **Test with minimal example:** Isolate the problem with simplest reproduction +4. **Check mcp2rest status:** Ensure server is connected and healthy +5. **Restart mcp2rest:** Sometimes a fresh start helps: `mcp2rest restart` diff --git a/skills/mcp-chrome-devtools/scripts/click.js b/skills/mcp-chrome-devtools/scripts/click.js new file mode 100755 index 0000000..95a108c --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/click.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: click + * + * Clicks on the provided element + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('click') + .description('Clicks on the provided element') + .option('--uid ', 'The uid of an element on the page from the page content snapshot (required)') + .option('--dblClick', 'Set to true for double clicks. Default is false.') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.uid) { + console.error('Error: --uid is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.uid !== undefined) { + args['uid'] = options.uid; + } + if (options.dblClick) { + args['dblClick'] = true; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'click', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/close_page.js b/skills/mcp-chrome-devtools/scripts/close_page.js new file mode 100755 index 0000000..6bb4717 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/close_page.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: close_page + * + * Closes the page by its index. The last open page cannot be closed. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('close_page') + .description('Closes the page by its index. The last open page cannot be closed.') + .option('--pageIdx ', 'The index of the page to close. Call list_pages to list pages. (required)', parseFloat) + .addHelpText('after', ' Note: --pageIdx is required') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.pageIdx) { + console.error('Error: --pageIdx is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.pageIdx !== undefined) { + args['pageIdx'] = options.pageIdx; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'close_page', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/drag.js b/skills/mcp-chrome-devtools/scripts/drag.js new file mode 100755 index 0000000..12e3db3 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/drag.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: drag + * + * Drag an element onto another element + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('drag') + .description('Drag an element onto another element') + .option('--from-uid ', 'The uid of the element to drag (required)') + .option('--to-uid ', 'The uid of the element to drop into (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.fromUid) { + console.error('Error: --from-uid is required'); + process.exit(1); + } + if (!options.toUid) { + console.error('Error: --to-uid is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.fromUid !== undefined) { + args['from_uid'] = options.fromUid; + } + if (options.toUid !== undefined) { + args['to_uid'] = options.toUid; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'drag', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/emulate.js b/skills/mcp-chrome-devtools/scripts/emulate.js new file mode 100755 index 0000000..30236fb --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/emulate.js @@ -0,0 +1,39 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: emulate + * + * Emulates various features on the selected page. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('emulate') + .description('Emulates various features on the selected page.') + .option('--networkConditions ', 'Throttle network. Set to \"No emulation\" to disable. If omitted, conditions remain unchanged.. Choices: "No emulation", "Offline", "Slow 3G", "Fast 3G", "Slow 4G", "Fast 4G"') + .option('--cpuThrottlingRate ', 'Represents the CPU slowdown factor. Set the rate to 1 to disable throttling. If omitted, throttling remains unchanged.', parseFloat) + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.networkConditions !== undefined) { + args['networkConditions'] = options.networkConditions; + } + if (options.cpuThrottlingRate !== undefined) { + args['cpuThrottlingRate'] = options.cpuThrottlingRate; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'emulate', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/evaluate_script.js b/skills/mcp-chrome-devtools/scripts/evaluate_script.js new file mode 100755 index 0000000..c45fb0d --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/evaluate_script.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: evaluate_script + * + * Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON +so returned values have to JSON-serializable. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('evaluate_script') + .description('Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON\nso returned values have to JSON-serializable.') + .option('--function ', 'A JavaScript function declaration to be executed by the tool in the currently selected page. +Example without arguments: `() => { + return document.title +}` or `async () => { + return await fetch(\"example.com\") +}`. +Example with arguments: `(el) => { + return el.innerText; +}` + (required)') + .option('--args ', 'An optional list of arguments to pass to the function.') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.function) { + console.error('Error: --function is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.function !== undefined) { + args['function'] = options.function; + } + if (options.args !== undefined) { + args['args'] = options.args; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'evaluate_script', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/fill.js b/skills/mcp-chrome-devtools/scripts/fill.js new file mode 100755 index 0000000..fdc10af --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/fill.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: fill + * + * Type text into a input, text area or select an option from a element.') + .option('--uid ', 'The uid of an element on the page from the page content snapshot (required)') + .option('--value ', 'The value to fill in (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.uid) { + console.error('Error: --uid is required'); + process.exit(1); + } + if (!options.value) { + console.error('Error: --value is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.uid !== undefined) { + args['uid'] = options.uid; + } + if (options.value !== undefined) { + args['value'] = options.value; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'fill', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/fill_form.js b/skills/mcp-chrome-devtools/scripts/fill_form.js new file mode 100755 index 0000000..edf7718 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/fill_form.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: fill_form + * + * Fill out multiple form elements at once + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('fill_form') + .description('Fill out multiple form elements at once') + .option('--elements ', 'Elements from snapshot to fill out. (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.elements) { + console.error('Error: --elements is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.elements !== undefined) { + args['elements'] = options.elements; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'fill_form', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/get_console_message.js b/skills/mcp-chrome-devtools/scripts/get_console_message.js new file mode 100755 index 0000000..c52e0df --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/get_console_message.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: get_console_message + * + * Gets a console message by its ID. You can get all messages by calling list_console_messages. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('get_console_message') + .description('Gets a console message by its ID. You can get all messages by calling list_console_messages.') + .option('--msgid ', 'The msgid of a console message on the page from the listed console messages (required)', parseFloat) + .addHelpText('after', ' Note: --msgid is required') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.msgid) { + console.error('Error: --msgid is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.msgid !== undefined) { + args['msgid'] = options.msgid; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'get_console_message', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/get_network_request.js b/skills/mcp-chrome-devtools/scripts/get_network_request.js new file mode 100755 index 0000000..aa65190 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/get_network_request.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: get_network_request + * + * Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('get_network_request') + .description('Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.') + .option('--reqid ', 'The reqid of the network request. If omitted returns the currently selected request in the DevTools Network panel.', parseFloat) + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.reqid !== undefined) { + args['reqid'] = options.reqid; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'get_network_request', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/handle_dialog.js b/skills/mcp-chrome-devtools/scripts/handle_dialog.js new file mode 100755 index 0000000..9559c4b --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/handle_dialog.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: handle_dialog + * + * If a browser dialog was opened, use this command to handle it + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('handle_dialog') + .description('If a browser dialog was opened, use this command to handle it') + .option('--action ', 'Whether to dismiss or accept the dialog (required). Choices: "accept", "dismiss"') + .option('--promptText ', 'Optional prompt text to enter into the dialog.') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.action) { + console.error('Error: --action is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.action !== undefined) { + args['action'] = options.action; + } + if (options.promptText !== undefined) { + args['promptText'] = options.promptText; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'handle_dialog', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/hover.js b/skills/mcp-chrome-devtools/scripts/hover.js new file mode 100755 index 0000000..9e9de6c --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/hover.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: hover + * + * Hover over the provided element + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('hover') + .description('Hover over the provided element') + .option('--uid ', 'The uid of an element on the page from the page content snapshot (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.uid) { + console.error('Error: --uid is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.uid !== undefined) { + args['uid'] = options.uid; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'hover', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/list_console_messages.js b/skills/mcp-chrome-devtools/scripts/list_console_messages.js new file mode 100755 index 0000000..609a441 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/list_console_messages.js @@ -0,0 +1,47 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: list_console_messages + * + * List all console messages for the currently selected page since the last navigation. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('list_console_messages') + .description('List all console messages for the currently selected page since the last navigation.') + .option('--pageSize ', 'Maximum number of messages to return. When omitted, returns all requests.', (val) => parseInt(val, 10)) + .option('--pageIdx ', 'Page number to return (0-based). When omitted, returns the first page.', (val) => parseInt(val, 10)) + .option('--types ', 'Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.') + .option('--includePreservedMessages', 'Set to true to return the preserved messages over the last 3 navigations.') + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.pageSize !== undefined) { + args['pageSize'] = options.pageSize; + } + if (options.pageIdx !== undefined) { + args['pageIdx'] = options.pageIdx; + } + if (options.types !== undefined) { + args['types'] = options.types; + } + if (options.includePreservedMessages) { + args['includePreservedMessages'] = true; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'list_console_messages', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/list_network_requests.js b/skills/mcp-chrome-devtools/scripts/list_network_requests.js new file mode 100755 index 0000000..00068a7 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/list_network_requests.js @@ -0,0 +1,47 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: list_network_requests + * + * List all requests for the currently selected page since the last navigation. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('list_network_requests') + .description('List all requests for the currently selected page since the last navigation.') + .option('--pageSize ', 'Maximum number of requests to return. When omitted, returns all requests.', (val) => parseInt(val, 10)) + .option('--pageIdx ', 'Page number to return (0-based). When omitted, returns the first page.', (val) => parseInt(val, 10)) + .option('--resourceTypes ', 'Filter requests to only return requests of the specified resource types. When omitted or empty, returns all requests.') + .option('--includePreservedRequests', 'Set to true to return the preserved requests over the last 3 navigations.') + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.pageSize !== undefined) { + args['pageSize'] = options.pageSize; + } + if (options.pageIdx !== undefined) { + args['pageIdx'] = options.pageIdx; + } + if (options.resourceTypes !== undefined) { + args['resourceTypes'] = options.resourceTypes; + } + if (options.includePreservedRequests) { + args['includePreservedRequests'] = true; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'list_network_requests', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/list_pages.js b/skills/mcp-chrome-devtools/scripts/list_pages.js new file mode 100755 index 0000000..8783c0d --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/list_pages.js @@ -0,0 +1,31 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: list_pages + * + * Get a list of pages open in the browser. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('list_pages') + .description('Get a list of pages open in the browser.') + // No options required + .parse(); + +const options = program.opts(); + + const args = {}; + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'list_pages', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/mcp_client.js b/skills/mcp-chrome-devtools/scripts/mcp_client.js new file mode 100644 index 0000000..16ead5b --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/mcp_client.js @@ -0,0 +1,79 @@ +#!/usr/bin/env node +/** + * MCP REST Client for chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * + * Shared MCP REST client for tool scripts. + */ + +import axios from 'axios'; + +// MCP2REST endpoint (configurable via environment variable) +const MCP_REST_URL = process.env.MCP_REST_URL || 'http://localhost:28888'; + +/** + * Call an MCP tool via mcp2rest REST API. + * + * @param {string} server - Server name (e.g., "chrome-devtools") + * @param {string} tool - Tool name (e.g., "click") + * @param {object} args - Tool arguments as object + * @returns {Promise} Tool result as formatted string + */ +export async function callTool(server, tool, args) { + const url = `${MCP_REST_URL}/call`; + const payload = { + server, + tool, + arguments: args || {}, + }; + + try { + const response = await axios.post(url, payload, { + headers: { 'Content-Type': 'application/json' }, + timeout: 30000, + }); + + const data = response.data; + + if (data.success) { + // Extract and format result + const result = data.result || {}; + const content = result.content || []; + + // Format output nicely + const outputParts = []; + for (const item of content) { + if (item.type === 'text') { + outputParts.push(item.text || ''); + } else if (item.type === 'image') { + // For images, just note their presence + const dataLen = (item.data || '').length; + outputParts.push(`[Image data: ${dataLen} bytes]`); + } else if (item.type === 'resource') { + outputParts.push(JSON.stringify(item.resource || {}, null, 2)); + } + } + + return outputParts.length > 0 ? outputParts.join('\n') : JSON.stringify(result, null, 2); + } else { + const error = data.error || {}; + const errorMsg = error.message || 'Unknown error'; + const errorCode = error.code || 'UNKNOWN'; + console.error(`Error [${errorCode}]: ${errorMsg}`); + process.exit(1); + } + } catch (error) { + if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { + console.error(`Error: Cannot connect to mcp2rest at ${MCP_REST_URL}`); + console.error('Make sure mcp2rest is running.'); + } else if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') { + console.error('Error: Request timed out after 30 seconds'); + } else if (error.response) { + console.error(`Error: HTTP ${error.response.status} - ${error.response.data}`); + } else { + console.error(`Error: ${error.message}`); + } + process.exit(1); + } +} diff --git a/skills/mcp-chrome-devtools/scripts/navigate_page.js b/skills/mcp-chrome-devtools/scripts/navigate_page.js new file mode 100755 index 0000000..1bd5bb3 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/navigate_page.js @@ -0,0 +1,47 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: navigate_page + * + * Navigates the currently selected page to a URL. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('navigate_page') + .description('Navigates the currently selected page to a URL.') + .option('--type ', 'Navigate the page by URL, back or forward in history, or reload.. Choices: "url", "back", "forward", "reload"') + .option('--url ', 'Target URL (only type=url)') + .option('--ignoreCache', 'Whether to ignore cache on reload.') + .option('--timeout ', 'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.', (val) => parseInt(val, 10)) + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.type !== undefined) { + args['type'] = options.type; + } + if (options.url !== undefined) { + args['url'] = options.url; + } + if (options.ignoreCache) { + args['ignoreCache'] = true; + } + if (options.timeout !== undefined) { + args['timeout'] = options.timeout; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'navigate_page', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/new_page.js b/skills/mcp-chrome-devtools/scripts/new_page.js new file mode 100755 index 0000000..b53237d --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/new_page.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: new_page + * + * Creates a new page + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('new_page') + .description('Creates a new page') + .option('--url ', 'URL to load in a new page. (required)') + .option('--timeout ', 'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.', (val) => parseInt(val, 10)) + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.url) { + console.error('Error: --url is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.url !== undefined) { + args['url'] = options.url; + } + if (options.timeout !== undefined) { + args['timeout'] = options.timeout; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'new_page', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/package.json b/skills/mcp-chrome-devtools/scripts/package.json new file mode 100644 index 0000000..840d33d --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/package.json @@ -0,0 +1,18 @@ +{ + "name": "mcp-chrome-devtools-skill", + "version": "1.0.0", + "description": "Claude Code skill scripts for chrome-devtools MCP server", + "type": "module", + "dependencies": { + "axios": "^1.6.2", + "commander": "^11.1.0" + }, + "keywords": [ + "mcp", + "claude-code", + "skill", + "chrome-devtools" + ], + "author": "", + "license": "MIT" +} diff --git a/skills/mcp-chrome-devtools/scripts/performance_analyze_insight.js b/skills/mcp-chrome-devtools/scripts/performance_analyze_insight.js new file mode 100755 index 0000000..7992b16 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/performance_analyze_insight.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: performance_analyze_insight + * + * Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('performance_analyze_insight') + .description('Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording.') + .option('--insightSetId ', 'The id for the specific insight set. Only use the ids given in the \"Available insight sets\" list. (required)') + .option('--insightName ', 'The name of the Insight you want more information on. For example: \"DocumentLatency\" or \"LCPBreakdown\" (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.insightSetId) { + console.error('Error: --insightSetId is required'); + process.exit(1); + } + if (!options.insightName) { + console.error('Error: --insightName is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.insightSetId !== undefined) { + args['insightSetId'] = options.insightSetId; + } + if (options.insightName !== undefined) { + args['insightName'] = options.insightName; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'performance_analyze_insight', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/performance_start_trace.js b/skills/mcp-chrome-devtools/scripts/performance_start_trace.js new file mode 100755 index 0000000..55f7ba6 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/performance_start_trace.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: performance_start_trace + * + * Starts a performance trace recording on the selected page. This can be used to look for performance problems and insights to improve the performance of the page. It will also report Core Web Vital (CWV) scores for the page. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('performance_start_trace') + .description('Starts a performance trace recording on the selected page. This can be used to look for performance problems and insights to improve the performance of the page. It will also report Core Web Vital (CWV) scores for the page.') + .option('--reload', 'Determines if, once tracing has started, the page should be automatically reloaded.') + .option('--autoStop', 'Determines if the trace recording should be automatically stopped.') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.reload) { + console.error('Error: --reload is required'); + process.exit(1); + } + if (!options.autoStop) { + console.error('Error: --autoStop is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.reload) { + args['reload'] = true; + } + if (options.autoStop) { + args['autoStop'] = true; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'performance_start_trace', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/performance_stop_trace.js b/skills/mcp-chrome-devtools/scripts/performance_stop_trace.js new file mode 100755 index 0000000..3acae5b --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/performance_stop_trace.js @@ -0,0 +1,31 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: performance_stop_trace + * + * Stops the active performance trace recording on the selected page. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('performance_stop_trace') + .description('Stops the active performance trace recording on the selected page.') + // No options required + .parse(); + +const options = program.opts(); + + const args = {}; + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'performance_stop_trace', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/press_key.js b/skills/mcp-chrome-devtools/scripts/press_key.js new file mode 100755 index 0000000..45bdd55 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/press_key.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: press_key + * + * Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations). + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('press_key') + .description('Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations).') + .option('--key ', 'A key or a combination (e.g., \"Enter\", \"Control+A\", \"Control++\", \"Control+Shift+R\"). Modifiers: Control, Shift, Alt, Meta (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.key) { + console.error('Error: --key is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.key !== undefined) { + args['key'] = options.key; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'press_key', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/resize_page.js b/skills/mcp-chrome-devtools/scripts/resize_page.js new file mode 100755 index 0000000..bee5f80 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/resize_page.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: resize_page + * + * Resizes the selected page's window so that the page has specified dimension + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('resize_page') + .description('Resizes the selected page\'s window so that the page has specified dimension') + .option('--width ', 'Page width (required)', parseFloat) + .addHelpText('after', ' Note: --width is required') + .option('--height ', 'Page height (required)', parseFloat) + .addHelpText('after', ' Note: --height is required') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.width) { + console.error('Error: --width is required'); + process.exit(1); + } + if (!options.height) { + console.error('Error: --height is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.width !== undefined) { + args['width'] = options.width; + } + if (options.height !== undefined) { + args['height'] = options.height; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'resize_page', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/select_page.js b/skills/mcp-chrome-devtools/scripts/select_page.js new file mode 100755 index 0000000..e4d3c88 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/select_page.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: select_page + * + * Select a page as a context for future tool calls. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('select_page') + .description('Select a page as a context for future tool calls.') + .option('--pageIdx ', 'The index of the page to select. Call list_pages to list pages. (required)', parseFloat) + .addHelpText('after', ' Note: --pageIdx is required') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.pageIdx) { + console.error('Error: --pageIdx is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.pageIdx !== undefined) { + args['pageIdx'] = options.pageIdx; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'select_page', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/take_screenshot.js b/skills/mcp-chrome-devtools/scripts/take_screenshot.js new file mode 100755 index 0000000..fe585a3 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/take_screenshot.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: take_screenshot + * + * Take a screenshot of the page or element. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('take_screenshot') + .description('Take a screenshot of the page or element.') + .option('--format ', 'Type of format to save the screenshot as. Default is \"png\". Choices: "png", "jpeg", "webp"') + .option('--quality ', 'Compression quality for JPEG and WebP formats (0-100). Higher values mean better quality but larger file sizes. Ignored for PNG format.', parseFloat) + .option('--uid ', 'The uid of an element on the page from the page content snapshot. If omitted takes a pages screenshot.') + .option('--fullPage', 'If set to true takes a screenshot of the full page instead of the currently visible viewport. Incompatible with uid.') + .option('--filePath ', 'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.') + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.format !== undefined) { + args['format'] = options.format; + } + if (options.quality !== undefined) { + args['quality'] = options.quality; + } + if (options.uid !== undefined) { + args['uid'] = options.uid; + } + if (options.fullPage) { + args['fullPage'] = true; + } + if (options.filePath !== undefined) { + args['filePath'] = options.filePath; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'take_screenshot', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/take_snapshot.js b/skills/mcp-chrome-devtools/scripts/take_snapshot.js new file mode 100755 index 0000000..4197647 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/take_snapshot.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: take_snapshot + * + * Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique +identifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected +in the DevTools Elements panel (if any). + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('take_snapshot') + .description('Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique\nidentifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected\nin the DevTools Elements panel (if any).') + .option('--verbose', 'Whether to include all possible information available in the full a11y tree. Default is false.') + .option('--filePath ', 'The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.') + .parse(); + +const options = program.opts(); + + // Build arguments object + const args = {}; + if (options.verbose) { + args['verbose'] = true; + } + if (options.filePath !== undefined) { + args['filePath'] = options.filePath; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'take_snapshot', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/upload_file.js b/skills/mcp-chrome-devtools/scripts/upload_file.js new file mode 100755 index 0000000..2576e76 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/upload_file.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: upload_file + * + * Upload a file through a provided element. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('upload_file') + .description('Upload a file through a provided element.') + .option('--uid ', 'The uid of the file input element or an element that will open file chooser on the page from the page content snapshot (required)') + .option('--filePath ', 'The local path of the file to upload (required)') + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.uid) { + console.error('Error: --uid is required'); + process.exit(1); + } + if (!options.filePath) { + console.error('Error: --filePath is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.uid !== undefined) { + args['uid'] = options.uid; + } + if (options.filePath !== undefined) { + args['filePath'] = options.filePath; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'upload_file', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/scripts/wait_for.js b/skills/mcp-chrome-devtools/scripts/wait_for.js new file mode 100755 index 0000000..3b19f31 --- /dev/null +++ b/skills/mcp-chrome-devtools/scripts/wait_for.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node +/** + * MCP Server: chrome-devtools + * Server Version: 0.10.2 + * Generated: 2025-11-23 + * Tool: wait_for + * + * Wait for the specified text to appear on the selected page. + */ + +import { program } from 'commander'; +import { callTool } from './mcp_client.js'; + +program + .name('wait_for') + .description('Wait for the specified text to appear on the selected page.') + .option('--text ', 'Text to appear on the page (required)') + .option('--timeout ', 'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.', (val) => parseInt(val, 10)) + .parse(); + +const options = program.opts(); + + // Validate required options + if (!options.text) { + console.error('Error: --text is required'); + process.exit(1); + } + + // Build arguments object + const args = {}; + if (options.text !== undefined) { + args['text'] = options.text; + } + if (options.timeout !== undefined) { + args['timeout'] = options.timeout; + } + +// Call the tool +try { + const result = await callTool('chrome-devtools', 'wait_for', args); + console.log(result); +} catch (error) { + console.error('Error:', error.message); + process.exit(1); +} diff --git a/skills/mcp-chrome-devtools/workflows/element-interaction.md b/skills/mcp-chrome-devtools/workflows/element-interaction.md new file mode 100644 index 0000000..233b42a --- /dev/null +++ b/skills/mcp-chrome-devtools/workflows/element-interaction.md @@ -0,0 +1,310 @@ +# Element Interaction Workflows + +User input simulation for clicking, typing, form filling, and drag & drop operations. + +## Tools in This Group + +### click +Clicks on an element identified by its UID. + +**Required:** `--uid UID` +**Optional:** `--dblClick [true|false]` + +```bash +# Single click +node scripts/click.js --uid button_submit_abc123 + +# Double click +node scripts/click.js --uid file_icon_xyz789 --dblClick true +``` + +### fill +Types text into inputs, textareas, or selects options in dropdown menus. + +**Required:** `--uid UID --value VALUE` + +```bash +# Fill text input +node scripts/fill.js --uid input_username_abc --value john.doe + +# Fill textarea +node scripts/fill.js --uid textarea_comment_def --value "This is a comment" + +# Select dropdown option +node scripts/fill.js --uid select_country_ghi --value "United States" +``` + +### fill_form +Fills multiple form fields at once using a JSON array. + +**Required:** `--elements JSON_ARRAY` + +```bash +node scripts/fill_form.js --elements '[{"uid":"input_email","value":"test@example.com"},{"uid":"input_password","value":"secret123"}]' +``` + +### hover +Hovers the mouse over an element. + +**Required:** `--uid UID` + +```bash +node scripts/hover.js --uid tooltip_trigger_abc +``` + +### drag +Drags one element onto another element. + +**Required:** `--from-uid FROM_UID --to-uid TO_UID` + +```bash +node scripts/drag.js --from-uid draggable_item_abc --to-uid dropzone_xyz +``` + +### upload_file +Uploads a file through a file input element. + +**Required:** `--uid UID --filePath FILEPATH` + +```bash +node scripts/upload_file.js --uid input_file_upload --filePath /Users/username/documents/resume.pdf +``` + +### press_key +Presses a key or key combination (for keyboard shortcuts, navigation, special keys). + +**Required:** `--key KEY` + +```bash +# Single key +node scripts/press_key.js --key Enter + +# Key combination +node scripts/press_key.js --key "Control+S" + +# Navigation +node scripts/press_key.js --key ArrowDown +``` + +## Workflows + +### Workflow: Login Form Automation + +Complete login process with validation: + +- [ ] Open login page: `node scripts/new_page.js --url https://example.com/login` +- [ ] Wait for form: `node scripts/wait_for.js --text "Sign In" --timeout 5000` +- [ ] Get element UIDs: `node scripts/take_snapshot.js` +- [ ] Fill username: `node scripts/fill.js --uid input_username_a1b2 --value testuser` +- [ ] Fill password: `node scripts/fill.js --uid input_password_c3d4 --value mypassword123` +- [ ] Submit form: `node scripts/click.js --uid button_submit_e5f6` +- [ ] Wait for redirect: `node scripts/wait_for.js --text "Dashboard" --timeout 10000` +- [ ] Verify login: `node scripts/take_screenshot.js --filePath logged_in.png` + +**Input Example:** +``` +Username field UID: input_username_a1b2 +Password field UID: input_password_c3d4 +Submit button UID: button_submit_e5f6 +``` + +**Expected Output:** +User logged in successfully, redirected to dashboard. + +### Workflow: Multi-Field Form with Dropdowns + +Fill complex form with various input types: + +- [ ] Navigate to form: `node scripts/new_page.js --url https://example.com/signup` +- [ ] Get structure: `node scripts/take_snapshot.js` +- [ ] Fill first name: `node scripts/fill.js --uid input_firstname --value John` +- [ ] Fill last name: `node scripts/fill.js --uid input_lastname --value Doe` +- [ ] Fill email: `node scripts/fill.js --uid input_email --value john.doe@example.com` +- [ ] Select country: `node scripts/fill.js --uid select_country --value "United States"` +- [ ] Select state: `node scripts/fill.js --uid select_state --value California` +- [ ] Fill textarea: `node scripts/fill.js --uid textarea_bio --value "Software engineer with 5 years experience"` +- [ ] Submit: `node scripts/click.js --uid button_register` +- [ ] Verify: `node scripts/wait_for.js --text "Registration successful" --timeout 10000` + +**Expected Output:** +All form fields filled correctly, registration completed. + +### Workflow: Bulk Form Filling + +Use fill_form for efficient multi-field updates: + +- [ ] Open form: `node scripts/new_page.js --url https://example.com/profile` +- [ ] Identify UIDs: `node scripts/take_snapshot.js` +- [ ] Fill all fields at once: +```bash +node scripts/fill_form.js --elements '[ + {"uid":"input_name","value":"John Doe"}, + {"uid":"input_email","value":"john@example.com"}, + {"uid":"input_phone","value":"555-1234"}, + {"uid":"select_timezone","value":"America/Los_Angeles"} +]' +``` +- [ ] Review changes: `node scripts/take_snapshot.js` +- [ ] Save: `node scripts/click.js --uid button_save` +- [ ] Verify: `node scripts/wait_for.js --text "Profile updated" --timeout 5000` + +**Expected Output:** +All fields updated in single operation, profile saved successfully. + +### Workflow: File Upload with Validation + +Upload a file and verify success: + +- [ ] Navigate to upload page: `node scripts/new_page.js --url https://example.com/upload` +- [ ] Get file input UID: `node scripts/take_snapshot.js` +- [ ] Select file: `node scripts/upload_file.js --uid input_file_abc123 --filePath /Users/username/documents/report.pdf` +- [ ] Wait for preview: `node scripts/wait_for.js --text "report.pdf" --timeout 5000` +- [ ] Verify file name appears: `node scripts/take_snapshot.js` +- [ ] Click upload button: `node scripts/click.js --uid button_upload_xyz` +- [ ] Wait for completion: `node scripts/wait_for.js --text "Upload successful" --timeout 30000` +- [ ] Capture confirmation: `node scripts/take_screenshot.js --filePath upload_complete.png` + +**Input Example:** +File path: `/Users/username/documents/report.pdf` +File input UID: `input_file_abc123` + +**Expected Output:** +File uploaded successfully, confirmation message displayed. + +### Workflow: Drag and Drop Interface + +Interact with drag-and-drop components: + +- [ ] Open drag interface: `node scripts/new_page.js --url https://example.com/kanban` +- [ ] Get board structure: `node scripts/take_snapshot.js` +- [ ] Drag task 1: `node scripts/drag.js --from-uid task_item_1 --to-uid column_in_progress` +- [ ] Wait for update: `node scripts/wait_for.js --text "Task moved" --timeout 3000` +- [ ] Drag task 2: `node scripts/drag.js --from-uid task_item_2 --to-uid column_done` +- [ ] Verify final state: `node scripts/take_snapshot.js` +- [ ] Save changes: `node scripts/click.js --uid button_save_board` + +**Expected Output:** +Tasks moved between columns, board state updated and saved. + +### Workflow: Keyboard Navigation + +Use keyboard shortcuts and navigation keys: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/editor` +- [ ] Focus text area: `node scripts/click.js --uid textarea_editor_abc` +- [ ] Type content: `node scripts/fill.js --uid textarea_editor_abc --value "Hello world"` +- [ ] Select all: `node scripts/press_key.js --key "Control+A"` +- [ ] Copy: `node scripts/press_key.js --key "Control+C"` +- [ ] Navigate down: `node scripts/press_key.js --key ArrowDown` +- [ ] Paste: `node scripts/press_key.js --key "Control+V"` +- [ ] Save: `node scripts/press_key.js --key "Control+S"` +- [ ] Verify save: `node scripts/wait_for.js --text "Saved" --timeout 5000` + +**Expected Output:** +Keyboard shortcuts execute correctly, content manipulated and saved. + +### Workflow: Hover Tooltips and Menus + +Interact with hover-triggered UI elements: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/dashboard` +- [ ] Get elements: `node scripts/take_snapshot.js` +- [ ] Hover over help icon: `node scripts/hover.js --uid icon_help_abc` +- [ ] Wait for tooltip: `node scripts/wait_for.js --text "Click for help" --timeout 2000` +- [ ] Capture tooltip: `node scripts/take_screenshot.js --filePath tooltip.png` +- [ ] Hover over menu: `node scripts/hover.js --uid menu_trigger_xyz` +- [ ] Wait for dropdown: `node scripts/wait_for.js --text "Settings" --timeout 2000` +- [ ] Click menu item: `node scripts/click.js --uid menu_item_settings` + +**Expected Output:** +Tooltips and dropdowns appear on hover, menu items clickable. + +## Common Patterns + +### Pattern: Always Snapshot Before Interaction + +Get fresh UIDs for every interaction: + +```bash +# 1. Navigate to page +node scripts/new_page.js --url https://example.com/form + +# 2. Wait for page load +node scripts/wait_for.js --text "Submit" --timeout 5000 + +# 3. Get current element UIDs +node scripts/take_snapshot.js + +# 4. Use UIDs from snapshot output +node scripts/fill.js --uid --value "data" +``` + +### Pattern: Form Validation Handling + +Handle form validation errors: + +```bash +# 1. Fill form +node scripts/fill.js --uid input_email --value "invalid-email" + +# 2. Submit +node scripts/click.js --uid button_submit + +# 3. Check for error message +node scripts/wait_for.js --text "Invalid email" --timeout 3000 + +# 4. Correct the input +node scripts/fill.js --uid input_email --value "valid@example.com" + +# 5. Resubmit +node scripts/click.js --uid button_submit +``` + +### Pattern: Wait After Each Interaction + +Ensure UI updates before next action: + +```bash +# 1. Click button +node scripts/click.js --uid button_load_more + +# 2. Wait for new content +node scripts/wait_for.js --text "Showing 20 items" --timeout 5000 + +# 3. Now interact with new elements +node scripts/take_snapshot.js +``` + +## Troubleshooting + +**Problem:** Element UID not found + +**Solution:** UIDs are dynamic. Always take a fresh snapshot before interaction. Don't reuse old UIDs. + +**Problem:** Click doesn't trigger action + +**Solution:** +- Ensure element is visible and clickable (not hidden) +- Try waiting for page to fully load first with `wait_for.js` +- Check if element requires hover first: use `hover.js` then `click.js` + +**Problem:** Fill doesn't work on input + +**Solution:** +- Verify the element is an input/textarea/select +- For some custom components, use `click.js` to focus, then `press_key.js` to type +- Check if page has JavaScript that prevents fill + +**Problem:** File upload fails + +**Solution:** +- Use absolute file paths (not relative) +- Verify file exists at the specified path +- Use forward slashes in paths: `/Users/username/file.pdf` + +**Problem:** Drag and drop doesn't work + +**Solution:** +- Ensure both UIDs are valid and current +- Some drag implementations require specific timing - add `wait_for.js` between actions +- Verify dropzone accepts the dragged element type diff --git a/skills/mcp-chrome-devtools/workflows/inspection-debugging.md b/skills/mcp-chrome-devtools/workflows/inspection-debugging.md new file mode 100644 index 0000000..60524c9 --- /dev/null +++ b/skills/mcp-chrome-devtools/workflows/inspection-debugging.md @@ -0,0 +1,326 @@ +# Inspection & Debugging Workflows + +Monitor and debug web applications using snapshots, screenshots, console logs, and network requests. + +## Tools in This Group + +### take_snapshot +Captures text-based page structure from the accessibility tree with element UIDs. + +**Optional:** `--verbose [true|false]`, `--filePath FILEPATH` + +```bash +# Console output +node scripts/take_snapshot.js + +# Verbose mode (more details) +node scripts/take_snapshot.js --verbose true + +# Save to file +node scripts/take_snapshot.js --filePath snapshot.txt +``` + +**Output Example:** +``` +Page: https://example.com +Title: Example Domain + +button "Submit" [uid: button_submit_abc123] +input "Email" [uid: input_email_def456] +link "About" [uid: link_about_ghi789] +``` + +### take_screenshot +Captures visual screenshot of the page or specific element. + +**Optional:** `--format [png|jpeg]`, `--quality 0-100`, `--uid UID`, `--fullPage [true|false]`, `--filePath FILEPATH` + +```bash +# Full page screenshot +node scripts/take_screenshot.js --format png --fullPage true --filePath page.png + +# Element screenshot +node scripts/take_screenshot.js --uid element_abc123 --filePath element.png + +# Compressed JPEG +node scripts/take_screenshot.js --format jpeg --quality 80 --filePath page.jpg +``` + +### list_console_messages +Lists console logs, warnings, and errors from the current page. + +**Optional:** `--pageSize SIZE`, `--pageIdx INDEX`, `--types [log,warn,error,info]`, `--includePreservedMessages [true|false]` + +```bash +# All messages +node scripts/list_console_messages.js + +# Only errors +node scripts/list_console_messages.js --types error + +# Paginated results +node scripts/list_console_messages.js --pageSize 10 --pageIdx 0 +``` + +### get_console_message +Retrieves a specific console message by ID. + +**Required:** `--msgid MESSAGE_ID` + +```bash +node scripts/get_console_message.js --msgid msg_abc123 +``` + +### list_network_requests +Lists network requests made by the current page. + +**Optional:** `--pageSize SIZE`, `--pageIdx INDEX`, `--resourceTypes [fetch,xhr,document,script,stylesheet]`, `--includePreservedRequests [true|false]` + +```bash +# All requests +node scripts/list_network_requests.js + +# Only API calls +node scripts/list_network_requests.js --resourceTypes fetch,xhr + +# Paginated results +node scripts/list_network_requests.js --pageSize 20 --pageIdx 0 +``` + +### get_network_request +Retrieves details of a specific network request. + +**Optional:** `--reqid REQUEST_ID` + +```bash +# Get specific request +node scripts/get_network_request.js --reqid req_abc123 + +# Get currently selected request in DevTools +node scripts/get_network_request.js +``` + +## Workflows + +### Workflow: Debug JavaScript Errors + +Identify and analyze console errors: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/app` +- [ ] Wait for page load: `node scripts/wait_for.js --text "Welcome" --timeout 10000` +- [ ] List all console messages: `node scripts/list_console_messages.js` +- [ ] Filter errors only: `node scripts/list_console_messages.js --types error` +- [ ] Get specific error details: `node scripts/get_console_message.js --msgid ` +- [ ] Take screenshot of error state: `node scripts/take_screenshot.js --filePath error_state.png` +- [ ] Take snapshot for context: `node scripts/take_snapshot.js --filePath error_snapshot.txt` + +**Expected Output:** +Console errors identified, stack traces captured, visual state documented. + +### Workflow: Monitor API Calls + +Track network requests and responses: + +- [ ] Open application: `node scripts/new_page.js --url https://example.com/dashboard` +- [ ] Trigger data load: `node scripts/click.js --uid button_load_data` +- [ ] Wait for request: `node scripts/wait_for.js --text "Data loaded" --timeout 10000` +- [ ] List API calls: `node scripts/list_network_requests.js --resourceTypes fetch,xhr` +- [ ] Get specific request: `node scripts/get_network_request.js --reqid ` +- [ ] Verify response data in output +- [ ] Save network log: `node scripts/list_network_requests.js > network_log.txt` + +**Expected Output:** +All API calls logged, request/response details captured, timing information available. + +### Workflow: Visual Regression Testing + +Capture screenshots for comparison: + +- [ ] Open baseline page: `node scripts/new_page.js --url https://example.com/page` +- [ ] Wait for load: `node scripts/wait_for.js --text "Content loaded" --timeout 5000` +- [ ] Capture full page: `node scripts/take_screenshot.js --fullPage true --filePath baseline.png` +- [ ] Capture header: `node scripts/take_screenshot.js --uid header_main --filePath header.png` +- [ ] Capture footer: `node scripts/take_screenshot.js --uid footer_main --filePath footer.png` +- [ ] Navigate to variant: `node scripts/navigate_page.js --url https://example.com/page?variant=b` +- [ ] Wait for load: `node scripts/wait_for.js --text "Content loaded" --timeout 5000` +- [ ] Capture variant: `node scripts/take_screenshot.js --fullPage true --filePath variant.png` + +**Expected Output:** +Screenshots captured for visual comparison, specific components isolated. + +### Workflow: Form Submission Debugging + +Debug form submission issues: + +- [ ] Open form: `node scripts/new_page.js --url https://example.com/contact` +- [ ] Initial snapshot: `node scripts/take_snapshot.js` +- [ ] Fill form fields: `node scripts/fill.js --uid input_name --value "Test User"` +- [ ] Continue filling: `node scripts/fill.js --uid input_email --value "test@example.com"` +- [ ] Submit form: `node scripts/click.js --uid button_submit` +- [ ] Monitor console: `node scripts/list_console_messages.js --types error,warn` +- [ ] Monitor network: `node scripts/list_network_requests.js --resourceTypes fetch,xhr` +- [ ] Get POST request: `node scripts/get_network_request.js --reqid ` +- [ ] Check response: Verify status code and response body in output +- [ ] Take error screenshot: `node scripts/take_screenshot.js --filePath form_error.png` + +**Expected Output:** +Form submission tracked, network call details captured, errors identified. + +### Workflow: Content Extraction + +Extract page content and structure: + +- [ ] Navigate to page: `node scripts/new_page.js --url https://example.com/article` +- [ ] Wait for content: `node scripts/wait_for.js --text "Published" --timeout 5000` +- [ ] Take detailed snapshot: `node scripts/take_snapshot.js --verbose true --filePath article_structure.txt` +- [ ] Extract main content: `node scripts/evaluate_script.js --function "() => document.querySelector('article').textContent"` +- [ ] Extract metadata: `node scripts/evaluate_script.js --function "() => ({title: document.title, author: document.querySelector('.author').textContent})"` +- [ ] Screenshot article: `node scripts/take_screenshot.js --uid article_main --filePath article.png` +- [ ] List external resources: `node scripts/list_network_requests.js --resourceTypes script,stylesheet,image` + +**Expected Output:** +Page structure documented, content extracted, external dependencies identified. + +### Workflow: Performance Monitoring + +Monitor page performance and resource loading: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/heavy-page` +- [ ] Wait for interactive: `node scripts/wait_for.js --text "Loaded" --timeout 30000` +- [ ] List all requests: `node scripts/list_network_requests.js` +- [ ] Identify slow requests: Review timing in network list output +- [ ] Get slow request details: `node scripts/get_network_request.js --reqid ` +- [ ] Check console warnings: `node scripts/list_console_messages.js --types warn` +- [ ] Take final screenshot: `node scripts/take_screenshot.js --filePath loaded_state.png` + +**Expected Output:** +Resource loading times captured, slow requests identified, console warnings logged. + +### Workflow: Multi-Step User Flow Debugging + +Debug complex user interactions: + +- [ ] Start flow: `node scripts/new_page.js --url https://example.com/checkout` +- [ ] **Step 1: Cart** + - [ ] Snapshot: `node scripts/take_snapshot.js --filePath step1_snapshot.txt` + - [ ] Screenshot: `node scripts/take_screenshot.js --filePath step1_cart.png` + - [ ] Console: `node scripts/list_console_messages.js > step1_console.txt` + - [ ] Network: `node scripts/list_network_requests.js > step1_network.txt` + - [ ] Next: `node scripts/click.js --uid button_checkout` +- [ ] **Step 2: Shipping** + - [ ] Wait: `node scripts/wait_for.js --text "Shipping Information" --timeout 5000` + - [ ] Snapshot: `node scripts/take_snapshot.js --filePath step2_snapshot.txt` + - [ ] Screenshot: `node scripts/take_screenshot.js --filePath step2_shipping.png` + - [ ] Fill: `node scripts/fill_form.js --elements '[{"uid":"input_address","value":"123 Main St"}]'` + - [ ] Next: `node scripts/click.js --uid button_continue` +- [ ] **Step 3: Payment** + - [ ] Wait: `node scripts/wait_for.js --text "Payment Method" --timeout 5000` + - [ ] Snapshot: `node scripts/take_snapshot.js --filePath step3_snapshot.txt` + - [ ] Console errors: `node scripts/list_console_messages.js --types error` + - [ ] Network calls: `node scripts/list_network_requests.js --resourceTypes fetch,xhr` + +**Expected Output:** +Full debugging trace of multi-step flow, each step documented with snapshot/screenshot/logs. + +## Common Patterns + +### Pattern: Snapshot First, Then Screenshot + +Use snapshot for UIDs and structure, screenshot for visual verification: + +```bash +# 1. Get structure and UIDs +node scripts/take_snapshot.js --filePath structure.txt + +# 2. Get visual representation +node scripts/take_screenshot.js --filePath visual.png + +# 3. Use UIDs from snapshot for interaction +node scripts/click.js --uid +``` + +### Pattern: Filter Console by Type + +Focus on specific message types: + +```bash +# Errors only (most critical) +node scripts/list_console_messages.js --types error + +# Errors and warnings +node scripts/list_console_messages.js --types error,warn + +# Everything +node scripts/list_console_messages.js +``` + +### Pattern: Track API Call Sequence + +Monitor API calls in order: + +```bash +# 1. Before action +node scripts/list_network_requests.js > before.txt + +# 2. Trigger action +node scripts/click.js --uid button_submit + +# 3. After action +node scripts/list_network_requests.js > after.txt + +# 4. Compare to see new requests +# (manually diff before.txt and after.txt) +``` + +### Pattern: Element-Specific Screenshot + +Capture specific UI components: + +```bash +# 1. Get element UID +node scripts/take_snapshot.js + +# 2. Screenshot just that element +node scripts/take_screenshot.js --uid --filePath component.png +``` + +## Troubleshooting + +**Problem:** Snapshot shows different UIDs each time + +**Solution:** This is expected. UIDs are regenerated on each snapshot. Always use the most recent snapshot before interaction. + +**Problem:** Screenshot is blank or black + +**Solution:** +- Wait for page to fully load with `wait_for.js` +- Check if element is visible (not hidden or off-screen) +- Try full page screenshot first: `--fullPage true` + +**Problem:** Console messages not showing up + +**Solution:** +- Messages accumulate since last navigation +- Reload page if you need to clear: `navigate_page.js --type reload` +- Use `--includePreservedMessages true` to see older messages + +**Problem:** Network requests list is empty + +**Solution:** +- Requests are captured from current navigation onwards +- Navigate to page after opening it to capture requests +- Use `--includePreservedRequests true` to see older requests + +**Problem:** Cannot find specific console message ID + +**Solution:** +- Run `list_console_messages.js` first to get message IDs +- Message IDs are shown in the list output +- Use the exact ID from the list in `get_console_message.js` + +**Problem:** Screenshot file path error + +**Solution:** +- Use absolute paths: `/Users/username/screenshots/image.png` +- Use forward slashes (not backslashes) +- Ensure directory exists before saving diff --git a/skills/mcp-chrome-devtools/workflows/page-management.md b/skills/mcp-chrome-devtools/workflows/page-management.md new file mode 100644 index 0000000..41e2d3d --- /dev/null +++ b/skills/mcp-chrome-devtools/workflows/page-management.md @@ -0,0 +1,218 @@ +# Page Management Workflows + +Browser window and tab operations for managing multiple pages and navigation. + +## Tools in This Group + +### new_page +Creates a new browser page (tab). + +**Required:** `--url URL` +**Optional:** `--timeout MILLISECONDS` + +```bash +node scripts/new_page.js --url https://example.com --timeout 30000 +``` + +### list_pages +Lists all open pages with their indices and URLs. + +```bash +node scripts/list_pages.js +``` + +**Output Example:** +``` +Page 0: https://example.com (selected) +Page 1: https://google.com +Page 2: https://github.com +``` + +### select_page +Switches the active context to a specific page by index. + +**Required:** `--pageIdx INDEX` + +```bash +node scripts/select_page.js --pageIdx 1 +``` + +### navigate_page +Navigates the currently selected page to a new URL. + +**Optional:** `--url URL`, `--type [navigate|reload|back|forward]`, `--ignoreCache [true|false]`, `--timeout MILLISECONDS` + +```bash +# Navigate to URL +node scripts/navigate_page.js --url https://example.com/page2 + +# Reload page +node scripts/navigate_page.js --type reload --ignoreCache true + +# Go back +node scripts/navigate_page.js --type back +``` + +### resize_page +Resizes the browser window to specific dimensions. + +**Required:** `--width WIDTH --height HEIGHT` + +```bash +node scripts/resize_page.js --width 1920 --height 1080 +``` + +### close_page +Closes a page by its index. Cannot close the last remaining page. + +**Required:** `--pageIdx INDEX` + +```bash +node scripts/close_page.js --pageIdx 2 +``` + +## Workflows + +### Workflow: Open Multiple Research Tabs + +Open several pages for research or comparison: + +- [ ] List current pages: `node scripts/list_pages.js` +- [ ] Open first article: `node scripts/new_page.js --url https://example.com/article1` +- [ ] Open second article: `node scripts/new_page.js --url https://example.com/article2` +- [ ] Open third article: `node scripts/new_page.js --url https://example.com/article3` +- [ ] Verify all open: `node scripts/list_pages.js` + +**Expected Output:** +Multiple tabs open, each with different content, ready for analysis. + +### Workflow: Navigate Through Site Pages + +Walk through a multi-page flow: + +- [ ] Start at homepage: `node scripts/new_page.js --url https://example.com` +- [ ] Take initial snapshot: `node scripts/take_snapshot.js` +- [ ] Click "About" link: `node scripts/click.js --uid link_about_xyz` +- [ ] Wait for page load: `node scripts/wait_for.js --text "About Us" --timeout 5000` +- [ ] Go back: `node scripts/navigate_page.js --type back` +- [ ] Verify homepage: `node scripts/wait_for.js --text "Welcome" --timeout 5000` +- [ ] Go forward: `node scripts/navigate_page.js --type forward` + +**Expected Output:** +Browser navigates through pages, back/forward works correctly. + +### Workflow: Multi-Tab Data Extraction + +Extract data from multiple pages simultaneously: + +- [ ] Open page 1: `node scripts/new_page.js --url https://example.com/data/item1` +- [ ] Take snapshot 1: `node scripts/take_snapshot.js --filePath item1.txt` +- [ ] Open page 2: `node scripts/new_page.js --url https://example.com/data/item2` +- [ ] Take snapshot 2: `node scripts/take_snapshot.js --filePath item2.txt` +- [ ] Open page 3: `node scripts/new_page.js --url https://example.com/data/item3` +- [ ] Take snapshot 3: `node scripts/take_snapshot.js --filePath item3.txt` +- [ ] Switch to page 0: `node scripts/select_page.js --pageIdx 0` +- [ ] Extract from page 0: `node scripts/evaluate_script.js --function "() => document.querySelector('.price').textContent"` +- [ ] Switch to page 1: `node scripts/select_page.js --pageIdx 1` +- [ ] Extract from page 1: `node scripts/evaluate_script.js --function "() => document.querySelector('.price').textContent"` + +**Expected Output:** +Data extracted from multiple pages, context switching successful. + +### Workflow: Responsive Design Testing + +Test page at different viewport sizes: + +- [ ] Open test page: `node scripts/new_page.js --url https://example.com` +- [ ] Desktop view: `node scripts/resize_page.js --width 1920 --height 1080` +- [ ] Take desktop screenshot: `node scripts/take_screenshot.js --fullPage true --filePath desktop.png` +- [ ] Tablet view: `node scripts/resize_page.js --width 768 --height 1024` +- [ ] Take tablet screenshot: `node scripts/take_screenshot.js --fullPage true --filePath tablet.png` +- [ ] Mobile view: `node scripts/resize_page.js --width 375 --height 667` +- [ ] Take mobile screenshot: `node scripts/take_screenshot.js --fullPage true --filePath mobile.png` + +**Expected Output:** +Screenshots captured at different viewport sizes for comparison. + +### Workflow: Clean Up Tabs + +Close unnecessary tabs while keeping important ones: + +- [ ] List all pages: `node scripts/list_pages.js` +- [ ] Identify indices to close (e.g., pages 2, 3, 4) +- [ ] Close page 4: `node scripts/close_page.js --pageIdx 4` +- [ ] Close page 3: `node scripts/close_page.js --pageIdx 3` +- [ ] Close page 2: `node scripts/close_page.js --pageIdx 2` +- [ ] Verify remaining: `node scripts/list_pages.js` +- [ ] Switch to desired page: `node scripts/select_page.js --pageIdx 0` + +**Note:** Close tabs in reverse order (highest index first) to avoid index shifting issues. + +**Expected Output:** +Unwanted tabs closed, important tabs remain active. + +## Common Patterns + +### Pattern: Safe Page Closing + +Always list pages before closing to avoid errors: + +```bash +# 1. Check what's open +node scripts/list_pages.js + +# 2. Close specific page (use actual index from list) +node scripts/close_page.js --pageIdx 2 + +# 3. Verify closure +node scripts/list_pages.js +``` + +### Pattern: Page Context Switching + +When working with multiple pages, always select before interacting: + +```bash +# 1. List to see indices +node scripts/list_pages.js + +# 2. Select target page +node scripts/select_page.js --pageIdx 1 + +# 3. Now interact with that page +node scripts/take_snapshot.js +node scripts/click.js --uid button_xyz +``` + +### Pattern: Reliable Navigation + +Use wait_for to ensure page loads before interaction: + +```bash +# 1. Navigate +node scripts/navigate_page.js --url https://example.com/login + +# 2. Wait for key element +node scripts/wait_for.js --text "Sign In" --timeout 10000 + +# 3. Now safe to interact +node scripts/take_snapshot.js +``` + +## Troubleshooting + +**Problem:** "Cannot close last page" error + +**Solution:** You must keep at least one page open. Open a new page before closing the last one. + +**Problem:** Page index out of range + +**Solution:** Always run `list_pages.js` first to see current indices. Indices shift when pages are closed. + +**Problem:** Navigation timeout + +**Solution:** Increase timeout value: `--timeout 60000` (60 seconds) for slow-loading pages. + +**Problem:** Wrong page context + +**Solution:** Use `list_pages.js` to check which page is selected (marked with "selected"). Use `select_page.js` to switch. diff --git a/skills/mcp-chrome-devtools/workflows/performance-analysis.md b/skills/mcp-chrome-devtools/workflows/performance-analysis.md new file mode 100644 index 0000000..a40b27e --- /dev/null +++ b/skills/mcp-chrome-devtools/workflows/performance-analysis.md @@ -0,0 +1,383 @@ +# Performance Analysis Workflows + +Advanced tools for JavaScript execution, performance tracing, device emulation, and automation utilities. + +## Tools in This Group + +### evaluate_script +Executes JavaScript code in the page context and returns JSON-serializable results. + +**Required:** `--function FUNCTION_STRING` +**Optional:** `--args JSON_ARRAY` + +```bash +# Simple extraction +node scripts/evaluate_script.js --function "() => document.title" + +# With parameters +node scripts/evaluate_script.js --function "(x, y) => x + y" --args '[5, 3]' + +# Complex extraction +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('h2')).map(h => h.textContent)" +``` + +### wait_for +Waits for specific text to appear on the page (for dynamic content loading). + +**Required:** `--text TEXT` +**Optional:** `--timeout MILLISECONDS` + +```bash +# Wait up to 10 seconds +node scripts/wait_for.js --text "Loading complete" --timeout 10000 + +# Wait for error message +node scripts/wait_for.js --text "Error" --timeout 5000 +``` + +### handle_dialog +Handles browser dialogs (alert, confirm, prompt). + +**Required:** `--action [accept|dismiss]` +**Optional:** `--promptText TEXT` + +```bash +# Accept alert +node scripts/handle_dialog.js --action accept + +# Dismiss confirm +node scripts/handle_dialog.js --action dismiss + +# Accept prompt with text +node scripts/handle_dialog.js --action accept --promptText "User input" +``` + +### emulate +Emulates network conditions and CPU throttling. + +**Optional:** `--networkConditions JSON`, `--cpuThrottlingRate NUMBER` + +```bash +# Slow 3G network +node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}' + +# 4x CPU throttling +node scripts/emulate.js --cpuThrottlingRate 4 + +# Both +node scripts/emulate.js --networkConditions '{"downloadThroughput":100000,"uploadThroughput":50000,"latency":100}' --cpuThrottlingRate 2 +``` + +### performance_start_trace +Starts recording performance trace for Core Web Vitals and performance insights. + +**Required:** `--reload [true|false]`, `--autoStop [true|false]` + +```bash +# Start tracing with page reload +node scripts/performance_start_trace.js --reload true --autoStop false + +# Start tracing without reload +node scripts/performance_start_trace.js --reload false --autoStop true +``` + +### performance_stop_trace +Stops the active performance trace and returns results. + +```bash +node scripts/performance_stop_trace.js +``` + +**Output includes:** +- Core Web Vitals: LCP, FID, CLS scores +- Performance insights and recommendations +- Insight set IDs for detailed analysis + +### performance_analyze_insight +Gets detailed information about a specific performance insight. + +**Required:** `--insightSetId SET_ID`, `--insightName INSIGHT_NAME` + +```bash +node scripts/performance_analyze_insight.js --insightSetId set_abc123 --insightName LargestContentfulPaint +``` + +## Workflows + +### Workflow: Extract Structured Data + +Scrape data from pages using JavaScript: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/products` +- [ ] Wait for load: `node scripts/wait_for.js --text "Products" --timeout 10000` +- [ ] Extract product titles: +```bash +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product-title')).map(el => el.textContent)" +``` +- [ ] Extract product prices: +```bash +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product-price')).map(el => el.textContent)" +``` +- [ ] Extract complete product data: +```bash +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.product')).map(p => ({title: p.querySelector('.title').textContent, price: p.querySelector('.price').textContent, id: p.dataset.id}))" +``` + +**Expected Output:** +Structured JSON data extracted from page, ready for processing. + +### Workflow: Comprehensive Performance Analysis + +Measure page performance and Core Web Vitals: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/landing` +- [ ] Start trace with reload: `node scripts/performance_start_trace.js --reload true --autoStop false` +- [ ] Wait for page load: `node scripts/wait_for.js --text "Get Started" --timeout 20000` +- [ ] Interact with page: `node scripts/click.js --uid button_cta` +- [ ] Wait for interaction: `node scripts/wait_for.js --text "Form" --timeout 5000` +- [ ] Stop trace: `node scripts/performance_stop_trace.js` +- [ ] Review output for: + - LCP (Largest Contentful Paint) - should be < 2.5s + - FID (First Input Delay) - should be < 100ms + - CLS (Cumulative Layout Shift) - should be < 0.1 + - Performance insights list +- [ ] Analyze specific insight: `node scripts/performance_analyze_insight.js --insightSetId --insightName LargestContentfulPaint` + +**Expected Output:** +Full performance profile, CWV scores, actionable insights for optimization. + +### Workflow: Test Under Network Constraints + +Simulate slow connections: + +- [ ] Set up slow 3G: `node scripts/emulate.js --networkConditions '{"downloadThroughput":50000,"uploadThroughput":50000,"latency":2000}'` +- [ ] Open page: `node scripts/new_page.js --url https://example.com --timeout 60000` +- [ ] Start performance trace: `node scripts/performance_start_trace.js --reload true --autoStop false` +- [ ] Wait for load: `node scripts/wait_for.js --text "Content" --timeout 60000` +- [ ] Stop trace: `node scripts/performance_stop_trace.js` +- [ ] Review load times: Check trace output for timing metrics +- [ ] Screenshot loaded state: `node scripts/take_screenshot.js --filePath slow_3g_loaded.png` +- [ ] Reset to fast network: `node scripts/emulate.js --networkConditions '{"downloadThroughput":10000000,"uploadThroughput":10000000,"latency":10}'` + +**Expected Output:** +Page behavior under slow network documented, performance impact measured. + +### Workflow: CPU Throttling Test + +Test performance on low-powered devices: + +- [ ] Apply 4x throttling: `node scripts/emulate.js --cpuThrottlingRate 4` +- [ ] Open app: `node scripts/new_page.js --url https://example.com/app` +- [ ] Start trace: `node scripts/performance_start_trace.js --reload true --autoStop false` +- [ ] Interact with heavy UI: `node scripts/click.js --uid button_render_chart` +- [ ] Wait for render: `node scripts/wait_for.js --text "Chart loaded" --timeout 30000` +- [ ] Stop trace: `node scripts/performance_stop_trace.js` +- [ ] Check JavaScript execution time in trace output +- [ ] Remove throttling: `node scripts/emulate.js --cpuThrottlingRate 1` +- [ ] Repeat test for comparison + +**Expected Output:** +Performance comparison between throttled and normal CPU, bottlenecks identified. + +### Workflow: Handle Dynamic Content Loading + +Work with lazy-loaded content: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/infinite-scroll` +- [ ] Wait for initial load: `node scripts/wait_for.js --text "Item 1" --timeout 5000` +- [ ] Scroll to bottom: `node scripts/evaluate_script.js --function "() => window.scrollTo(0, document.body.scrollHeight)"` +- [ ] Wait for more items: `node scripts/wait_for.js --text "Item 20" --timeout 10000` +- [ ] Take snapshot: `node scripts/take_snapshot.js` +- [ ] Scroll again: `node scripts/evaluate_script.js --function "() => window.scrollTo(0, document.body.scrollHeight)"` +- [ ] Wait for more: `node scripts/wait_for.js --text "Item 40" --timeout 10000` +- [ ] Extract all items: +```bash +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('.item')).length" +``` + +**Expected Output:** +All lazy-loaded content triggered and captured, full list extracted. + +### Workflow: Automated Dialog Handling + +Automate flows with browser dialogs: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/confirm-action` +- [ ] Click delete button: `node scripts/click.js --uid button_delete` +- [ ] Handle confirm dialog: `node scripts/handle_dialog.js --action accept` +- [ ] Wait for deletion: `node scripts/wait_for.js --text "Deleted successfully" --timeout 5000` +- [ ] Verify: `node scripts/take_snapshot.js` + +**For prompt dialog:** +```bash +# Click button that opens prompt +node scripts/click.js --uid button_rename + +# Enter new name and accept +node scripts/handle_dialog.js --action accept --promptText "New Name" + +# Verify change +node scripts/wait_for.js --text "New Name" --timeout 3000 +``` + +**Expected Output:** +Browser dialogs handled automatically, flow completes without manual intervention. + +### Workflow: Custom Metrics Collection + +Collect custom performance metrics: + +- [ ] Open page: `node scripts/new_page.js --url https://example.com/dashboard` +- [ ] Wait for load: `node scripts/wait_for.js --text "Dashboard" --timeout 10000` +- [ ] Get page load time: +```bash +node scripts/evaluate_script.js --function "() => performance.timing.loadEventEnd - performance.timing.navigationStart" +``` +- [ ] Get resource count: +```bash +node scripts/evaluate_script.js --function "() => performance.getEntriesByType('resource').length" +``` +- [ ] Get memory usage (if available): +```bash +node scripts/evaluate_script.js --function "() => performance.memory ? performance.memory.usedJSHeapSize : null" +``` +- [ ] Get paint timings: +```bash +node scripts/evaluate_script.js --function "() => performance.getEntriesByType('paint').map(p => ({name: p.name, time: p.startTime}))" +``` + +**Expected Output:** +Custom performance metrics collected via Performance API, specific to your needs. + +### Workflow: A/B Test Performance Comparison + +Compare performance across variants: + +- [ ] **Variant A:** + - [ ] Open: `node scripts/new_page.js --url https://example.com?variant=a` + - [ ] Trace: `node scripts/performance_start_trace.js --reload true --autoStop false` + - [ ] Wait: `node scripts/wait_for.js --text "Content" --timeout 15000` + - [ ] Stop: `node scripts/performance_stop_trace.js > variant_a_trace.txt` + - [ ] Screenshot: `node scripts/take_screenshot.js --filePath variant_a.png` +- [ ] **Variant B:** + - [ ] Navigate: `node scripts/navigate_page.js --url https://example.com?variant=b` + - [ ] Trace: `node scripts/performance_start_trace.js --reload true --autoStop false` + - [ ] Wait: `node scripts/wait_for.js --text "Content" --timeout 15000` + - [ ] Stop: `node scripts/performance_stop_trace.js > variant_b_trace.txt` + - [ ] Screenshot: `node scripts/take_screenshot.js --filePath variant_b.png` +- [ ] Compare CWV scores from both trace files + +**Expected Output:** +Performance metrics for both variants, data-driven comparison for optimization. + +## Common Patterns + +### Pattern: Safe Script Evaluation + +Always return JSON-serializable data: + +```bash +# Good: Returns string +node scripts/evaluate_script.js --function "() => document.title" + +# Good: Returns array of strings +node scripts/evaluate_script.js --function "() => Array.from(document.querySelectorAll('a')).map(a => a.href)" + +# Bad: Returns DOM nodes (not serializable) +# node scripts/evaluate_script.js --function "() => document.querySelectorAll('a')" +``` + +### Pattern: Wait Before Interaction + +Always wait for dynamic content: + +```bash +# 1. Trigger action +node scripts/click.js --uid button_load + +# 2. Wait for content +node scripts/wait_for.js --text "Loaded" --timeout 10000 + +# 3. Now safe to interact +node scripts/take_snapshot.js +``` + +### Pattern: Complete Performance Workflow + +Standard performance analysis sequence: + +```bash +# 1. Start tracing +node scripts/performance_start_trace.js --reload true --autoStop false + +# 2. Let page load completely +node scripts/wait_for.js --text "Ready" --timeout 20000 + +# 3. Stop tracing +node scripts/performance_stop_trace.js + +# 4. Analyze specific insights +node scripts/performance_analyze_insight.js --insightSetId --insightName +``` + +### Pattern: Emulation Reset + +Reset emulation to normal after testing: + +```bash +# 1. Test under constraints +node scripts/emulate.js --cpuThrottlingRate 4 + +# ... run tests ... + +# 2. Reset to normal +node scripts/emulate.js --cpuThrottlingRate 1 +``` + +## Troubleshooting + +**Problem:** evaluate_script returns null or error + +**Solution:** +- Ensure function returns JSON-serializable values (no DOM nodes, functions, or circular references) +- Use .map() to extract primitive values from DOM elements +- Check browser console for JavaScript errors: `list_console_messages.js --types error` + +**Problem:** wait_for times out + +**Solution:** +- Increase timeout: `--timeout 30000` (30 seconds) +- Verify text actually appears on page (check with `take_snapshot.js`) +- Text match is exact - check spelling and case +- Wait for network to finish if text appears after API call + +**Problem:** Dialog not handled + +**Solution:** +- Dialog must be already open when you call `handle_dialog.js` +- Trigger dialog first (e.g., click button), then immediately call `handle_dialog.js` +- Some "dialogs" are custom HTML, not browser dialogs - use `click.js` instead + +**Problem:** Performance trace shows unexpected results + +**Solution:** +- Ensure page fully loads before stopping trace +- Use `--reload true` for consistent initial page load measurement +- Clear browser cache if testing first-time load performance +- Disable browser extensions that might affect performance + +**Problem:** Emulation not working + +**Solution:** +- Emulation settings persist for the session +- To remove emulation, set back to normal values +- Network conditions JSON must be valid with all three properties +- CPU throttling rate of 1 = normal, higher = slower + +**Problem:** Script evaluation with args fails + +**Solution:** +- Args must be valid JSON array: `--args '[1, 2, 3]'` +- Function must accept the correct number of parameters +- Use single quotes around JSON, double quotes inside +- Example: `--function "(a, b) => a + b" --args '[5, 10]'`