chrometools-mcp 3.5.4 → 3.5.6
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 +25 -0
- package/COMPONENT_MAPPING_SPEC.md +1217 -1217
- package/README.md +13 -4
- package/SPEC-swagger-api-tools.md +3101 -3101
- package/browser/page-manager.js +7 -0
- package/index.js +199 -14
- package/models/DATEPICKER_IMPLEMENTATION.md +543 -543
- package/models/ModelRegistry.js +115 -115
- package/package.json +1 -1
- package/pom/apom-tree-converter.js +56 -1
- package/server/tool-definitions.js +10 -5
- package/server/tool-schemas.js +10 -5
- package/specs/SEGM-537-UNBLOCKERS_PROGRESS.md +94 -0
- package/specs/SEGM-537-UNBLOCKERS_SPEC.md +187 -0
- package/utils/actions/click-action.js +76 -8
- package/SPEC-IMPROVEMENTS.md +0 -173
- package/SPEC-pom-integration.md +0 -227
package/SPEC-pom-integration.md
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
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-интеграцией
|