pne-ui 4.3.0-rc.0 → 4.3.0-rc.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/README.md +640 -2
- package/cjs/component/search-ui/SearchUI.d.ts +52 -19
- package/cjs/component/search-ui/SearchUI.js +80 -8
- package/cjs/component/search-ui/SearchUI.js.map +1 -1
- package/cjs/component/table/AbstractTable.d.ts +5 -0
- package/cjs/component/table/AbstractTable.js +16 -2
- package/cjs/component/table/AbstractTable.js.map +1 -1
- package/cjs/component/table/PneTablePaginationActions.js +12 -18
- package/cjs/component/table/PneTablePaginationActions.js.map +1 -1
- package/cjs/component/table/PneTableViewSelector.d.ts +30 -0
- package/cjs/component/table/PneTableViewSelector.js +81 -0
- package/cjs/component/table/PneTableViewSelector.js.map +1 -0
- package/cjs/component/table/useDelayedLoading.d.ts +1 -1
- package/cjs/component/table/useDelayedLoading.js +48 -20
- package/cjs/component/table/useDelayedLoading.js.map +1 -1
- package/cjs/component/table/useTable.d.ts +4 -0
- package/cjs/component/table/useTable.js +116 -32
- package/cjs/component/table/useTable.js.map +1 -1
- package/cjs/exports/search.d.ts +1 -1
- package/cjs/exports/search.js.map +1 -1
- package/cjs/exports/table.d.ts +1 -0
- package/cjs/exports/table.js +3 -1
- package/cjs/exports/table.js.map +1 -1
- package/docs/selenium-locators.md +4 -636
- package/esm/component/search-ui/SearchUI.d.ts +52 -19
- package/esm/component/search-ui/SearchUI.js +81 -9
- package/esm/component/search-ui/SearchUI.js.map +1 -1
- package/esm/component/table/AbstractTable.d.ts +5 -0
- package/esm/component/table/AbstractTable.js +16 -2
- package/esm/component/table/AbstractTable.js.map +1 -1
- package/esm/component/table/PneTablePaginationActions.js +13 -19
- package/esm/component/table/PneTablePaginationActions.js.map +1 -1
- package/esm/component/table/PneTableViewSelector.d.ts +30 -0
- package/esm/component/table/PneTableViewSelector.js +77 -0
- package/esm/component/table/PneTableViewSelector.js.map +1 -0
- package/esm/component/table/useDelayedLoading.d.ts +1 -1
- package/esm/component/table/useDelayedLoading.js +49 -21
- package/esm/component/table/useDelayedLoading.js.map +1 -1
- package/esm/component/table/useTable.d.ts +4 -0
- package/esm/component/table/useTable.js +116 -32
- package/esm/component/table/useTable.js.map +1 -1
- package/esm/exports/search.d.ts +1 -1
- package/esm/exports/search.js.map +1 -1
- package/esm/exports/table.d.ts +1 -0
- package/esm/exports/table.js +1 -0
- package/esm/exports/table.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -152,8 +152,646 @@ required textbox/text buttons и ищутся по role/name внутри scoped
|
|
|
152
152
|
state. Не используйте MUI classes, SVG/path, DOM depth, array index, переведённый текст как технический ID или
|
|
153
153
|
сгенерированный `aria-controls` ID.
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
## Справочник Selenium-якорей `pne-ui`
|
|
156
|
+
|
|
157
|
+
Документ предназначен для тестировщиков, которые пишут Selenium-автотесты. Здесь перечислены готовые
|
|
158
|
+
стабильные якоря `PneTable`, `SearchUI`, `SearchUIFilters`, всех 31 типов критериев и вынесенных в portal
|
|
159
|
+
панелей. Искать нужный элемент по JSX, структуре MUI или случайным классам не требуется.
|
|
160
|
+
|
|
161
|
+
Примеры ниже используют CSS selectors, поддерживаемые обычным Selenium WebDriver. Это справочник публичного
|
|
162
|
+
DOM-контракта, а не руководство по реализации компонентов библиотеки.
|
|
163
|
+
|
|
164
|
+
### Быстрый старт
|
|
165
|
+
|
|
166
|
+
Тест всегда проходит три уровня:
|
|
167
|
+
|
|
168
|
+
1. Находит scope экземпляра компонента.
|
|
169
|
+
2. Внутри scope находит смысловой slot/action/control.
|
|
170
|
+
3. Читает состояние из native DOM или ARIA, а не из отдельной test-only копии.
|
|
171
|
+
|
|
172
|
+
Три служебных атрибута имеют разные назначения:
|
|
173
|
+
|
|
174
|
+
| Атрибут | Назначение |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `data-autotest` | Стабильное имя slot/action/control |
|
|
177
|
+
| `data-autotest-value` | Scope экземпляра или raw domain/enum ID |
|
|
178
|
+
| `data-autotest-criterion` | Raw `CriterionTypeEnum` владельца portal-контента |
|
|
179
|
+
|
|
180
|
+
Короткая запись, используемая дальше в документе:
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
slot/value
|
|
184
|
+
= [data-autotest="<slot>"][data-autotest-value="<value>"]
|
|
185
|
+
|
|
186
|
+
portal/scope + criterion
|
|
187
|
+
= [data-autotest="<portal>"][data-autotest-value="<scope>"][data-autotest-criterion="<criterion>"]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`<scope>` в примерах ниже — стабильное имя конкретного экземпляра компонента на странице, например `orders`.
|
|
191
|
+
У нескольких таблиц scopes обязаны различаться. SearchUI и связанная таблица результатов используют общий
|
|
192
|
+
scope.
|
|
193
|
+
|
|
194
|
+
`data-autotest-value` не является универсальным полем состояния. В зависимости от якоря это scope либо raw
|
|
195
|
+
domain/enum ID. Введённый текст и состояния `checked/disabled` Selenium читает из настоящего DOM-свойства или
|
|
196
|
+
ARIA.
|
|
197
|
+
|
|
198
|
+
#### Пример scoped lookup
|
|
199
|
+
|
|
200
|
+
```java
|
|
201
|
+
WebElement filters = driver.findElement(By.cssSelector(
|
|
202
|
+
"[data-autotest='search-filters'][data-autotest-value='orders']"
|
|
203
|
+
));
|
|
204
|
+
|
|
205
|
+
WebElement status = filters.findElement(By.cssSelector(
|
|
206
|
+
"[data-autotest='criterion'][data-autotest-value='STATUS']"
|
|
207
|
+
));
|
|
208
|
+
|
|
209
|
+
WebElement enabled = status.findElement(By.cssSelector(
|
|
210
|
+
"[data-autotest='criterion-option'][data-autotest-value='ENABLED']"
|
|
211
|
+
));
|
|
212
|
+
|
|
213
|
+
enabled.click();
|
|
214
|
+
assertEquals("true", enabled.getAttribute("aria-pressed"));
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Эти lookup-операции удобно инкапсулировать в Selenium Page/Component Object. Selenium штатно поддерживает
|
|
218
|
+
поиск от найденного `WebElement`, поэтому внутренний selector не обязан быть глобально уникальным на всей
|
|
219
|
+
странице.
|
|
220
|
+
|
|
221
|
+
### Как читать состояние
|
|
222
|
+
|
|
223
|
+
| Состояние | Источник истины в Selenium/DOM |
|
|
224
|
+
|---|---|
|
|
225
|
+
| Enabled/disabled native control | `element.isEnabled()`; native `disabled` присутствует только у disabled |
|
|
226
|
+
| Enabled/disabled MUI control с `role="combobox"` | `aria-disabled="true"` у disabled; у enabled атрибут отсутствует |
|
|
227
|
+
| Checkbox/radio/switch на native input | `element.isSelected()` или DOM property `checked` |
|
|
228
|
+
| Custom switch/checkbox | `aria-checked` |
|
|
229
|
+
| Toggle button | `aria-pressed` |
|
|
230
|
+
| Option | `aria-selected` |
|
|
231
|
+
| Открыт/закрыт trigger | `aria-expanded`; связь с popup — текущее `aria-controls` |
|
|
232
|
+
| Loading | `aria-busy` |
|
|
233
|
+
| Активная сортировка | `aria-sort="ascending|descending"` на semantic `<th>` |
|
|
234
|
+
| Текущая страница semantic Pagination | `aria-current="page"` |
|
|
235
|
+
| Значение input | DOM property `value` |
|
|
236
|
+
|
|
237
|
+
Не ожидайте `disabled="false"`: `disabled` является boolean HTML attribute. Если он присутствует, control
|
|
238
|
+
отключён независимо от текстового значения атрибута.
|
|
239
|
+
|
|
240
|
+
### `PneTable`
|
|
241
|
+
|
|
242
|
+
#### Scope экземпляра
|
|
243
|
+
|
|
244
|
+
```css
|
|
245
|
+
[data-autotest="table"][data-autotest-value="orders"]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`PneTable` может повторяться на одной странице, поэтому для нового page contract значение `<scope>` является
|
|
249
|
+
обязательной частью локатора и должно быть уникальным для каждой логической таблицы. Конкретное значение
|
|
250
|
+
задаёт интеграция страницы через `autoTestId`; оно должно быть зафиксировано в тестовых данных/Page Object.
|
|
251
|
+
Пример `orders` ниже иллюстративный. Не заменяйте scope заголовком, текущим переводом, порядковым номером или
|
|
252
|
+
именем WhiteLabel.
|
|
253
|
+
|
|
254
|
+
Технически legacy-страница ещё может отрендерить только `[data-autotest="table"]` без value. Такой selector
|
|
255
|
+
не различает несколько таблиц: для страницы, входящей в автоматизацию, отсутствие согласованного scope нужно
|
|
256
|
+
фиксировать как пробел page-level контракта.
|
|
257
|
+
|
|
258
|
+
Таблица результатов SearchUI получает тот же scope, что SearchUI:
|
|
259
|
+
|
|
260
|
+
```css
|
|
261
|
+
[data-autotest="table"][data-autotest-value="orders"]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### Внутренние элементы
|
|
265
|
+
|
|
266
|
+
| Элемент | Selector относительно table scope | Состояние |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| Верхняя пагинация | `[data-autotest="pagination"][data-autotest-value="top"]` | Native button `disabled`; `current-page` внутри |
|
|
269
|
+
| Нижняя пагинация | `[data-autotest="pagination"][data-autotest-value="bottom"]` | Native button `disabled`; `current-page` внутри |
|
|
270
|
+
| Пустой результат | `[data-autotest="empty-state"]` | Наличие существующей empty row |
|
|
271
|
+
| Загрузка | Semantic `table` | `aria-busy="true|false"` |
|
|
272
|
+
| Активная сортировка | `th[aria-sort="ascending"], th[aria-sort="descending"]` | Значение `aria-sort` |
|
|
273
|
+
|
|
274
|
+
Внутри каждого `pagination/top|bottom` уже существуют:
|
|
275
|
+
|
|
276
|
+
- `[data-autotest="first-page"]`, `[data-autotest="prev-page"]`, `[data-autotest="next-page"]` — actual native
|
|
277
|
+
buttons; доступность через `isEnabled()`;
|
|
278
|
+
- `[data-autotest="current-page"]` — отображаемый текущий диапазон/номер;
|
|
279
|
+
- `[data-autotest="page-sizes"][data-autotest-value="<current size>"]` — группа размеров и текущее raw value;
|
|
280
|
+
- `[data-autotest="page-size"][data-autotest-value="<raw size>"]` — конкретный вариант.
|
|
281
|
+
|
|
282
|
+
Отдельной last-page кнопки нет. Конец списка определяется disabled-состоянием `next-page`.
|
|
283
|
+
|
|
284
|
+
У библиотеки нет универсальных якорей business-строк и business-колонок: их identity определяется конкретной
|
|
285
|
+
страницей. Если странице нужны локаторы вида `row/<orderId>` или `cell/<columnKey>`, они должны быть описаны в
|
|
286
|
+
контракте этой страницы, а не угадываться по позиции строки или тексту ячейки.
|
|
287
|
+
|
|
288
|
+
### SearchUI/SearchUIFilters
|
|
289
|
+
|
|
290
|
+
На текущих продуктовых страницах обычно присутствует один SearchUI/SearchUIFilters. Его scope задаётся
|
|
291
|
+
страницей или наследуется из стабильного `settingsContextName`. Если в DOM окажутся два экземпляра, они будут
|
|
292
|
+
иметь разные scopes.
|
|
293
|
+
|
|
294
|
+
Не ожидайте общего DOM-wrapper вокруг SearchUI. Фильтры и результаты — отдельные roots с одним scope:
|
|
295
|
+
|
|
296
|
+
```css
|
|
297
|
+
[data-autotest="search-filters"][data-autotest-value="orders"]
|
|
298
|
+
[data-autotest="table"][data-autotest-value="orders"]
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Каждый критерий ищется внутри filter scope по raw enum:
|
|
302
|
+
|
|
303
|
+
```css
|
|
304
|
+
[data-autotest="criterion"][data-autotest-value="STATUS"]
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Общие actions
|
|
308
|
+
|
|
309
|
+
Selectors ниже относительны к `search-filters/<scope>`.
|
|
310
|
+
|
|
311
|
+
| Action | Selector | Состояние/примечание |
|
|
312
|
+
|---|---|---|
|
|
313
|
+
| Показать/скрыть фильтры | `[data-autotest="toggle-filters"]` | Native button, `aria-expanded`, `aria-controls` |
|
|
314
|
+
| Очистить всё | `[data-autotest="clear-all"]` | Условно присутствует |
|
|
315
|
+
| Запустить поиск/refresh | `[data-autotest="run-search"]` | Native `disabled`/`isEnabled()` |
|
|
316
|
+
| Шаблоны | `[data-autotest="templates"]` | Native button, `aria-expanded`, `aria-controls` |
|
|
317
|
+
| Добавить фильтр | `[role="combobox"][data-autotest="add-filter"]` | Кликать actual combobox; `aria-expanded` |
|
|
318
|
+
| Очистить критерий | `[data-autotest="clear-criterion"]` | Native button внутри criterion root |
|
|
319
|
+
| Удалить критерий | `[data-autotest="remove-criterion"]` | Отсутствует у non-removable predefined criterion |
|
|
320
|
+
|
|
321
|
+
`clear-all`, templates, add-filter и отдельные criterion actions могут отсутствовать из-за config или текущего
|
|
322
|
+
состояния. Это условный UI, а не нарушение locator contract.
|
|
323
|
+
|
|
324
|
+
Внутри `add-filter-options/<scope>` конкретный доступный критерий сейчас выбирается как `[role="option"]` по
|
|
325
|
+
computed accessible name в фиксированной locale. Отдельного raw `data-autotest-value=<CriterionTypeEnum>` у
|
|
326
|
+
этих options пока нет; это явно известное исключение из raw-ID контракта.
|
|
327
|
+
|
|
328
|
+
#### Общие portals
|
|
329
|
+
|
|
330
|
+
MUI popover/modal/listbox может находиться вне DOM-поддерева `search-filters`. Такие roots ищутся от document по
|
|
331
|
+
тому же owner scope:
|
|
332
|
+
|
|
333
|
+
```css
|
|
334
|
+
[data-autotest="templates-panel"][data-autotest-value="orders"]
|
|
335
|
+
[data-autotest="add-filter-options"][data-autotest-value="orders"]
|
|
336
|
+
[data-autotest="template-editor"][data-autotest-value="orders"]
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Внутри templates panel:
|
|
340
|
+
|
|
341
|
+
- строка: `[data-autotest="template-item"]`;
|
|
342
|
+
- применить конкретный шаблон: `button[data-autotest="select-template"][title="<template name>"]`;
|
|
343
|
+
- удалить: сначала найти строку выбранного шаблона, затем внутри неё
|
|
344
|
+
`button[data-autotest="remove-template"]`.
|
|
345
|
+
|
|
346
|
+
`template-editor/<scope>` является отдельным dialog portal, а не потомком `templates-panel`. Его close button:
|
|
347
|
+
`button[data-autotest="close-template-editor"]`.
|
|
348
|
+
|
|
349
|
+
Имя шаблона остаётся пользовательским значением/accessible name и не копируется в technical ID. Create,
|
|
350
|
+
Cancel и обычные поля формы ищутся внутри scoped dialog по native role/name.
|
|
351
|
+
|
|
352
|
+
#### Actions без отдельного `data-autotest`
|
|
353
|
+
|
|
354
|
+
Для нескольких стандартных dialog actions контрактом служат native button + computed accessible name внутри
|
|
355
|
+
уже найденного scoped dialog:
|
|
356
|
+
|
|
357
|
+
- Add filter: option нужного критерия внутри `add-filter-options/<scope>`;
|
|
358
|
+
- Template editor: Create, Cancel;
|
|
359
|
+
- Grouping: Save, Cancel;
|
|
360
|
+
- Multiget: Clear в selected column, Save, Cancel;
|
|
361
|
+
- Transaction Session Status: Close.
|
|
362
|
+
|
|
363
|
+
В Selenium 4 их можно находить без XPath по внутренней разметке:
|
|
364
|
+
|
|
365
|
+
```java
|
|
366
|
+
static WebElement byAccessibleName(SearchContext scope, String css, String expectedName) {
|
|
367
|
+
return scope.findElements(By.cssSelector(css)).stream()
|
|
368
|
+
.filter(element -> expectedName.equals(element.getAccessibleName()))
|
|
369
|
+
.findFirst()
|
|
370
|
+
.orElseThrow();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
WebElement save = byAccessibleName(dialog, "button, [role='button']", "Save");
|
|
374
|
+
WebElement status = byAccessibleName(addFilterListbox, "[role='option']", "Status");
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
`expectedName` берётся из фиксированной locale тестового сценария. Это явно перечисленные locale-aware actions;
|
|
378
|
+
raw IDs критериев, options и entities по переведённому тексту не ищутся.
|
|
379
|
+
|
|
380
|
+
Для portal конкретного критерия используются все три owner attributes:
|
|
381
|
+
|
|
382
|
+
```css
|
|
383
|
+
[data-autotest="criterion-project-currency-options"][data-autotest-value="orders"][data-autotest-criterion="PROJECT_CURRENCY"]
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Generated ID из `aria-controls` не хардкодируется; при необходимости он считывается у trigger после открытия
|
|
387
|
+
popup.
|
|
388
|
+
|
|
389
|
+
### Матрица всех 31 критериев
|
|
390
|
+
|
|
391
|
+
В таблице указан meaningful control, который должен быть ровно один внутри соответствующего
|
|
392
|
+
`criterion/<CriterionTypeEnum>` root.
|
|
393
|
+
|
|
394
|
+
| `CriterionTypeEnum` | Primary selector внутри criterion root | Family |
|
|
395
|
+
|---|---|---|
|
|
396
|
+
| `EXACT` | `input[data-autotest="criterion-input"]` | Exact input |
|
|
397
|
+
| `ORDERS_SEARCH` | `button[role="combobox"][data-autotest="criterion-label"]` | Orders input |
|
|
398
|
+
| `CURRENCY` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
399
|
+
| `CUSTOMER_LEVEL` | `[role="combobox"][data-autotest="criterion-customer-level"]` | Dependent select |
|
|
400
|
+
| `THREE_D` | `[role="button"][data-autotest="criterion-option"]` | Enum buttons |
|
|
401
|
+
| `STATUS` | `[role="button"][data-autotest="criterion-option"]` | Enum buttons |
|
|
402
|
+
| `MERCHANT` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
403
|
+
| `ENDPOINT` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
404
|
+
| `RESELLER` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
405
|
+
| `PROCESSOR` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
406
|
+
| `MANAGER` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
407
|
+
| `PROJECT` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
408
|
+
| `COMPANY` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
409
|
+
| `GATE` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
410
|
+
| `DEALER` | `button[data-autotest="criterion-multiget-trigger"]` | Multiget |
|
|
411
|
+
| `DATE_RANGE` | `[role="combobox"][data-autotest="criterion-range-spec"]` | Date |
|
|
412
|
+
| `DATE_RANGE_ORDERS` | `[role="combobox"][data-autotest="criterion-order-date-type"]` | Date |
|
|
413
|
+
| `PROJECT_CURRENCY` | `[role="combobox"][data-autotest="criterion-project-currency"]` | Dependent select |
|
|
414
|
+
| `CARD_TYPES` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
415
|
+
| `COUNTRIES` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
416
|
+
| `GROUPING` | `button[data-autotest="criterion-grouping-groups"]` | Grouping dialog |
|
|
417
|
+
| `TRANSACTION_TYPES` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
418
|
+
| `TRANSACTION_STATUS` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
419
|
+
| `RECURRENCE_TYPE` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
420
|
+
| `RECURRENCE_STATUS` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
421
|
+
| `MFO_CONFIGURATION_TYPE` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
422
|
+
| `MARKER_TYPE` | `input[role="combobox"][data-autotest="criterion-collection"]` | Collection |
|
|
423
|
+
| `MARKER_STATUS` | `[role="button"][data-autotest="criterion-option"]` | Enum buttons |
|
|
424
|
+
| `PROCESSOR_LOG_ENTRY_TYPE` | `[role="combobox"][data-autotest="criterion-processor-log-entry-type"]` | Single select |
|
|
425
|
+
| `ERROR_CODE` | `input[role="combobox"][data-autotest="criterion-error-code"]` | Async autocomplete |
|
|
426
|
+
| `TRANSACTION_SESSION_STATUS` | `button[data-autotest="criterion-transaction-session-status"]` | Session dialog |
|
|
427
|
+
|
|
428
|
+
Ниже описаны controls и panels каждой family.
|
|
429
|
+
|
|
430
|
+
### `EXACT`
|
|
431
|
+
|
|
432
|
+
Внутри `criterion/EXACT`:
|
|
433
|
+
|
|
434
|
+
| Элемент | Contract |
|
|
435
|
+
|---|---|
|
|
436
|
+
| Native input | `input[data-autotest="criterion-input"]`; текст читается из `.value` |
|
|
437
|
+
| Выбранное поле | `[role="combobox"][data-autotest="criterion-label"][data-autotest-value="<raw ExactCriterionSearchLabelEnum>"]` |
|
|
438
|
+
| Portal listbox | `criterion-label-options/<scope>` + `data-autotest-criterion="EXACT"` |
|
|
439
|
+
| Option | `[role="option"][data-autotest="criterion-label-option"][data-autotest-value="<raw label>"]` |
|
|
440
|
+
|
|
441
|
+
Selection option читается из `aria-selected`.
|
|
442
|
+
|
|
443
|
+
Raw values `ExactCriterionSearchLabelEnum`:
|
|
444
|
+
|
|
445
|
+
`ALL`, `NAME`, `DESCRIPTION`, `TAGS`, `IDENTIFIER`, `BEAN`, `END_POINT_GROUP_ID`, `ID`, `AMOUNT`,
|
|
446
|
+
`FINAL_CLEARING_DATE`, `MANAGER`, `SERIAL_NUMBER`, `INVOICE`, `CARD_FROM_RECURRENCE_NUMBER`, `FIRST_6`,
|
|
447
|
+
`LAST_4`, `FIRST_6_LAST_4`, `ORDER_IDENTIFIER`, `EMAIL`, `LOGIN`, `PRINCIPAL_DEALER`, `PRINCIPAL_MANAGER`,
|
|
448
|
+
`PRINCIPAL_MERCHANT`, `PRINCIPAL_RESELLER`, `PRINCIPAL_SUPERIOR`, `END_POINT_IDENTIFIER`,
|
|
449
|
+
`END_POINT_GROUP_IDENTIFIER`.
|
|
450
|
+
|
|
451
|
+
### `ORDERS_SEARCH`
|
|
452
|
+
|
|
453
|
+
Внутри `criterion/ORDERS_SEARCH`:
|
|
454
|
+
|
|
455
|
+
- label trigger: `button[role="combobox"][data-autotest="criterion-label"]`;
|
|
456
|
+
- выбранный raw search label находится в `data-autotest-value` trigger;
|
|
457
|
+
- обычные, numeric, IP и masked inputs используют actual
|
|
458
|
+
`input[data-autotest="criterion-input"]`; значение читается из `.value`;
|
|
459
|
+
- country-вариант использует actual combobox `criterion-input/<raw country id>`.
|
|
460
|
+
|
|
461
|
+
Группированный label dialog:
|
|
462
|
+
|
|
463
|
+
```css
|
|
464
|
+
[role="dialog"][data-autotest="criterion-label-options"][data-autotest-value="<scope>"][data-autotest-criterion="ORDERS_SEARCH"]
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Внутри него:
|
|
468
|
+
|
|
469
|
+
- семь native disclosure summaries: `criterion-label-group/<main|customer|source-card|destination-card|wire|card-present-api|mobile-api>`;
|
|
470
|
+
- 45 native radio inputs: `criterion-label-option/<raw ORDER_SEARCH_LABEL>`;
|
|
471
|
+
- expanded state группы: `aria-expanded` на `summary` и native `details.open`;
|
|
472
|
+
- выбранное поле: native radio `checked`/Selenium `isSelected()`.
|
|
473
|
+
|
|
474
|
+
Selectable raw labels по группам:
|
|
475
|
+
|
|
476
|
+
- `main`: `merchant_invoice_id`, `order_id`, `processor_order_id`, `purpose`, `transaction_amount`,
|
|
477
|
+
`session_token`, `batch_id`;
|
|
478
|
+
- `customer`: `customer_id`, `merchant_customer_identifier`, `customer_phone`, `customer_email`, `customer_ip`,
|
|
479
|
+
`customer_ip_country`, `customer_billing_country`;
|
|
480
|
+
- `source-card`: `source_bank_name`, `source_country`, `source_from_order_id`, `source_bin`,
|
|
481
|
+
`source_bin_range_from_order_id`, `source_last4`, `source_bin_last4`, `source_auth_code`, `source_arn`,
|
|
482
|
+
`source_rrn`, `source_card_holder`, `source_card_ref_id`;
|
|
483
|
+
- `destination-card`: `dest_bank_name`, `dest_country`, `dest_from_order_id`, `dest_bin`,
|
|
484
|
+
`dest_bin_range_from_order_id`, `dest_last4`, `dest_bin_last`, `dest_auth_code`, `dest_arn`, `dest_rrn`,
|
|
485
|
+
`dest_card_ref_id`;
|
|
486
|
+
- `wire`: `account_number`, `routing_number`;
|
|
487
|
+
- `card-present-api`: `reader_id`, `reader_key_serial_number`, `reader_device_serial_number`;
|
|
488
|
+
- `mobile-api`: `device_serial_number`, `phone_serial_number`, `phone_imei`.
|
|
489
|
+
|
|
490
|
+
Не проверяйте, что в dialog обязательно присутствуют все legacy values сохранённого фильтра. Десять значений
|
|
491
|
+
можно восстановить из сохранённого поиска, но нельзя выбрать в текущем dialog:
|
|
492
|
+
`customer_dna_id`, `registration_info_id`, `inn`, `mtcn`, `rebill`, `swift_number`, `webmoney_account`,
|
|
493
|
+
`yamoney_account`, `wire_account`, `card_number_hash_hash`. Для них trigger и input работают, но ни один radio
|
|
494
|
+
не будет выбран.
|
|
495
|
+
|
|
496
|
+
Country options portal:
|
|
497
|
+
|
|
498
|
+
- owner listbox: `criterion-input-options/<scope>` + `data-autotest-criterion="ORDERS_SEARCH"`;
|
|
499
|
+
- option: `criterion-input-option/<raw numeric country id>`;
|
|
500
|
+
- selection: `aria-selected`.
|
|
501
|
+
|
|
502
|
+
### Enum buttons: `STATUS`, `THREE_D`, `MARKER_STATUS`
|
|
503
|
+
|
|
504
|
+
Каждый вариант является actual button:
|
|
505
|
+
|
|
506
|
+
```css
|
|
507
|
+
[role="button"][data-autotest="criterion-option"][data-autotest-value="<raw enum>"]
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Состояние читается из `aria-pressed`.
|
|
511
|
+
|
|
512
|
+
| Criterion | Raw values |
|
|
513
|
+
|---|---|
|
|
514
|
+
| `STATUS` | `ANY`, `DISABLED`, `ENABLED` |
|
|
515
|
+
| `THREE_D` | `ANY`, `NO`, `YES` |
|
|
516
|
+
| `MARKER_STATUS` | `any`, `unprocessed`, `processed` |
|
|
517
|
+
|
|
518
|
+
Регистр raw value значим.
|
|
519
|
+
|
|
520
|
+
### Collections
|
|
521
|
+
|
|
522
|
+
Один общий contract используется для:
|
|
523
|
+
|
|
524
|
+
- `CURRENCY`;
|
|
525
|
+
- `CARD_TYPES`;
|
|
526
|
+
- `COUNTRIES`;
|
|
527
|
+
- `TRANSACTION_TYPES`;
|
|
528
|
+
- `TRANSACTION_STATUS`;
|
|
529
|
+
- `RECURRENCE_TYPE`;
|
|
530
|
+
- `RECURRENCE_STATUS`;
|
|
531
|
+
- `MFO_CONFIGURATION_TYPE`;
|
|
532
|
+
- `MARKER_TYPE`.
|
|
533
|
+
|
|
534
|
+
Внутри criterion root:
|
|
535
|
+
|
|
536
|
+
- actual input: `input[role="combobox"][data-autotest="criterion-collection"]`;
|
|
537
|
+
- выбранные Chips: `criterion-collection-value/<raw entity id>`;
|
|
538
|
+
- synthetic All имеет literal value `all`, а не translated label.
|
|
539
|
+
|
|
540
|
+
Detached content:
|
|
541
|
+
|
|
542
|
+
| Элемент | Contract |
|
|
543
|
+
|---|---|
|
|
544
|
+
| Autocomplete paper | `criterion-collection-panel/<scope>` + owning criterion |
|
|
545
|
+
| Named listbox | `criterion-collection-options/<scope>` + owning criterion |
|
|
546
|
+
| Option | `criterion-collection-option/<raw entity id|all>` |
|
|
547
|
+
|
|
548
|
+
Option selection читается из `aria-selected`. Состояние All определяется raw `all`, а не сравнением количества
|
|
549
|
+
выбранных и доступных options.
|
|
550
|
+
|
|
551
|
+
### `CUSTOMER_LEVEL`
|
|
552
|
+
|
|
553
|
+
- control: `criterion-customer-level/<raw selected level id>`;
|
|
554
|
+
- listbox: `criterion-customer-level-options/<scope>` + `data-autotest-criterion="CUSTOMER_LEVEL"`;
|
|
555
|
+
- option: `criterion-customer-level-option/<raw level id>`;
|
|
556
|
+
- loading: `aria-busy`;
|
|
557
|
+
- недоступность до выбора зависимостей/при loading: `aria-disabled="true"` на combobox;
|
|
558
|
+
- выбранный option: `aria-selected`.
|
|
559
|
+
|
|
560
|
+
Control может быть disabled или список может быть пустым, если не выбран ровно один Merchant либо provider не
|
|
561
|
+
вернул подходящие уровни. Это product state.
|
|
562
|
+
|
|
563
|
+
### `PROJECT_CURRENCY`
|
|
564
|
+
|
|
565
|
+
- control: `criterion-project-currency/<raw currency id>`;
|
|
566
|
+
- listbox: `criterion-project-currency-options/<scope>` + owning criterion;
|
|
567
|
+
- option: `criterion-project-currency-option/<raw currency id>`;
|
|
568
|
+
- conversion checkbox: native
|
|
569
|
+
`input[data-autotest="criterion-project-currency-convert"]`; состояние через `isSelected()`/`checked`;
|
|
570
|
+
- loading: `aria-busy`; disabled selector: `aria-disabled="true"` на combobox.
|
|
571
|
+
|
|
572
|
+
Conversion checkbox остаётся отдельным native control и не становится disabled автоматически только из-за
|
|
573
|
+
недоступности currency combobox.
|
|
574
|
+
|
|
575
|
+
### Date criteria
|
|
576
|
+
|
|
577
|
+
Оба date criteria имеют range-spec selector:
|
|
578
|
+
|
|
579
|
+
- control: `criterion-range-spec/<raw DateRangeSpecType>`;
|
|
580
|
+
- listbox: `criterion-range-spec-options/<scope>` + owning criterion;
|
|
581
|
+
- option: `criterion-range-spec-option/<raw DateRangeSpecType>`;
|
|
582
|
+
- option selection: `aria-selected`.
|
|
583
|
+
|
|
584
|
+
Raw `DateRangeSpecType`:
|
|
585
|
+
|
|
586
|
+
`EXACTLY`, `TODAY`, `YESTERDAY`, `THIS_WEEK`, `LAST_WEEK`, `THIS_MONTH`, `LAST_MONTH`, `DAYS_BEFORE`,
|
|
587
|
+
`HOURS_BEFORE`, `DATE_INDEPENDENT`.
|
|
588
|
+
|
|
589
|
+
Конкретная страница может разрешать только подмножество этих режимов, поэтому автотест не должен ожидать все
|
|
590
|
+
десять options без соответствующей фикстуры/config.
|
|
591
|
+
|
|
592
|
+
`DATE_RANGE_ORDERS` дополнительно имеет:
|
|
593
|
+
|
|
594
|
+
- control: `criterion-order-date-type/<raw order date type>`;
|
|
595
|
+
- listbox: `criterion-order-date-type-options/<scope>` + `data-autotest-criterion="DATE_RANGE_ORDERS"`;
|
|
596
|
+
- option: `criterion-order-date-type-option/<raw order date type>`.
|
|
597
|
+
|
|
598
|
+
Raw order date types: `SESSION_CREATED`, `SESSION_STATUS_CHANGED`, `TX_CREATED`, `BANK`, `TX_SETTLED`,
|
|
599
|
+
`TX_UNSETTLED`.
|
|
600
|
+
|
|
601
|
+
Зависимые от режима inputs:
|
|
602
|
+
|
|
603
|
+
| Режим | Contract |
|
|
604
|
+
|---|---|
|
|
605
|
+
| `DAYS_BEFORE`/`HOURS_BEFORE` | Native number input `criterion-before-count`; значение из `.value` |
|
|
606
|
+
| Exact date-only | Named composite group `criterion-date-range`; picker button `criterion-date-range-picker-toggle` |
|
|
607
|
+
| Exact date-time start | Composite `criterion-date-time-from`; button `criterion-date-time-from-picker-toggle` |
|
|
608
|
+
| Exact date-time end | Composite `criterion-date-time-to`; button `criterion-date-time-to-picker-toggle` |
|
|
609
|
+
|
|
610
|
+
Picker portal roots:
|
|
611
|
+
|
|
612
|
+
- `criterion-date-range-picker/<scope>`;
|
|
613
|
+
- `criterion-date-time-from-picker/<scope>`;
|
|
614
|
+
- `criterion-date-time-to-picker/<scope>`;
|
|
615
|
+
- каждый также получает `data-autotest-criterion` владельца.
|
|
616
|
+
|
|
617
|
+
Внутри picker:
|
|
618
|
+
|
|
619
|
+
- day gridcell: `criterion-date-option/<YYYY-MM-DD>`, selection через `aria-selected`;
|
|
620
|
+
- clock option: `[role="option"][data-autotest="criterion-time-option"]`; конкретное число берётся из option
|
|
621
|
+
content/accessible name внутри уже scoped picker, selection — из `aria-selected`.
|
|
622
|
+
|
|
623
|
+
Не используйте hidden serialized input date picker: контрактом являются visible composite sections и actual
|
|
624
|
+
picker controls.
|
|
625
|
+
|
|
626
|
+
### `PROCESSOR_LOG_ENTRY_TYPE`
|
|
627
|
+
|
|
628
|
+
- control: `criterion-processor-log-entry-type/<raw numeric provider id>`;
|
|
629
|
+
- listbox: `criterion-processor-log-entry-type-options/<scope>` + owning criterion;
|
|
630
|
+
- option: `criterion-processor-log-entry-type-option/<raw numeric provider id>`;
|
|
631
|
+
- selection: `aria-selected`.
|
|
632
|
+
|
|
633
|
+
### `ERROR_CODE`
|
|
634
|
+
|
|
635
|
+
- actual autocomplete input: `criterion-error-code/<raw committed choice id>`;
|
|
636
|
+
- текст запроса читается из `.value`, а не из test attribute;
|
|
637
|
+
- clear action: `criterion-error-code-clear`;
|
|
638
|
+
- paper: `criterion-error-code-panel/<scope>` + owning criterion;
|
|
639
|
+
- listbox: `criterion-error-code-options/<scope>` + owning criterion;
|
|
640
|
+
- option: `criterion-error-code-option/<raw choice id>`;
|
|
641
|
+
- loading: `aria-busy`; selection: `aria-selected`.
|
|
642
|
+
|
|
643
|
+
Одинаковые display labels не создают коллизию, потому что identity option — raw ID.
|
|
644
|
+
|
|
645
|
+
### `GROUPING`
|
|
646
|
+
|
|
647
|
+
Inline controls:
|
|
648
|
+
|
|
649
|
+
- dialog trigger: `button[data-autotest="criterion-grouping-groups"]`;
|
|
650
|
+
- selected Chips: `criterion-grouping-value/<raw GroupingType>`;
|
|
651
|
+
- date-type control: `criterion-grouping-date-type/<raw date type>`;
|
|
652
|
+
- date-type listbox: `criterion-grouping-date-type-options/<scope>` + owning criterion;
|
|
653
|
+
- date-type option: `criterion-grouping-date-type-option/<raw date type>`.
|
|
654
|
+
|
|
655
|
+
Raw grouping date types: `MONTH`, `DAY`, `CLOSE_DAY`, `SETTLEMENT_DAY`, `SETTLEMENT_MONTH`.
|
|
656
|
+
|
|
657
|
+
Raw `GroupingType` values: `MERCHANT`, `MANAGER`, `PROJECT`, `CURRENCY`, `ENDPOINT`, `CARD_TYPE`, `GATE`,
|
|
658
|
+
`PROCESSOR`, `MID`, `COUNTERPARTY`, `PROJECT_CODE`, `DATE`, `MONTH`, `DAY`, `CLOSE_DAY`, `SETTLEMENT_DAY`,
|
|
659
|
+
`SETTLEMENT_MONTH`. Страница может передать только подмножество available types.
|
|
660
|
+
|
|
661
|
+
Detached dialog:
|
|
662
|
+
|
|
663
|
+
```css
|
|
664
|
+
[role="dialog"][data-autotest="criterion-grouping-panel"][data-autotest-value="<scope>"][data-autotest-criterion="GROUPING"]
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Внутри dialog:
|
|
668
|
+
|
|
669
|
+
| Элемент | Contract |
|
|
670
|
+
|---|---|
|
|
671
|
+
| Available group | `criterion-grouping-available` |
|
|
672
|
+
| Selected group | `criterion-grouping-selected` |
|
|
673
|
+
| Add/remove row | `criterion-grouping-option/<raw GroupingType>`; actual native button |
|
|
674
|
+
| Search input | `criterion-grouping-search` |
|
|
675
|
+
| Conditional clear search | `criterion-grouping-search-clear` |
|
|
676
|
+
| Add all | `criterion-grouping-add-all` |
|
|
677
|
+
| Remove all | `criterion-grouping-remove-all` |
|
|
678
|
+
|
|
679
|
+
После переноса row из available в selected тот же raw ID сохраняется, а action/accessible name меняется.
|
|
680
|
+
Save/Cancel ищутся по native role/name внутри scoped dialog.
|
|
681
|
+
|
|
682
|
+
### `TRANSACTION_SESSION_STATUS`
|
|
683
|
+
|
|
684
|
+
Inline:
|
|
685
|
+
|
|
686
|
+
- trigger: `criterion-transaction-session-status/<raw current group>`;
|
|
687
|
+
- current group Chip: `criterion-transaction-session-status-group-value/<raw group>`;
|
|
688
|
+
- selected status Chips: `criterion-transaction-session-status-value/<status.displayName>`;
|
|
689
|
+
- trigger state: `aria-expanded`, `aria-controls`, `aria-busy`.
|
|
690
|
+
|
|
691
|
+
Portal dialog:
|
|
692
|
+
|
|
693
|
+
- root: `criterion-transaction-session-status-panel/<scope>` +
|
|
694
|
+
`data-autotest-criterion="TRANSACTION_SESSION_STATUS"`;
|
|
695
|
+
- group combobox: `criterion-transaction-session-status-group/<raw group>`;
|
|
696
|
+
- group listbox: `criterion-transaction-session-status-group-options/<scope>` + owning criterion;
|
|
697
|
+
- group option: `criterion-transaction-session-status-group-option/<raw group>`;
|
|
698
|
+
- status checkbox input: `criterion-transaction-session-status-option/<status.displayName>`;
|
|
699
|
+
- checkbox state: native `checked`/Selenium `isSelected()`.
|
|
700
|
+
|
|
701
|
+
Список group/status приходит от provider и является динамическим: не проверяйте фиксированное число групп без
|
|
702
|
+
соответствующей фикстуры. `status.displayName` является backend identity статуса внутри группы; locator не
|
|
703
|
+
зависит от перевода или позиции в массиве. Изменения статусов применяются сразу, без отдельного Save.
|
|
704
|
+
|
|
705
|
+
Group listbox является отдельным portal и не находится внутри status dialog card. После открытия combobox его
|
|
706
|
+
нужно искать от `document` по owner scope и `data-autotest-criterion`, а не descendant-поиском от dialog.
|
|
707
|
+
|
|
708
|
+
### Multiget: девять типов критериев
|
|
709
|
+
|
|
710
|
+
| Criterion | `LinkedEntityTypeEnum` | Only enabled control | Gate search labels |
|
|
711
|
+
|---|---|---|---|
|
|
712
|
+
| `PROJECT` | `PROJECT` | Да | Нет |
|
|
713
|
+
| `ENDPOINT` | `ENDPOINT` | Да | Нет |
|
|
714
|
+
| `GATE` | `GATE` | Да | Да |
|
|
715
|
+
| `PROCESSOR` | `PROCESSOR` | Да | Нет |
|
|
716
|
+
| `COMPANY` | `COMPANY` | Да | Нет |
|
|
717
|
+
| `MANAGER` | `MANAGER` | Нет | Нет |
|
|
718
|
+
| `MERCHANT` | `MERCHANT` | Да | Нет |
|
|
719
|
+
| `RESELLER` | `RESELLER` | Да | Нет |
|
|
720
|
+
| `DEALER` | `DEALER` | Нет | Нет |
|
|
721
|
+
|
|
722
|
+
#### Inline trigger и summary
|
|
723
|
+
|
|
724
|
+
- actual native button: `criterion-multiget-trigger/<NONE|ALL|SEARCH>`;
|
|
725
|
+
- selected/excluded summary Chip: `criterion-multiget-value/<raw numeric entity.id>`;
|
|
726
|
+
- open state: `aria-expanded`; portal link: `aria-controls`; popup type: `aria-haspopup="dialog"`.
|
|
727
|
+
|
|
728
|
+
Сохранённый фильтр может восстановить режим `SEARCH`, однако внутри dialog переключатели режима существуют
|
|
729
|
+
только для `NONE` и `ALL`. В таком восстановленном состоянии не ожидайте обязательный `aria-pressed="true"`
|
|
730
|
+
у одного из этих двух переключателей.
|
|
731
|
+
|
|
732
|
+
#### Owner-scoped dialog
|
|
733
|
+
|
|
734
|
+
```css
|
|
735
|
+
[role="dialog"][data-autotest="criterion-multiget-panel"][data-autotest-value="<scope>"][data-autotest-criterion="<multiget CriterionTypeEnum>"]
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
Внутри dialog:
|
|
739
|
+
|
|
740
|
+
| Элемент | Contract/state |
|
|
741
|
+
|---|---|
|
|
742
|
+
| Close | `criterion-multiget-close` |
|
|
743
|
+
| Include mode | `criterion-multiget-mode/NONE`, `aria-pressed` |
|
|
744
|
+
| Exclude mode | `criterion-multiget-mode/ALL`, `aria-pressed` |
|
|
745
|
+
| Only enabled | Native checkbox `criterion-multiget-only-enabled`; только для семи типов из таблицы |
|
|
746
|
+
| Search | Native input `criterion-multiget-search`; query из `.value` |
|
|
747
|
+
| Gate search field | `criterion-multiget-search-label/<all|mid|descriptor>`, `aria-pressed` |
|
|
748
|
+
| Available column | Named group `criterion-multiget-available`, loading через `aria-busy` |
|
|
749
|
+
| Selected/excluded column | Named group `criterion-multiget-selected` |
|
|
750
|
+
| Add entity | Native button `criterion-multiget-add/<raw numeric entity.id>` |
|
|
751
|
+
| Remove entity | Native button `criterion-multiget-remove/<raw numeric entity.id>` |
|
|
752
|
+
|
|
753
|
+
Одинаковый entity ID допустим в разных SearchUI scopes. Внутри одного dialog hidden duplicate может оставаться в
|
|
754
|
+
available column после выбора, поэтому add/remove всегда ищутся сначала относительно нужной колонки.
|
|
755
|
+
|
|
756
|
+
Clear в selected column, Save и Cancel ищутся по native role/name внутри scoped dialog. Pagination остаётся
|
|
757
|
+
semantic `nav`; текущая страница — `aria-current="page"`, unavailable controls — native disabled. Отдельные
|
|
758
|
+
anchors для этих стандартных действий отсутствуют.
|
|
759
|
+
|
|
760
|
+
### Ожидания и асинхронный UI
|
|
761
|
+
|
|
762
|
+
Для async lists/pickers/modal используйте explicit waits на смысловое состояние:
|
|
763
|
+
|
|
764
|
+
- owner-scoped portal появился;
|
|
765
|
+
- trigger получил `aria-expanded="true"`;
|
|
766
|
+
- `aria-busy` стал `false`;
|
|
767
|
+
- ожидаемый raw option появился;
|
|
768
|
+
- после action изменился native/ARIA state или portal исчез.
|
|
769
|
+
|
|
770
|
+
Не используйте fixed sleeps. Не считайте empty result ошибкой locator, если provider действительно вернул
|
|
771
|
+
пустой список.
|
|
772
|
+
|
|
773
|
+
### На чём не строить Selenium-локаторы
|
|
774
|
+
|
|
775
|
+
Не используйте как постоянную identity:
|
|
776
|
+
|
|
777
|
+
- MUI/Emotion class names (`Mui*`, `css-*`);
|
|
778
|
+
- `svg`, `path`, декоративную стрелку/иконку;
|
|
779
|
+
- DOM depth, `nth-child`, array index;
|
|
780
|
+
- translated visible text как технический ID raw-критерия, option или entity; явно перечисленные выше
|
|
781
|
+
role/name actions являются locale-aware исключением;
|
|
782
|
+
- generated React/MUI IDs из `aria-controls`;
|
|
783
|
+
- `PNE`, `Paynet`, WhiteLabel/product name;
|
|
784
|
+
- произвольное введённое или секретное значение как переиспользуемый технический ID; поиск заранее созданного
|
|
785
|
+
template fixture по его имени является test-data lookup, а не общей identity компонента;
|
|
786
|
+
- tag name как единственный признак (`//button`, `//div`).
|
|
787
|
+
|
|
788
|
+
Если элемент кликабельный, выбирайте якорь на actual meaningful control из таблиц выше, а не вложенную
|
|
789
|
+
декоративную иконку.
|
|
790
|
+
|
|
791
|
+
### Где находится источник истины
|
|
792
|
+
|
|
793
|
+
Этот раздел README — основной реестр поддерживаемых Selenium-якорей библиотеки. Storybook используется только для
|
|
794
|
+
интерактивных примеров.
|
|
157
795
|
|
|
158
796
|
## OverlayHost
|
|
159
797
|
|