chrometools-mcp 1.7.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,117 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.8.2] - 2025-12-19
6
+
7
+ ### Fixed
8
+ - **Code Generator Bugs** - Fixed multiple issues in test code generators
9
+ - **Python generators**: Fixed comment syntax - now use `#` instead of `//`
10
+ - **Python generators**: Moved `import re` to top of file instead of inline
11
+ - **Java generator**: Fixed variable name conflicts - now uses unique names (`typeElement`, `hoverElement`, etc.) instead of reusing `element`
12
+ - **Java generator**: Added missing imports (`JavascriptExecutor`, `Select`)
13
+ - **All generators**: Implemented language-specific comment generation via `generateComment()` method
14
+ - Location: `utils/code-generators/code-generator-base.js`, `playwright-python.js`, `selenium-python.js`, `selenium-java.js`
15
+
16
+ ## [1.8.1] - 2025-12-19
17
+
18
+ ### Added
19
+ - **Smart Project Directory Detection** - Scenarios now automatically save to the correct project directory
20
+ - Auto-detection cascade: `CLAUDE_PROJECT_DIR` env var → `PROJECT_DIR` env var → Git root → current working directory
21
+ - Optional `directory` parameter on all recorder tools (`enableRecorder`, `executeScenario`, `listScenarios`, `searchScenarios`, `getScenarioInfo`, `deleteScenario`, `exportScenarioAsCode`)
22
+ - Session memory: once directory is set (explicitly or auto-detected), it's remembered for the entire MCP server session
23
+ - Solves issue where scenarios were saved to unpredictable locations based on where MCP process was launched
24
+ - Location: `utils/project-detector.js`, `index.js:97-115`
25
+
26
+ ### Changed
27
+ - **All recorder storage functions now accept `baseDir` parameter** - Breaking change for direct API usage
28
+ - Updated: `saveScenario()`, `loadScenario()`, `listScenarios()`, `searchScenarios()`, `deleteScenario()`, `loadIndex()`, and all other storage functions
29
+ - MCP tool users: no breaking changes, just new optional `directory` parameter
30
+ - Location: `recorder/scenario-storage.js`, `recorder/scenario-executor.js`, `recorder/recorder-script.js`
31
+
32
+ ## [1.8.0] - 2025-12-19
33
+
34
+ ### Added
35
+ - **Test Code Generation** - New MCP tool `exportScenarioAsCode` for generating executable test code from recorded scenarios
36
+ - Supports 4 test frameworks: Playwright (TypeScript/Python), Selenium (Python/Java)
37
+ - Automatic selector cleaning - removes unstable CSS classes (CSS Modules, styled-components, Emotion, hashed classes)
38
+ - Generates clean, readable test code with comments
39
+ - Smart selector stability analysis with pattern-based detection
40
+ - Fallback selector selection - chooses most stable selector from fallbacks
41
+ - Location: `utils/code-generators/`, `utils/selector-cleaner.js`
42
+
43
+ **Unstable patterns detected:**
44
+ - CSS Modules: `Button_primary__2x3yZ`
45
+ - Styled-components: `sc-AbCdEf-0`
46
+ - Emotion: `css-1a2b3c4d`
47
+ - Hash suffixes: `component_a1b2c3d`
48
+ - Random hashes: `_1a2b3c4d`
49
+
50
+ **Usage:**
51
+ ```javascript
52
+ exportScenarioAsCode('checkout', {
53
+ language: 'playwright-typescript',
54
+ cleanSelectors: true,
55
+ includeComments: true
56
+ })
57
+ ```
58
+
59
+ ## [1.7.4] - 2025-12-19
60
+
61
+ ### Changed
62
+ - **executeScenario auto-opens browser** - No longer throws error when no page is open
63
+ - Automatically opens browser at scenario's `entryUrl` if no page is currently open
64
+ - Eliminates need to manually call `openBrowser` before executing scenarios
65
+ - Improves user experience by treating browser opening as a side effect
66
+ - Falls back gracefully: shows error only if scenario has no `entryUrl`
67
+ - Location: `index.js:3417-3469`
68
+
69
+ ## [1.7.3] - 2025-12-19
70
+
71
+ ### Fixed
72
+ - **Fixed CSS selector generation crash** - `analyzePage` now handles attribute values with special characters
73
+ - Added `isSafeSelectorValue()` function to validate attribute values before using in selectors
74
+ - Filters out attributes containing problematic characters: `["'\\[]{}()]`
75
+ - Added try-catch blocks to prevent selector syntax errors
76
+ - Example: `button[data-counter="["b"]"]` (invalid) is now skipped
77
+ - Location: `element-finder-utils.js:302-360`
78
+
79
+ ### Improved
80
+ - **Recorder now skips hidden elements** - Prevents recording actions on invisible elements
81
+ - Added `isElementVisible()` function to check element visibility before recording
82
+ - Checks: offsetWidth/Height, display, visibility, opacity
83
+ - Applies to all event types: click, type, select, upload, hover, drag
84
+ - Prevents scenarios with duplicate/invisible element actions (e.g., Yandex search with hidden input)
85
+ - Console logs when skipping hidden elements for debugging
86
+ - Location: `recorder/recorder-script.js:1173-1188`
87
+
88
+ ## [1.7.2] - 2025-12-16
89
+
90
+ ### Added
91
+ - **Figma API Token Setup documentation** - Added comprehensive guide on how to obtain and configure Figma Personal Access Token
92
+ - Step-by-step instructions for getting token from Figma account settings
93
+ - Configuration examples for both Claude Desktop and Claude Code
94
+ - Environment variable setup (`FIGMA_TOKEN`)
95
+ - Note about alternative parameter-based token passing
96
+
97
+ ## [1.7.1] - 2025-12-15
98
+
99
+ ### Performance
100
+ - **Optimized tool descriptions** - Reduced token usage by 35-45% (~1,500-2,000 tokens)
101
+ - Shortened main tool descriptions from verbose to concise format
102
+ - Reduced parameter descriptions (e.g., "CSS selector for element to click" → "CSS selector")
103
+ - Standardized Figma tool parameters (7 tools optimized)
104
+ - Pattern-based reductions across all 41 tools
105
+ - Impact: Saves 1,500-2,000 tokens in every request to Claude
106
+ - Examples:
107
+ - `analyzePage`: 95 tokens → 30 tokens (68% reduction)
108
+ - `screenshot`: 75 tokens → 25 tokens (66% reduction)
109
+ - `listNetworkRequests`: 50 tokens → 20 tokens (60% reduction)
110
+
111
+ ### Changed
112
+ - All tool descriptions now use imperative voice and remove redundancy
113
+ - Figma tools: "Figma API token (optional if FIGMA_TOKEN env var is set)" → "API token (optional)"
114
+ - Common patterns: "Milliseconds to wait" → "Wait ms", "Maximum" → "Max", etc.
115
+
5
116
  ## [1.7.0] - 2025-12-14
6
117
 
7
118
  ### Removed
package/README.md CHANGED
@@ -14,7 +14,7 @@ MCP server for Chrome automation using Puppeteer with persistent browser session
14
14
  - [Interaction Tools](#2-interaction-tools) - click, type, scrollTo
15
15
  - [Inspection Tools](#3-inspection-tools) - getElement, getComputedCss, getBoxModel, screenshot
16
16
  - [Advanced Tools](#4-advanced-tools) - executeScript, getConsoleLogs, listNetworkRequests, getNetworkRequest, filterNetworkRequests, hover, setStyles, setViewport, getViewport, navigateTo
17
- - [Recorder Tools](#6-recorder-tools) ⭐ **NEW** - enableRecorder, executeScenario, listScenarios, searchScenarios, getScenarioInfo, deleteScenario
17
+ - [Recorder Tools](#6-recorder-tools) ⭐ **NEW** - enableRecorder, executeScenario, listScenarios, searchScenarios, getScenarioInfo, deleteScenario, exportScenarioAsCode
18
18
  - [Typical Workflow Example](#typical-workflow-example)
19
19
  - [Tool Usage Tips](#tool-usage-tips)
20
20
  - [Configuration](#configuration)
@@ -506,9 +506,32 @@ Extract detailed design specifications from Figma including text content, colors
506
506
 
507
507
  ### 6. Recorder Tools ⭐ NEW
508
508
 
509
+ **Directory Management**: All recorder tools support an optional `directory` parameter to specify where scenarios are stored. If not provided, the directory is auto-detected using this cascade:
510
+ 1. `CLAUDE_PROJECT_DIR` environment variable (set by Claude Code)
511
+ 2. `PROJECT_DIR` environment variable (custom)
512
+ 3. Git repository root (detected via `git rev-parse --show-toplevel`)
513
+ 4. Current working directory (fallback)
514
+
515
+ Once a directory is set (explicitly or auto-detected), it's remembered for the entire MCP server session.
516
+
517
+ **Example**:
518
+ ```javascript
519
+ // Let it auto-detect (recommended)
520
+ enableRecorder()
521
+
522
+ // Or specify explicitly
523
+ enableRecorder({ directory: "/path/to/project" })
524
+
525
+ // Later calls reuse the same directory automatically
526
+ executeScenario({ name: "test" }) // Uses remembered directory
527
+ ```
528
+
529
+ ---
530
+
509
531
  #### enableRecorder
510
532
  Inject visual recorder UI widget into the current page.
511
- - **Parameters**: None
533
+ - **Parameters**:
534
+ - `directory` (optional): Directory to save scenarios (auto-detected if not provided)
512
535
  - **Use case**: Start recording user interactions visually
513
536
  - **Returns**: Success status
514
537
  - **Features**:
@@ -524,6 +547,7 @@ Execute a previously recorded scenario by name.
524
547
  - `name` (required): Scenario name
525
548
  - `parameters` (optional): Runtime parameters (e.g., { email: "user@test.com" })
526
549
  - `executeDependencies` (optional): Execute dependencies before running scenario (default: true)
550
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
527
551
  - **Use case**: Run automated test scenarios
528
552
  - **Returns**: Execution result with success/failure status
529
553
  - **Features**:
@@ -541,7 +565,8 @@ Execute a previously recorded scenario by name.
541
565
 
542
566
  #### listScenarios
543
567
  Get all available scenarios with metadata.
544
- - **Parameters**: None
568
+ - **Parameters**:
569
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
545
570
  - **Use case**: Browse recorded scenarios
546
571
  - **Returns**: Array of scenarios with names, descriptions, tags, timestamps
547
572
 
@@ -550,6 +575,7 @@ Search scenarios by text or tags.
550
575
  - **Parameters**:
551
576
  - `text` (optional): Search in name/description
552
577
  - `tags` (optional): Array of tags to filter
578
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
553
579
  - **Use case**: Find specific scenarios
554
580
  - **Returns**: Matching scenarios
555
581
 
@@ -558,15 +584,59 @@ Get detailed information about a scenario.
558
584
  - **Parameters**:
559
585
  - `name` (required): Scenario name
560
586
  - `includeSecrets` (optional): Include secret values (default: false)
587
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
561
588
  - **Use case**: Inspect scenario actions and dependencies
562
589
  - **Returns**: Full scenario details (actions, metadata, dependencies)
563
590
 
564
591
  #### deleteScenario
565
592
  Delete a scenario and its associated secrets.
566
- - **Parameters**: `name` (required)
593
+ - **Parameters**:
594
+ - `name` (required): Scenario name
595
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
567
596
  - **Use case**: Clean up unused scenarios
568
597
  - **Returns**: Success confirmation
569
598
 
599
+ #### exportScenarioAsCode ⭐ **NEW**
600
+ Export recorded scenario as executable test code for various frameworks. Automatically cleans unstable selectors (CSS Modules, styled-components, Emotion).
601
+
602
+ - **Parameters**:
603
+ - `scenarioName` (required): Name of scenario to export
604
+ - `language` (required): Target framework - `"playwright-typescript"`, `"playwright-python"`, `"selenium-python"`, `"selenium-java"`
605
+ - `cleanSelectors` (optional): Remove unstable CSS classes (default: true)
606
+ - `includeComments` (optional): Include descriptive comments (default: true)
607
+ - `directory` (optional): Directory where scenarios are stored (auto-detected if not provided)
608
+
609
+ - **Use case**: Convert recorded scenarios into maintainable test code
610
+
611
+ - **Returns**: Generated test code as string
612
+
613
+ - **Example**:
614
+ ```javascript
615
+ // Export scenario as Playwright TypeScript
616
+ exportScenarioAsCode({
617
+ scenarioName: "checkout_flow",
618
+ language: "playwright-typescript",
619
+ cleanSelectors: true,
620
+ includeComments: true
621
+ })
622
+
623
+ // Returns clean test code:
624
+ // import { test, expect } from '@playwright/test';
625
+ //
626
+ // test('checkout_flow', async ({ page }) => {
627
+ // await page.goto('https://example.com');
628
+ // await page.locator('button[data-testid="add-to-cart"]').click();
629
+ // await expect(page).toHaveURL(/checkout/);
630
+ // });
631
+ ```
632
+
633
+ - **Selector Cleaning**: Automatically removes unstable patterns:
634
+ - CSS Modules: `Button_primary__2x3yZ` → removed
635
+ - Styled-components: `sc-AbCdEf-0` → removed
636
+ - Emotion: `css-1a2b3c4d` → removed
637
+ - Hash suffixes: `component_a1b2c3d` → removed
638
+ - Prefers stable selectors: `data-testid`, `role`, `aria-label`, semantic attributes
639
+
570
640
  ---
571
641
 
572
642
  ## Typical Workflow Example
@@ -667,6 +737,54 @@ If you don't need to see the browser window, you can use xvfb (virtual X server)
667
737
 
668
738
  This runs Chrome in GUI mode but on a virtual display (window is not visible).
669
739
 
740
+ ### Figma API Token Setup
741
+
742
+ To use Figma tools, you need to configure your Figma Personal Access Token.
743
+
744
+ **How to get your Figma token:**
745
+ 1. Go to your Figma account settings: https://www.figma.com/settings
746
+ 2. Scroll down to "Personal access tokens"
747
+ 3. Click "Create a new personal access token"
748
+ 4. Give it a name (e.g., "chrometools-mcp")
749
+ 5. Copy the generated token
750
+
751
+ **Add token to MCP configuration:**
752
+
753
+ **Claude Desktop** (`~/.claude/mcp_config.json` or `~/AppData/Roaming/Claude/mcp_config.json` on Windows):
754
+
755
+ ```json
756
+ {
757
+ "mcpServers": {
758
+ "chrometools": {
759
+ "command": "npx",
760
+ "args": ["-y", "chrometools-mcp"],
761
+ "env": {
762
+ "FIGMA_TOKEN": "your-figma-token-here"
763
+ }
764
+ }
765
+ }
766
+ }
767
+ ```
768
+
769
+ **Claude Code** (`~/.claude.json`):
770
+
771
+ ```json
772
+ {
773
+ "mcpServers": {
774
+ "chrometools": {
775
+ "type": "stdio",
776
+ "command": "npx",
777
+ "args": ["-y", "chrometools-mcp"],
778
+ "env": {
779
+ "FIGMA_TOKEN": "your-figma-token-here"
780
+ }
781
+ }
782
+ }
783
+ }
784
+ ```
785
+
786
+ **Note:** Alternatively, you can pass the token directly in each Figma tool call using the `figmaToken` parameter, but using the environment variable is more convenient.
787
+
670
788
  ---
671
789
 
672
790
  ## WSL Setup Guide
@@ -295,6 +295,16 @@ function scoreInputField(element, context, description) {
295
295
  return score;
296
296
  }
297
297
 
298
+ /**
299
+ * Check if attribute value is safe to use in CSS selector
300
+ * Returns false if value contains characters that could break selector syntax
301
+ */
302
+ function isSafeSelectorValue(value) {
303
+ if (!value || typeof value !== 'string') return false;
304
+ // Check for problematic characters: quotes, brackets, backslashes
305
+ return !/["'\\[\]{}()]/.test(value);
306
+ }
307
+
298
308
  /**
299
309
  * Generate unique CSS selector for an element
300
310
  */
@@ -320,23 +330,32 @@ function getUniqueSelectorInPage(element) {
320
330
  }
321
331
  }
322
332
 
323
- // Try name attribute
324
- if (element.name) {
333
+ // Try name attribute (only if value is safe)
334
+ if (element.name && isSafeSelectorValue(element.name)) {
325
335
  const selector = `${element.tagName.toLowerCase()}[name="${element.name}"]`;
326
- if (document.querySelectorAll(selector).length === 1) {
327
- return selector;
336
+ try {
337
+ if (document.querySelectorAll(selector).length === 1) {
338
+ return selector;
339
+ }
340
+ } catch (e) {
341
+ // Invalid selector, skip
328
342
  }
329
343
  }
330
344
 
331
- // Try data attributes
345
+ // Try data attributes (only if values are safe)
332
346
  const dataAttrs = Array.from(element.attributes)
333
- .filter(attr => attr.name.startsWith('data-'))
347
+ .filter(attr => attr.name.startsWith('data-') && isSafeSelectorValue(attr.value))
334
348
  .slice(0, 2);
335
349
 
336
350
  for (const attr of dataAttrs) {
337
351
  const selector = `${element.tagName.toLowerCase()}[${attr.name}="${attr.value}"]`;
338
- if (document.querySelectorAll(selector).length === 1) {
339
- return selector;
352
+ try {
353
+ if (document.querySelectorAll(selector).length === 1) {
354
+ return selector;
355
+ }
356
+ } catch (e) {
357
+ // Invalid selector, skip
358
+ continue;
340
359
  }
341
360
  }
342
361