chrometools-mcp 3.3.8 → 3.3.9
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 +40 -0
- package/README.md +129 -24
- package/SPEC-pom-integration.md +227 -0
- package/SPEC-swagger-api-tools.md +3101 -0
- package/index.js +503 -198
- package/package.json +2 -1
- package/pom/apom-tree-converter.js +5 -26
- package/recorder/page-object-generator.js +45 -1
- package/server/tool-definitions.js +54 -5
- package/server/tool-schemas.js +29 -0
- package/test-swagger-phase1.mjs +959 -0
- package/utils/api-generators/api-models-python.js +448 -0
- package/utils/api-generators/api-models-typescript.js +375 -0
- package/utils/code-generators/code-generator-base.js +111 -6
- package/utils/code-generators/playwright-python.js +74 -0
- package/utils/code-generators/playwright-typescript.js +69 -0
- package/utils/code-generators/pom-integrator.js +373 -0
- package/utils/code-generators/selenium-java.js +72 -0
- package/utils/code-generators/selenium-python.js +75 -0
- package/utils/hints-generator.js +114 -19
- package/utils/openapi/helpers.js +25 -0
- package/utils/openapi/parser.js +448 -0
- package/utils/openapi/ref-resolver.js +149 -0
- package/utils/openapi/type-mapper.js +174 -0
- package/nul +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.3.9] - 2026-02-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **AI Hints: modal content extraction** — Modals now show title, body text (200 chars), and action buttons
|
|
9
|
+
- Expanded selectors: mat-dialog-container, cdk-overlay-pane, `[class*="dialog"]`
|
|
10
|
+
- Topmost modal dedup for pages with multiple modals
|
|
11
|
+
- Actions extracted from `.modal-footer` / `[mat-dialog-actions]` (limit 5)
|
|
12
|
+
|
|
13
|
+
- **AI Hints: dropdown/menu item extraction** — Overlays now list actual option texts
|
|
14
|
+
- 11 overlay selectors: Angular CDK/Material, PrimeNG, Ant Design, custom `select-options`
|
|
15
|
+
- Menu vs dropdown auto-classification (role="menu", role="listbox", menuitem detection)
|
|
16
|
+
- Item text extraction (limit 10 items, shows total count)
|
|
17
|
+
- Deduplication of nested overlay elements
|
|
18
|
+
|
|
19
|
+
- **AI Hints: page heading in navigation** — `navigateTo` and `openBrowser` now show page heading
|
|
20
|
+
- Extracts h1 or `.page-title` / `[class*="page-title"]` fallback for SPAs
|
|
21
|
+
- Filters sr-only/visually-hidden elements (clip, 1px size, opacity)
|
|
22
|
+
- 500ms SPA render delay for Angular/React/Vue frameworks
|
|
23
|
+
|
|
24
|
+
- **Swagger/OpenAPI tools** — `loadSwagger` and `generateApiModels` (Phase 1)
|
|
25
|
+
- `loadSwagger`: Parse OpenAPI 2.0/3.x specs from URL or file (JSON/YAML)
|
|
26
|
+
- `generateApiModels`: Generate TypeScript interfaces or Python models (dataclass/pydantic/TypedDict)
|
|
27
|
+
- $ref resolution, enum generation, snake_case conversion for Python
|
|
28
|
+
- Supports filtering specific schemas
|
|
29
|
+
|
|
30
|
+
- **Page Object Model integration in exported tests** — `pageObjectMode` parameter
|
|
31
|
+
- `generate-integrated`: Generate POM + test using it
|
|
32
|
+
- `use-existing`: Generate test referencing existing POM file
|
|
33
|
+
- Works with `exportScenarioAsCode` and `appendScenarioToFile`
|
|
34
|
+
|
|
35
|
+
- **Synthetic drag mode** — `drag` tool now supports `mode: 'synthetic'`
|
|
36
|
+
- Better compatibility with JS libraries (frappe-gantt, jQuery UI, Sortable.js)
|
|
37
|
+
- Native mode (default) for standard HTML drag operations
|
|
38
|
+
|
|
39
|
+
- **analyzePage: framework click handler detection** — Detect addEventListener-based handlers
|
|
40
|
+
- APOM IDs returned from `smartFindElement` and `findElementsByText`
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- Swagger Phase 1 code review fixes (error handling, edge cases)
|
|
44
|
+
|
|
5
45
|
## [3.3.8] - 2026-02-03
|
|
6
46
|
|
|
7
47
|
### Added
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
## Why ChromeTools MCP?
|
|
8
8
|
|
|
9
9
|
**For AI Agents & Developers:**
|
|
10
|
-
- 🎯 **
|
|
10
|
+
- 🎯 **56 specialized tools** for browser automation - from simple clicks to Figma comparisons
|
|
11
11
|
- 🧠 **APOM (Agent Page Object Model)** - AI-friendly page representation (~8-10k tokens vs 15-25k for screenshots)
|
|
12
12
|
- 🔄 **Persistent browser sessions** - pages stay open between commands for iterative workflows
|
|
13
13
|
- ⚡ **Framework-aware** - handles React, Vue, Angular events and state updates automatically
|
|
@@ -219,7 +219,7 @@ The Chrome Extension is **required** for scenario recording and other advanced f
|
|
|
219
219
|
- [Installation](#installation)
|
|
220
220
|
- [Chrome Extension Setup](#chrome-extension-setup)
|
|
221
221
|
- [AI Optimization Features](#ai-optimization-features)- [Scenario Recorder](#scenario-recorder) - Visual UI-based recording with smart optimization
|
|
222
|
-
- [Available Tools](#available-tools) - **
|
|
222
|
+
- [Available Tools](#available-tools) - **48+ Tools Total**
|
|
223
223
|
- [AI-Powered Tools](#ai-powered-tools) - smartFindElement, analyzePage, getElementDetails, findElementsByText
|
|
224
224
|
- [Core Tools](#1-core-tools) - ping, openBrowser
|
|
225
225
|
- [Interaction Tools](#2-interaction-tools) - click, type, scrollTo, selectOption, selectFromGroup, drag, scrollHorizontal
|
|
@@ -227,6 +227,7 @@ The Chrome Extension is **required** for scenario recording and other advanced f
|
|
|
227
227
|
- [Advanced Tools](#4-advanced-tools) - executeScript, getConsoleLogs, listNetworkRequests, getNetworkRequest, filterNetworkRequests, hover, setStyles, setViewport, getViewport, navigateTo
|
|
228
228
|
- [Tab Management Tools](#5-tab-management-tools) - listTabs, switchTab
|
|
229
229
|
- [Recorder Tools](#7-recorder-tools) - enableRecorder, executeScenario, listScenarios, searchScenarios, getScenarioInfo, deleteScenario, exportScenarioAsCode, appendScenarioToFile, generatePageObject
|
|
230
|
+
- [API / Swagger Tools](#8-api--swagger-tools) - loadSwagger, generateApiModels
|
|
230
231
|
- [Typical Workflow Example](#typical-workflow-example)
|
|
231
232
|
- [Tool Usage Tips](#tool-usage-tips)
|
|
232
233
|
- [Configuration](#configuration)
|
|
@@ -260,7 +261,7 @@ AI: smartFindElement("login button")
|
|
|
260
261
|
|
|
261
262
|
1. **`analyzePage`** - 🔥 **USE FREQUENTLY** - Get current page state after loads, clicks, submissions (cached, use refresh:true)
|
|
262
263
|
2. **`smartFindElement`** - Natural language element search with multilingual support
|
|
263
|
-
3. **AI Hints** - Automatic context in all tools (page type,
|
|
264
|
+
3. **AI Hints** - Automatic context in all tools (page type, page heading, modal content, dropdown/menu items, suggestions)
|
|
264
265
|
4. **Text search** - `findElementsByText` for finding elements by visible text
|
|
265
266
|
|
|
266
267
|
**Performance:** 3-5x faster, 5-10x fewer requests
|
|
@@ -603,10 +604,16 @@ Drag element by mouse (click-hold-move-release). Simulates real mouse drag, not
|
|
|
603
604
|
- `direction` (required): 'up', 'down', 'left', 'right', 'up-left', 'up-right', 'down-left', 'down-right'
|
|
604
605
|
- `distance` (optional): Distance in pixels (default: 100)
|
|
605
606
|
- `duration` (optional): Drag duration in milliseconds (default: 500)
|
|
607
|
+
- `mode` (optional): 'native' (default) or 'synthetic'
|
|
608
|
+
- **'native'**: Uses Puppeteer mouse API - faster, works for most cases
|
|
609
|
+
- **'synthetic'**: Dispatches DOM events (pointerdown/pointermove/pointerup) - better compatibility with JS libraries (frappe-gantt, jQuery UI Draggable, custom drag handlers)
|
|
606
610
|
- **Use case**: Interactive maps (Google Maps, Leaflet), Gantt charts, SVG diagrams, canvas elements, sliders, drag-to-pan interfaces
|
|
607
|
-
- **How it works**:
|
|
611
|
+
- **How it works**:
|
|
612
|
+
- **Native mode**: Uses Puppeteer's mouse API (mousedown → mousemove → mouseup)
|
|
613
|
+
- **Synthetic mode**: Dispatches PointerEvent/MouseEvent on element with intermediate pointermove events during drag
|
|
614
|
+
- **When to use synthetic mode**: If native drag doesn't trigger JS library event handlers (e.g., frappe-gantt, jQuery UI, React DnD)
|
|
608
615
|
- **NOT for**: Standard overflow scrollbars (use `scrollTo` or `scrollHorizontal` instead)
|
|
609
|
-
- **Returns**: Start/end mouse positions and
|
|
616
|
+
- **Returns**: Start/end mouse positions, drag delta, and mode used
|
|
610
617
|
|
|
611
618
|
#### scrollHorizontal
|
|
612
619
|
Scroll element horizontally (for tables, carousels, wide content).
|
|
@@ -1118,17 +1125,24 @@ Delete a scenario and its associated secrets. Searches all projects to find the
|
|
|
1118
1125
|
- `language` (required): Target framework - `"playwright-typescript"`, `"playwright-python"`, `"selenium-python"`, `"selenium-java"`
|
|
1119
1126
|
- `cleanSelectors` (optional): Remove unstable CSS classes (default: true)
|
|
1120
1127
|
- `includeComments` (optional): Include descriptive comments (default: true)
|
|
1121
|
-
- `generatePageObject` (optional): Also generate Page Object class for the page (default: false)
|
|
1128
|
+
- `generatePageObject` (optional): Also generate Page Object class for the page (default: false). Legacy - use `pageObjectMode` instead.
|
|
1122
1129
|
- `pageObjectClassName` (optional): Custom Page Object class name (auto-generated if not provided)
|
|
1130
|
+
- `pageObjectMode` (optional): POM integration mode:
|
|
1131
|
+
- `"none"` (default) - no Page Object
|
|
1132
|
+
- `"generate"` - generate separate POM file (same as `generatePageObject: true`)
|
|
1133
|
+
- `"generate-integrated"` - generate POM + test that **uses** POM methods (imports, instantiates, calls POM methods)
|
|
1134
|
+
- `"use-existing"` - generate test that uses an **existing** POM file (requires `pageObjectFile`)
|
|
1135
|
+
- `pageObjectFile` (optional): Path to existing POM file (required for `"use-existing"` mode)
|
|
1123
1136
|
|
|
1124
|
-
- **Use case**: Create new test files from recorded scenarios with optional Page
|
|
1137
|
+
- **Use case**: Create new test files from recorded scenarios with optional Page Object integration
|
|
1125
1138
|
|
|
1126
1139
|
- **Returns**: JSON with:
|
|
1127
1140
|
- `action`: `"create_new_file"`
|
|
1128
1141
|
- `suggestedFileName`: Suggested test filename
|
|
1129
1142
|
- `testCode`: Full test code with imports
|
|
1130
1143
|
- `instruction`: Instructions for Claude Code
|
|
1131
|
-
- `pageObject` (if
|
|
1144
|
+
- `pageObject` (if POM generated): Page Object code and metadata
|
|
1145
|
+
- `pomIntegration` (if POM integrated): `{ className, mode }` info
|
|
1132
1146
|
|
|
1133
1147
|
- **Example 1 - Test only**:
|
|
1134
1148
|
```javascript
|
|
@@ -1147,29 +1161,46 @@ Delete a scenario and its associated secrets. Searches all projects to find the
|
|
|
1147
1161
|
}
|
|
1148
1162
|
```
|
|
1149
1163
|
|
|
1150
|
-
- **Example 2 - Test + Page Object
|
|
1164
|
+
- **Example 2 - Test + separate Page Object** (legacy):
|
|
1151
1165
|
```javascript
|
|
1152
|
-
// Export with Page Object class
|
|
1153
1166
|
exportScenarioAsCode({
|
|
1154
1167
|
scenarioName: "login_test",
|
|
1155
1168
|
language: "playwright-typescript",
|
|
1156
1169
|
generatePageObject: true,
|
|
1157
1170
|
pageObjectClassName: "LoginPage"
|
|
1158
1171
|
})
|
|
1172
|
+
```
|
|
1159
1173
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
"
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1174
|
+
- **Example 3 - Test + integrated Page Object** (recommended):
|
|
1175
|
+
```javascript
|
|
1176
|
+
// Generate POM and test that USES POM methods (not raw selectors)
|
|
1177
|
+
exportScenarioAsCode({
|
|
1178
|
+
scenarioName: "login_test",
|
|
1179
|
+
language: "playwright-typescript",
|
|
1180
|
+
pageObjectMode: "generate-integrated",
|
|
1181
|
+
pageObjectClassName: "LoginPage"
|
|
1182
|
+
})
|
|
1183
|
+
|
|
1184
|
+
// Returns test code using POM:
|
|
1185
|
+
// import { LoginPage } from './LoginPage';
|
|
1186
|
+
// test('login_test', async ({ page }) => {
|
|
1187
|
+
// const loginPage = new LoginPage(page);
|
|
1188
|
+
// await loginPage.goto();
|
|
1189
|
+
// await loginPage.fillUsername('admin');
|
|
1190
|
+
// await loginPage.clickLoginBtn();
|
|
1191
|
+
// });
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
- **Example 4 - Test using existing POM file**:
|
|
1195
|
+
```javascript
|
|
1196
|
+
// Use pre-existing Page Object file
|
|
1197
|
+
exportScenarioAsCode({
|
|
1198
|
+
scenarioName: "login_test",
|
|
1199
|
+
language: "playwright-typescript",
|
|
1200
|
+
pageObjectMode: "use-existing",
|
|
1201
|
+
pageObjectFile: "./pages/LoginPage.ts"
|
|
1202
|
+
})
|
|
1203
|
+
// Test will import and use methods from the existing LoginPage
|
|
1173
1204
|
```
|
|
1174
1205
|
|
|
1175
1206
|
- **Selector Cleaning**: Automatically removes unstable patterns:
|
|
@@ -1191,8 +1222,10 @@ Append recorded scenario as test code to an **EXISTING** test file. Automaticall
|
|
|
1191
1222
|
- `referenceTestName` (optional): Reference test name for 'before'/'after' insertion
|
|
1192
1223
|
- `cleanSelectors` (optional): Remove unstable CSS classes (default: true)
|
|
1193
1224
|
- `includeComments` (optional): Include descriptive comments (default: true)
|
|
1194
|
-
- `generatePageObject` (optional): Also generate Page Object class for the page (default: false)
|
|
1225
|
+
- `generatePageObject` (optional): Also generate Page Object class for the page (default: false). Legacy - use `pageObjectMode` instead.
|
|
1195
1226
|
- `pageObjectClassName` (optional): Custom Page Object class name (auto-generated if not provided)
|
|
1227
|
+
- `pageObjectMode` (optional): POM integration mode - `"none"`, `"generate"`, `"generate-integrated"`, `"use-existing"` (see exportScenarioAsCode for details)
|
|
1228
|
+
- `pageObjectFile` (optional): Path to existing POM file (required for `"use-existing"` mode)
|
|
1196
1229
|
|
|
1197
1230
|
- **Use case**: Add tests to existing test files without overwriting current tests
|
|
1198
1231
|
|
|
@@ -1325,6 +1358,78 @@ Append recorded scenario as test code to an **EXISTING** test file. Automaticall
|
|
|
1325
1358
|
- `selenium-python`: Selenium with Python (WebDriver, explicit waits, By locators)
|
|
1326
1359
|
- `selenium-java`: Selenium with Java (WebDriver, Page Factory compatible)
|
|
1327
1360
|
|
|
1361
|
+
### 8. API / Swagger Tools
|
|
1362
|
+
|
|
1363
|
+
Tools for loading OpenAPI/Swagger specs and generating typed API models.
|
|
1364
|
+
|
|
1365
|
+
#### `loadSwagger`
|
|
1366
|
+
|
|
1367
|
+
Parse an OpenAPI 2.0 (Swagger) or 3.x spec and return a structured summary of endpoints, schemas, and auth.
|
|
1368
|
+
|
|
1369
|
+
| Parameter | Type | Required | Description |
|
|
1370
|
+
|-----------|------|----------|-------------|
|
|
1371
|
+
| `source` | string | Yes | URL (`https://...`) or local file path to `swagger.json` / `openapi.yaml` |
|
|
1372
|
+
| `format` | `'auto'` \| `'json'` \| `'yaml'` | No | Parse format (default: `auto` — detects from content) |
|
|
1373
|
+
|
|
1374
|
+
**Response includes:**
|
|
1375
|
+
- API title, version, base URL
|
|
1376
|
+
- All endpoints with method, path, operationId, parameters, request body, responses
|
|
1377
|
+
- Schema summaries (property names, types, enums)
|
|
1378
|
+
- Auth schemes (Bearer, API key, OAuth2)
|
|
1379
|
+
|
|
1380
|
+
```javascript
|
|
1381
|
+
// Load from URL
|
|
1382
|
+
loadSwagger({ source: "https://petstore.swagger.io/v2/swagger.json" })
|
|
1383
|
+
|
|
1384
|
+
// Load from local file
|
|
1385
|
+
loadSwagger({ source: "/path/to/openapi.yaml" })
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
#### `generateApiModels`
|
|
1389
|
+
|
|
1390
|
+
Generate TypeScript interfaces or Python dataclasses/pydantic models from an OpenAPI spec.
|
|
1391
|
+
|
|
1392
|
+
| Parameter | Type | Required | Description |
|
|
1393
|
+
|-----------|------|----------|-------------|
|
|
1394
|
+
| `source` | string | Yes | URL or file path to spec |
|
|
1395
|
+
| `language` | `'typescript'` \| `'python'` | Yes | Target language |
|
|
1396
|
+
| `format` | `'auto'` \| `'json'` \| `'yaml'` | No | Parse format (default: `auto`) |
|
|
1397
|
+
| `style` | `'interface'` \| `'type'` | No | TypeScript style (default: `interface`) |
|
|
1398
|
+
| `pythonStyle` | `'dataclass'` \| `'pydantic'` \| `'typeddict'` | No | Python style (default: `dataclass`) |
|
|
1399
|
+
| `includeEnums` | boolean | No | Generate enum types (default: `true`) |
|
|
1400
|
+
| `schemas` | string[] | No | Filter to specific schema names |
|
|
1401
|
+
|
|
1402
|
+
**Features:**
|
|
1403
|
+
- Topological sort ensures correct declaration order
|
|
1404
|
+
- Enum deduplication (property enums reuse top-level enums)
|
|
1405
|
+
- `allOf` → extends/inheritance, `oneOf`/`anyOf` → union types
|
|
1406
|
+
- Circular reference detection with forward references
|
|
1407
|
+
- Swagger 2.0 automatically normalized to OpenAPI 3.x
|
|
1408
|
+
|
|
1409
|
+
```javascript
|
|
1410
|
+
// Generate TypeScript interfaces
|
|
1411
|
+
generateApiModels({
|
|
1412
|
+
source: "https://petstore.swagger.io/v2/swagger.json",
|
|
1413
|
+
language: "typescript"
|
|
1414
|
+
})
|
|
1415
|
+
// Returns: { code: "export interface Pet { ... }", suggestedFileName: "pet-store-api.models.ts" }
|
|
1416
|
+
|
|
1417
|
+
// Generate Python pydantic models
|
|
1418
|
+
generateApiModels({
|
|
1419
|
+
source: "/path/to/openapi.yaml",
|
|
1420
|
+
language: "python",
|
|
1421
|
+
pythonStyle: "pydantic"
|
|
1422
|
+
})
|
|
1423
|
+
// Returns: { code: "class Pet(BaseModel): ...", suggestedFileName: "pet_store_api_models.py" }
|
|
1424
|
+
|
|
1425
|
+
// Generate only specific schemas
|
|
1426
|
+
generateApiModels({
|
|
1427
|
+
source: "https://api.example.com/openapi.json",
|
|
1428
|
+
language: "typescript",
|
|
1429
|
+
schemas: ["User", "Order"]
|
|
1430
|
+
})
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1328
1433
|
---
|
|
1329
1434
|
|
|
1330
1435
|
## Typical Workflow Example
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Спецификация: Интеграция Page Object Model в экспортируемые тесты
|
|
2
|
+
|
|
3
|
+
## Контекст
|
|
4
|
+
|
|
5
|
+
QA-автоматизаторы жалуются, что тесты, экспортируемые через `exportScenarioAsCode` / `appendScenarioToFile`, **не используют Page Object**. Даже при `generatePageObject: true` генерируются два несвязанных файла — тест с raw-селекторами и POM-класс отдельно.
|
|
6
|
+
|
|
7
|
+
**Сейчас** (raw-селекторы):
|
|
8
|
+
```typescript
|
|
9
|
+
test('login', async ({ page }) => {
|
|
10
|
+
await page.goto('https://example.com/login');
|
|
11
|
+
await page.locator('#username').fill('admin');
|
|
12
|
+
await page.locator('#password').fill('secret');
|
|
13
|
+
await page.locator('#login-btn').click();
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Нужно** (POM-интеграция):
|
|
18
|
+
```typescript
|
|
19
|
+
import { LoginPage } from './LoginPage';
|
|
20
|
+
|
|
21
|
+
test('login', async ({ page }) => {
|
|
22
|
+
const loginPage = new LoginPage(page);
|
|
23
|
+
await loginPage.goto();
|
|
24
|
+
await loginPage.fillUsername('admin');
|
|
25
|
+
await loginPage.fillPassword('secret');
|
|
26
|
+
await loginPage.clickLoginBtn();
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Подход
|
|
31
|
+
|
|
32
|
+
Добавить новый параметр `pageObjectMode` к тулам экспорта. Два сценария:
|
|
33
|
+
|
|
34
|
+
1. **`generate-integrated`** — сгенерировать POM + тест, который его использует
|
|
35
|
+
2. **`use-existing`** — прочитать существующий POM-файл, сгенерировать тест, который его использует
|
|
36
|
+
|
|
37
|
+
Ключевой механизм — **selector matching**: сопоставление селекторов из записанного сценария с локаторами POM-элементов.
|
|
38
|
+
|
|
39
|
+
## Изменения по файлам
|
|
40
|
+
|
|
41
|
+
### 1. Новый файл: `utils/code-generators/pom-integrator.js`
|
|
42
|
+
|
|
43
|
+
Модуль связки POM с экшнами сценария:
|
|
44
|
+
|
|
45
|
+
- **`matchActionToPomElement(actionSelector, pomElements)`** — сопоставляет селектор экшна с элементом POM:
|
|
46
|
+
1. Exact match (`#username` === `#username`)
|
|
47
|
+
2. Normalized match (strip tag prefix: `input#username` → `#username`)
|
|
48
|
+
3. Key-based match (извлечь id/name/data-testid и сравнить значения)
|
|
49
|
+
4. Не найдено → null (fallback на raw-селектор)
|
|
50
|
+
|
|
51
|
+
- **`parsePomFile(fileContent, framework)`** — парсит существующий POM-файл regex'ами, возвращает `{ className, elements: [{name, selector, methodName, methodType}] }`:
|
|
52
|
+
- Playwright TS: ищет `this.X = page.locator('...')` и `async fillX(` / `async clickX(`
|
|
53
|
+
- Playwright Python: ищет `self.X = page.locator('...')` и `def fill_X(` / `def click_X(`
|
|
54
|
+
- Selenium Python: ищет `X = (By.CSS_SELECTOR, '...')` и `def fill_X(` / `def click_X(`
|
|
55
|
+
- Selenium Java: ищет `By X = By.cssSelector("...")` и `void fillX(` / `void clickX(`
|
|
56
|
+
|
|
57
|
+
### 2. Изменить: `recorder/page-object-generator.js`
|
|
58
|
+
|
|
59
|
+
Добавить в return `generatePageObject()` поле **`elements`** — массив структурированных метаданных:
|
|
60
|
+
```js
|
|
61
|
+
elements: uniqueElements.map(el => ({
|
|
62
|
+
name: sanitizeIdentifier(el.name, lang),
|
|
63
|
+
selector: el.selector,
|
|
64
|
+
tag: el.tag,
|
|
65
|
+
type: el.type,
|
|
66
|
+
methodName: generateMethodName(el, framework), // "fillUsername" / "clickSubmit"
|
|
67
|
+
methodType: getMethodType(el) // "fill" | "click" | "select"
|
|
68
|
+
}))
|
|
69
|
+
```
|
|
70
|
+
Добавить вспомогательные функции `generateMethodName()` и `getMethodType()` (логика уже есть в `generateActionMethods()`, нужно её вынести).
|
|
71
|
+
|
|
72
|
+
### 3. Изменить: `utils/code-generators/code-generator-base.js`
|
|
73
|
+
|
|
74
|
+
Добавить в конструктор опции `pomElements`, `pomClassName`, `pomImportPath`.
|
|
75
|
+
|
|
76
|
+
Добавить методы с дефолтными реализациями (no-op):
|
|
77
|
+
- `generatePomImports(className, importPath)` → `[]`
|
|
78
|
+
- `generatePomInstantiation(className)` → `[]`
|
|
79
|
+
- `generatePomAction(action, pomElement)` → `null` (значит fallback)
|
|
80
|
+
|
|
81
|
+
Модифицировать `generate()` и `generateTestOnly()`:
|
|
82
|
+
```js
|
|
83
|
+
// После generateImports(), если POM mode:
|
|
84
|
+
if (this.options.pomClassName) {
|
|
85
|
+
lines.push(...this.generatePomImports(this.options.pomClassName, this.options.pomImportPath));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// После generateTestHeader(), если POM mode:
|
|
89
|
+
if (this.options.pomClassName) {
|
|
90
|
+
lines.push(...this.generatePomInstantiation(this.options.pomClassName));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// В цикле экшнов:
|
|
94
|
+
for (const action of scenario.chain) {
|
|
95
|
+
let actionCode = null;
|
|
96
|
+
if (this.options.pomElements) {
|
|
97
|
+
const match = matchActionToPomElement(this.prepareSelector(action), this.options.pomElements);
|
|
98
|
+
if (match) {
|
|
99
|
+
actionCode = this.generatePomAction(action, match);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!actionCode) {
|
|
103
|
+
actionCode = this.generateAction(action);
|
|
104
|
+
}
|
|
105
|
+
if (actionCode?.length > 0) lines.push(...actionCode);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Специальная обработка `navigate` → если URL совпадает с POM entryUrl, заменить на `pomInstance.goto()`.
|
|
110
|
+
|
|
111
|
+
### 4. Изменить: `playwright-typescript.js`
|
|
112
|
+
|
|
113
|
+
Реализовать 3 POM-метода:
|
|
114
|
+
```js
|
|
115
|
+
generatePomImports(className, importPath) {
|
|
116
|
+
return [`import { ${className} } from '${importPath || './' + className}';`];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
generatePomInstantiation(className) {
|
|
120
|
+
const varName = className.charAt(0).toLowerCase() + className.slice(1);
|
|
121
|
+
return [this.indent(`const ${varName} = new ${className}(page);`), ''];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
generatePomAction(action, pomElement) {
|
|
125
|
+
const varName = this.options.pomClassName.charAt(0).toLowerCase() + this.options.pomClassName.slice(1);
|
|
126
|
+
// fill → await varName.fillUsername('text');
|
|
127
|
+
// click → await varName.clickSubmit();
|
|
128
|
+
// select → await varName.selectCountry('US');
|
|
129
|
+
// other → await varName.elementName.hover();
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 5. Изменить: `playwright-python.js`
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# Import: from login_page import LoginPage
|
|
137
|
+
# Instantiation: login_page = LoginPage(page)
|
|
138
|
+
# Fill: login_page.fill_username('text')
|
|
139
|
+
# Click: login_page.click_submit()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 6. Изменить: `selenium-python.js`
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Import: from login_page import LoginPage
|
|
146
|
+
# Instantiation: login_page = LoginPage(driver)
|
|
147
|
+
# Fill: login_page.fill_username('text')
|
|
148
|
+
# Click: login_page.click_submit()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 7. Изменить: `selenium-java.js`
|
|
152
|
+
|
|
153
|
+
```java
|
|
154
|
+
// Import: import pages.LoginPage;
|
|
155
|
+
// Instantiation: LoginPage loginPage = new LoginPage(driver);
|
|
156
|
+
// Fill: loginPage.fillUsername("text");
|
|
157
|
+
// Click: loginPage.clickSubmit();
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 8. Изменить: `server/tool-schemas.js`
|
|
161
|
+
|
|
162
|
+
Добавить к `ExportScenarioAsCodeSchema` и `AppendScenarioToFileSchema`:
|
|
163
|
+
```js
|
|
164
|
+
pageObjectMode: z.enum(['none', 'generate', 'generate-integrated', 'use-existing']).optional()
|
|
165
|
+
.describe("POM integration: 'none' (default), 'generate' (separate POM, current behavior), 'generate-integrated' (POM + test using it), 'use-existing' (test uses existing POM file)"),
|
|
166
|
+
pageObjectFile: z.string().optional()
|
|
167
|
+
.describe("Path to existing POM file (for 'use-existing' mode)"),
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 9. Изменить: `server/tool-definitions.js`
|
|
171
|
+
|
|
172
|
+
Обновить описания тулов `exportScenarioAsCode` и `appendScenarioToFile` — добавить `pageObjectMode` и `pageObjectFile` в `inputSchema.properties`.
|
|
173
|
+
|
|
174
|
+
### 10. Изменить: `index.js` (экспорт-хендлеры)
|
|
175
|
+
|
|
176
|
+
**`exportScenarioAsCode` (~строка 3321):**
|
|
177
|
+
- При `pageObjectMode === 'generate-integrated'`: сгенерировать POM, передать `pomElements`/`pomClassName` в генератор → получить тест с POM-вызовами
|
|
178
|
+
- При `pageObjectMode === 'use-existing'`: прочитать POM-файл через `FileAppender.readFile()`, распарсить через `parsePomFile()`, передать в генератор
|
|
179
|
+
- При `pageObjectMode === 'generate'` или `generatePageObject: true`: текущее поведение (обратная совместимость)
|
|
180
|
+
|
|
181
|
+
**`appendScenarioToFile` (~строка 3182):**
|
|
182
|
+
- Аналогичная логика для `generateTestOnly()`
|
|
183
|
+
|
|
184
|
+
### 11. Обновить: `README.md`
|
|
185
|
+
|
|
186
|
+
Документировать `pageObjectMode` и `pageObjectFile` параметры для обеих тул.
|
|
187
|
+
|
|
188
|
+
## Обратная совместимость
|
|
189
|
+
|
|
190
|
+
- `generatePageObject: true` (bool) — работает как раньше (maps to `pageObjectMode: 'generate'`)
|
|
191
|
+
- Новое поведение только при явном `pageObjectMode: 'generate-integrated'` или `'use-existing'`
|
|
192
|
+
- Fallback: если экшн не сматчился с POM-элементом — raw-селектор (как сейчас)
|
|
193
|
+
|
|
194
|
+
## Алгоритм Selector Matching
|
|
195
|
+
|
|
196
|
+
| Action selector | POM selector | Результат |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| `#username` | `#username` | Exact match |
|
|
199
|
+
| `input#username` | `#username` | Normalized (strip tag) |
|
|
200
|
+
| `[name="email"]` | `[name="email"]` | Exact match |
|
|
201
|
+
| `input[name="email"]` | `[name="email"]` | Key match (name=email) |
|
|
202
|
+
| `.complex > path:nth(2)` | `#username` | No match → raw fallback |
|
|
203
|
+
|
|
204
|
+
## Порядок реализации
|
|
205
|
+
|
|
206
|
+
1. `page-object-generator.js` — добавить `elements` metadata + helper-функции
|
|
207
|
+
2. `pom-integrator.js` — создать (matching + parsing)
|
|
208
|
+
3. `code-generator-base.js` — POM-методы + модифицированный generate-цикл
|
|
209
|
+
4. `playwright-typescript.js` — имплементация POM-методов (reference)
|
|
210
|
+
5. `playwright-python.js` — имплементация POM-методов
|
|
211
|
+
6. `selenium-python.js` — имплементация POM-методов
|
|
212
|
+
7. `selenium-java.js` — имплементация POM-методов
|
|
213
|
+
8. `tool-schemas.js` — новые параметры
|
|
214
|
+
9. `tool-definitions.js` — обновить descriptions + schema
|
|
215
|
+
10. `index.js` — оркестрация в хендлерах экспорта
|
|
216
|
+
11. `README.md` — документация
|
|
217
|
+
|
|
218
|
+
## Верификация
|
|
219
|
+
|
|
220
|
+
1. Записать сценарий на тестовой странице (например, Google Search)
|
|
221
|
+
2. Вызвать `exportScenarioAsCode` с `pageObjectMode: 'generate-integrated'`
|
|
222
|
+
3. Проверить что тест-файл содержит import POM-класса и вызывает его методы
|
|
223
|
+
4. Вызвать `generatePageObject`, сохранить файл, затем `exportScenarioAsCode` с `pageObjectMode: 'use-existing'`
|
|
224
|
+
5. Проверить что тест использует существующий POM
|
|
225
|
+
6. Проверить fallback: экшны без матча → raw-селекторы
|
|
226
|
+
7. Проверить все 4 фреймворка
|
|
227
|
+
8. Проверить `appendScenarioToFile` с POM-интеграцией
|