Compare commits
2 Commits
v0.0.2
...
feature/ET
| Author | SHA1 | Date | |
|---|---|---|---|
| e77e4a2ab7 | |||
| 9d5e2e18c5 |
80
docs/work-items/ET-008/00-business-request.md
Normal file
80
docs/work-items/ET-008/00-business-request.md
Normal file
@@ -0,0 +1,80 @@
|
||||
---
|
||||
type: business-request
|
||||
work_item_id: ET-008
|
||||
title: "Smoke test analyst integration"
|
||||
created_at: 2026-05-31
|
||||
source: pipeline-smoke
|
||||
requester: claude-bot
|
||||
synthetic: true
|
||||
---
|
||||
|
||||
# Бизнес-запрос — ET-008 (Smoke test analyst integration)
|
||||
|
||||
## Контекст
|
||||
|
||||
Это **smoke-работа** для проверки интеграции аналитика в пайплайн
|
||||
`analyst → architect → coder → tester`. Реального заказчика нет;
|
||||
запрос синтезирован, чтобы проверить, что:
|
||||
|
||||
1. Аналитик умеет создать полный пакет артефактов
|
||||
(BRD / TRZ / AC / test-plan / UI test cases) без ручного вмешательства.
|
||||
2. Архитектор может декомпозировать ТЗ в исполнимый план.
|
||||
3. Кодер может реализовать минимальное изменение по плану.
|
||||
4. Тестировщик может прогнать функциональные и Playwright-тесты,
|
||||
и автоматически закрыть задачу.
|
||||
|
||||
В отличие от ET-007 (dry-run по реальной фиче), ET-008 — это **smoke**:
|
||||
скоуп ещё уже, никакого нового UX-функционала для пользователя нет,
|
||||
только технический маркер, видимый Playwright-у.
|
||||
|
||||
Требования к синтетическому скоупу (жёстче, чем у ET-007):
|
||||
|
||||
- Изменение исключительно во фронтенде (`src/web/index.html`,
|
||||
`src/web/app.css`). JavaScript **не трогаем**.
|
||||
- Не ломает существующий функционал: карта, темы, роутинг, GPX, рельеф
|
||||
(hillshade/TRI), POI, разведка, линейка, единицы измерения, поиск,
|
||||
переключатели слоёв.
|
||||
- Виден Playwright-у при специальном условии (`?smoke=et-008` в URL),
|
||||
но **невидим** обычному пользователю при чистой загрузке.
|
||||
- Тривиально откатывается: одна `<div>` в `index.html` + один CSS-блок.
|
||||
- Не зависит от сети, БД, времени, пользовательских действий.
|
||||
|
||||
## Исходная формулировка
|
||||
|
||||
> Нужен невидимый по умолчанию DOM-маркер, который сигнализирует, что
|
||||
> текущая сборка прошла полный конвейер аналитик → архитектор → кодер →
|
||||
> тестировщик. Маркер должен появляться в углу карты только когда в
|
||||
> URL присутствует параметр `?smoke=et-008` (или хеш `#smoke=et-008`).
|
||||
> Это нужно автоматическим тестам пайплайна — они проверяют, что
|
||||
> deploy на test содержит сборку правильного work-item, и что фронтенд
|
||||
> отвечает на разметку без падений.
|
||||
|
||||
## Уточнения (приняты по умолчанию для smoke)
|
||||
|
||||
1. Видимый идентификатор маркера: `#pipeline-smoke`.
|
||||
2. Текст маркера (на русском): «ET-008 ✓».
|
||||
3. Позиция: левый нижний угол экрана (не конфликтует с
|
||||
`#map-controls-r` справа, с `bottom-sheet` снизу-по центру, с
|
||||
`.maplibregl-ctrl-attrib` справа-внизу). Конкретно — `left: 8px;
|
||||
bottom: 8px`.
|
||||
4. Размер: 11px шрифт, нижний регистр, полупрозрачный фон, нейтральный
|
||||
тёмно-серый цвет; не должен закрывать ничего важного даже если
|
||||
как-то стал видимым случайно.
|
||||
5. Условие отображения: маркер присутствует в DOM **всегда**, но имеет
|
||||
`display: none` по умолчанию. Видим становится, когда у `<body>`
|
||||
есть класс `smoke-mode`. Класс ставится автоматически инлайн-скриптом
|
||||
в `<head>`, если `location.search` содержит `smoke=et-008` ИЛИ
|
||||
`location.hash` содержит `smoke=et-008`.
|
||||
6. Не использовать `localStorage`. Маркер ничего не сохраняет —
|
||||
только реагирует на URL текущего хита.
|
||||
7. Доступность: `aria-hidden="true"`, `role="presentation"` — маркер
|
||||
технический, не должен попадать в screen reader.
|
||||
8. Семантика body-класса: имя `smoke-mode` зарезервировано **только**
|
||||
за этим work item. Если в будущем понадобятся аналогичные маркеры
|
||||
для других work items — расширяем семантику тем же классом, но с
|
||||
дополнительными data-атрибутами.
|
||||
9. Backend / БД / тайл-эндпоинты / OSRM / app.js / units.js / gpx.js
|
||||
**не затрагиваются**.
|
||||
10. Тёмная и светлая темы: маркер использует одинаковые цвета в обеих
|
||||
темах (тёмный фон + светлый текст), читаемость гарантируется
|
||||
собственными цветами, а не наследованием от темы.
|
||||
120
docs/work-items/ET-008/01-brd.md
Normal file
120
docs/work-items/ET-008/01-brd.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
type: brd
|
||||
work_item_id: ET-008
|
||||
title: "BRD: Smoke test analyst integration"
|
||||
version: 1
|
||||
status: draft
|
||||
created_at: 2026-05-31
|
||||
updated_at: 2026-05-31
|
||||
authors:
|
||||
- "agent:analyst"
|
||||
---
|
||||
|
||||
# BRD — ET-008: Smoke test analyst integration
|
||||
|
||||
## 1. Цель
|
||||
|
||||
Подтвердить, что цепочка агентов `analyst → architect → coder → tester`
|
||||
работоспособна **end-to-end**: аналитик выдаёт валидные артефакты,
|
||||
архитектор по ним строит план, кодер минимально его реализует,
|
||||
тестировщик прогоняет автотесты (включая Playwright) и автоматически
|
||||
закрывает задачу.
|
||||
|
||||
Полезной фичи для конечного пользователя нет — это намеренно
|
||||
технический smoke. Минимальное изменение во фронтенде нужно лишь как
|
||||
«отпечаток сборки», который Playwright увидит и подтвердит.
|
||||
|
||||
## 2. Контекст
|
||||
|
||||
- Веб-приложение: MapLibre GL JS 4.7 + vanilla JS, без фреймворка.
|
||||
- Базовая страница: `src/web/index.html`; стили — `src/web/app.css`;
|
||||
логика — `src/web/app.js` (НЕ ТРОГАТЬ в рамках ET-008).
|
||||
- ET-007 (Спутниковая карта) уже использовал такую же idea-pipeline
|
||||
для dry-run; ET-008 — следующая итерация, ещё минимальнее: ноль JS,
|
||||
ноль внешних зависимостей, ноль localStorage.
|
||||
- Имеется работающая Playwright-инфра (`tests/web/e2e/`), которая
|
||||
умеет открывать тест-окружение и снимать скриншоты.
|
||||
|
||||
## 3. Scope
|
||||
|
||||
### In scope
|
||||
|
||||
| # | Функция |
|
||||
|------|------------------------------------------------------------------------------------------------------|
|
||||
| F-01 | DOM-элемент `#pipeline-smoke` с текстом «ET-008 ✓» в `src/web/index.html` |
|
||||
| F-02 | CSS-правила для `#pipeline-smoke` в `src/web/app.css` (скрыт по умолчанию) |
|
||||
| F-03 | CSS-правила для `body.smoke-mode #pipeline-smoke` (видим в smoke-режиме) |
|
||||
| F-04 | Инлайн-скрипт в `<head>` `src/web/index.html`, добавляющий `smoke-mode` к `<body>` по URL-условию |
|
||||
| F-05 | Условие активации: `location.search.includes('smoke=et-008')` ИЛИ `location.hash.includes('smoke=et-008')` |
|
||||
| F-06 | По умолчанию (без параметра) маркер физически в DOM, но `display:none` |
|
||||
| F-07 | Маркер `aria-hidden="true"` / `role="presentation"` — не попадает в screen reader |
|
||||
| F-08 | Позиционирование: `position: fixed; left: 8px; bottom: 8px; z-index` ниже sheets/popup'ов |
|
||||
| F-09 | Совместимость с тёмной и светлой темами — собственные цвета, не наследует темовые переменные |
|
||||
|
||||
### Out of scope
|
||||
|
||||
- JavaScript-логика в `src/web/app.js`, `units.js`, `gpx.js`.
|
||||
- Любой backend / БД / OSRM / тайлы.
|
||||
- Сохранение состояния (localStorage / sessionStorage / cookies).
|
||||
- Видимость по нажатию кнопки / shortcut'у клавиатуры / тапу — только URL.
|
||||
- Локализация (текст «ET-008 ✓» одинаков для всех языков).
|
||||
- Анимации появления / скрытия.
|
||||
- Управление через query API (REST/IPC).
|
||||
- Мобильный layout-tuning (маркер одинаков на desktop и mobile).
|
||||
- Любые другие work item identifiers, кроме `et-008`.
|
||||
|
||||
## 4. Метрики успеха
|
||||
|
||||
| Метрика | Критерий |
|
||||
|-----------------------------------------------|-----------------------------------------------------------------------------------------|
|
||||
| Наличие маркера в DOM | На любой загрузке `document.querySelector('#pipeline-smoke')` не null |
|
||||
| Скрытость по умолчанию | На `?` (без параметра) `getComputedStyle(...).display === 'none'` |
|
||||
| Видимость в smoke-режиме | На `?smoke=et-008` или `#smoke=et-008` маркер визуально различим в левом нижнем углу |
|
||||
| Контент маркера | `textContent.trim() === 'ET-008 ✓'` |
|
||||
| Корректность ARIA | `aria-hidden="true"`, `role="presentation"` |
|
||||
| Отсутствие конфликтов | Маркер не перекрывает `#map-controls-r`, sheets, `.maplibregl-ctrl-attrib` |
|
||||
| Стабильность тем | После `toggleTheme()` маркер остаётся видим/скрыт согласно своему правилу |
|
||||
| Отсутствие регрессий | Все существующие E2E (ET-001..ET-007) остаются зелёными |
|
||||
| Время от клика до отображения | После загрузки страницы маркер показан **до** `DOMContentLoaded` end (инлайн-скрипт) |
|
||||
| Отсутствие сетевых запросов | ET-008 не порождает ни одного нового HTTP-запроса |
|
||||
| Откатываемость | Полный откат — 3 диффа (HTML head + HTML body + CSS блок), 1 коммит |
|
||||
|
||||
## 5. Риски
|
||||
|
||||
| Риск | Вероятность | Влияние | Митигация |
|
||||
|---------------------------------------------------------------------|-------------|---------|------------------------------------------------------------------------------------|
|
||||
| Инлайн-скрипт в `<head>` ломает CSP | Низкая | Среднее | CSP не настроен сейчас. Если когда-то будет — переключить на data-атрибут + CSS-only|
|
||||
| `#pipeline-smoke` перекрывает важный UI (например `.maplibregl-ctrl-scale`) | Низкая | Низкое | `z-index: 1` — ниже всех плавающих контролов; позиция фиксирована подальше |
|
||||
| Маркер случайно засветился пользователю (например shared link с `?smoke=et-008`) | Низкая | Низкое | Текст нейтральный, не раскрывает ничего внутреннего; стиль ненавязчивый |
|
||||
| Body-класс `smoke-mode` конфликтует с будущим классом темы | Низкая | Низкое | Префикс `smoke-` зарезервирован; в проекте сейчас нет похожих имён |
|
||||
| ARIA-атрибуты «protect» сломаются при mutation observer на body | Низкая | Низкое | `aria-hidden` ставится статически в HTML, не из JS |
|
||||
| Маркер ломает Playwright-снимки других тестов | Низкая | Низкое | По умолчанию `display:none` — на скриншоте не виден, BB-rect = 0 |
|
||||
| Лишний div снижает производительность DOM | Очень низкая| Очень низкое| 1 элемент, без подписок, без обработчиков |
|
||||
| Старые браузеры не поддерживают `includes` на строках | Очень низкая| Низкое | `String.prototype.includes` — ES2015, поддержано во всех целевых браузерах |
|
||||
|
||||
## 6. Зависимости
|
||||
|
||||
- **Внешние сервисы**: нет.
|
||||
- **Внутренние**: только `src/web/index.html`, `src/web/app.css`.
|
||||
- Не зависит от ET-005 / ET-006 / ET-007.
|
||||
- Не блокирует ни одну фазу (PH-1..PH-9).
|
||||
- Не вносит изменений в `app.js`, `units.js`, `gpx.js`.
|
||||
- Не меняет `style.json`, `style-dark.json`.
|
||||
- Backend, БД, OSRM, миграции, контейнеры — не затрагиваются.
|
||||
- CI/CD — не меняется. Только новые E2E-тесты для самого маркера в
|
||||
`tests/web/e2e/pipeline-smoke.spec.ts`.
|
||||
|
||||
## 7. Критерии smoke-успеха (для пайплайна)
|
||||
|
||||
Эта работа считается завершённой, когда:
|
||||
|
||||
1. Все 5 артефактов аналитика (`00`..`04b`) присутствуют и валидны.
|
||||
2. Архитектор выдаёт минимум один план в `05-architecture.md` или
|
||||
эквивалент.
|
||||
3. Кодер вносит изменения только в `src/web/index.html` +
|
||||
`src/web/app.css` (по diff'у видно).
|
||||
4. Все тесты UT/IT/E2E зелёные на test-окружении.
|
||||
5. Tester автоматически закрывает задачу.
|
||||
|
||||
Само наличие зелёного smoke-прогона важнее, чем визуальная
|
||||
эстетика маркера.
|
||||
281
docs/work-items/ET-008/02-trz.md
Normal file
281
docs/work-items/ET-008/02-trz.md
Normal file
@@ -0,0 +1,281 @@
|
||||
---
|
||||
type: trz
|
||||
work_item_id: ET-008
|
||||
title: "ТЗ: Smoke test analyst integration"
|
||||
version: 1
|
||||
status: draft
|
||||
created_at: 2026-05-31
|
||||
updated_at: 2026-05-31
|
||||
authors:
|
||||
- "agent:analyst"
|
||||
depends_on:
|
||||
- "ET-008/01-brd.md"
|
||||
---
|
||||
|
||||
# Техническое задание — ET-008: Smoke test analyst integration
|
||||
|
||||
## 1. Общая архитектура изменений
|
||||
|
||||
Изменение строго фронтовое и максимально минимальное. Затрагиваются
|
||||
**ровно два файла**:
|
||||
|
||||
- `src/web/index.html`
|
||||
- В `<head>` добавить инлайн-скрипт, который выставляет
|
||||
`document.body.classList.add('smoke-mode')`, если в URL присутствует
|
||||
`smoke=et-008` (в `search` или `hash`).
|
||||
- В `<body>` (рядом с `<div id="map">` или сразу перед `<!-- Scripts -->`)
|
||||
добавить элемент `<div id="pipeline-smoke" aria-hidden="true"
|
||||
role="presentation">ET-008 ✓</div>`.
|
||||
- `src/web/app.css`
|
||||
- В конец файла добавить блок с правилами для `#pipeline-smoke`.
|
||||
|
||||
**Запрещено** трогать: `src/web/app.js`, `src/web/units.js`,
|
||||
`src/web/gpx.js`, `src/web/style.json`, `src/web/style-dark.json`,
|
||||
`src/api/**`, `tests/api/**`, миграции, Docker-конфигурацию.
|
||||
|
||||
## 2. Функциональные требования
|
||||
|
||||
### REQ-F-01. DOM-маркер `#pipeline-smoke`
|
||||
|
||||
В `src/web/index.html` добавить элемент:
|
||||
|
||||
```html
|
||||
<div id="pipeline-smoke" aria-hidden="true" role="presentation">ET-008 ✓</div>
|
||||
```
|
||||
|
||||
Размещение: после `<div id="map"></div>` (т.е. внутри `<body>`,
|
||||
сразу после карты), но **до** `<!-- Scripts -->`. Конкретное место —
|
||||
после блока `<div id="no-data-warning">` или эквивалентного места,
|
||||
где сейчас лежат «свободно плавающие» элементы (`#ruler-toast`,
|
||||
`#app-toast`).
|
||||
|
||||
Текст узла: ровно `ET-008 ✓` (без кавычек, с одним пробелом перед
|
||||
галочкой, U+2713 CHECK MARK).
|
||||
|
||||
### REQ-F-02. Инлайн-скрипт активации в `<head>`
|
||||
|
||||
В `<head>` `src/web/index.html`, **после** `<link rel="stylesheet" href="app.css">`
|
||||
и **до** закрывающего `</head>`, добавить:
|
||||
|
||||
```html
|
||||
<script>
|
||||
// ET-008: smoke marker activation. Pure URL-based, no storage, no I/O.
|
||||
(function () {
|
||||
try {
|
||||
var s = (location.search || '') + ' ' + (location.hash || '');
|
||||
if (s.indexOf('smoke=et-008') !== -1) {
|
||||
document.documentElement.classList.add('smoke-mode');
|
||||
}
|
||||
} catch (e) { /* swallow — smoke is non-critical */ }
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
Замечания:
|
||||
- Скрипт ставит класс на `<html>` (`documentElement`), а не на
|
||||
`<body>`, потому что на момент выполнения (в `<head>`) `<body>`
|
||||
ещё не существует. Эквивалентный селектор для CSS —
|
||||
`html.smoke-mode #pipeline-smoke`. Это требование к CSS-блоку
|
||||
(см. REQ-F-04).
|
||||
- `try/catch` обязателен — если по какой-то причине `location`
|
||||
не доступен (тест с jsdom без URL), скрипт не должен ронять
|
||||
страницу.
|
||||
- Скрипт **синхронный**, не модуль, без `defer`/`async` — он
|
||||
должен сработать до того, как CSS попытается применить
|
||||
`display:none` к видимому в smoke маркеру (избежать FOUC).
|
||||
|
||||
### REQ-F-03. CSS базовое состояние (скрыт)
|
||||
|
||||
В конец `src/web/app.css` добавить:
|
||||
|
||||
```css
|
||||
/* ── ET-008: pipeline smoke marker ───────────────────────────
|
||||
По умолчанию полностью скрыт. Включается классом .smoke-mode
|
||||
на <html>, который ставит инлайн-скрипт в <head>, если
|
||||
в URL присутствует ?smoke=et-008 или #smoke=et-008.
|
||||
──────────────────────────────────────────────────────────── */
|
||||
#pipeline-smoke {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
### REQ-F-04. CSS активное состояние (видим)
|
||||
|
||||
Сразу после REQ-F-03 в `src/web/app.css`:
|
||||
|
||||
```css
|
||||
html.smoke-mode #pipeline-smoke {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
left: 8px;
|
||||
bottom: 8px;
|
||||
z-index: 1;
|
||||
padding: 2px 6px;
|
||||
font: 11px/1.4 system-ui, -apple-system, sans-serif;
|
||||
color: #e7e7e7;
|
||||
background: rgba(20, 20, 28, 0.7);
|
||||
border-radius: 4px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
```
|
||||
|
||||
Значения цвета и фона **не зависят** от темы — это намеренно, чтобы
|
||||
маркер был стабильно читаем и в светлой, и в тёмной теме без отдельных
|
||||
правил `body.theme-dark`.
|
||||
|
||||
### REQ-F-05. Условие активации
|
||||
|
||||
Маркер показывается, если **любое** из условий выполнено:
|
||||
|
||||
- `location.search` (часть URL после `?`) содержит подстроку
|
||||
`smoke=et-008`;
|
||||
- `location.hash` (часть URL после `#`) содержит подстроку
|
||||
`smoke=et-008`.
|
||||
|
||||
Сравнение **точное**, чувствительно к регистру. Любое отклонение
|
||||
(`smoke=ET-008`, `smoke=et_008`, `smoke=et-007`, `smoketest=et-008`)
|
||||
**не** активирует маркер.
|
||||
|
||||
### REQ-F-06. Не-конфликтность с темами
|
||||
|
||||
После `toggleTheme()` маркер:
|
||||
- если был видим (smoke-mode) — остаётся видимым с теми же цветами;
|
||||
- если был скрыт (no smoke-mode) — остаётся скрытым.
|
||||
|
||||
То есть body-класс `theme-dark` не влияет на отображение
|
||||
`#pipeline-smoke`.
|
||||
|
||||
### REQ-F-07. Не-конфликтность с layout
|
||||
|
||||
`z-index: 1` ниже, чем у `#map-controls-r` (фактический z-index у
|
||||
существующих контролов — выше). Маркер не должен:
|
||||
- перекрывать `#map-controls-r` (top-right);
|
||||
- перекрывать `.maplibregl-ctrl-attrib` (bottom-right);
|
||||
- мешать `#toolbar` на мобильном (нижняя панель);
|
||||
- перекрывать любой `.bottom-sheet`, когда тот открыт.
|
||||
|
||||
В частности на мобильном бутылочное горлышко — `#toolbar` снизу.
|
||||
Маркер в `left: 8px; bottom: 8px` помещается слева, тулбар обычно
|
||||
центрирован/растянут, так что небольшой риск перекрытия допустим,
|
||||
но визуально не критичен (маркер маленький и полупрозрачный).
|
||||
|
||||
### REQ-F-08. ARIA
|
||||
|
||||
- `aria-hidden="true"` — обязательно.
|
||||
- `role="presentation"` — обязательно.
|
||||
- Никаких подсказок (`title`), `aria-label`, фокусируемых элементов
|
||||
внутри.
|
||||
|
||||
### REQ-F-09. Отсутствие сетевых эффектов
|
||||
|
||||
Реализация не должна:
|
||||
- добавлять `<link>` / `<script src="...">` / `<img>` / `<iframe>`;
|
||||
- обращаться к `fetch` / `XMLHttpRequest` / `navigator.sendBeacon`;
|
||||
- использовать `localStorage` / `sessionStorage` / `cookie` /
|
||||
`IndexedDB` / `caches`.
|
||||
|
||||
### REQ-F-10. Совместимость с Playwright `route(...)`
|
||||
|
||||
Playwright-тесты ET-008 имеют право ассертить отсутствие новых
|
||||
сетевых запросов после добавления маркера (например, через
|
||||
`page.on('request', ...)`). Любая сетевая активность из ET-008 —
|
||||
дефект.
|
||||
|
||||
## 3. Нефункциональные требования
|
||||
|
||||
### REQ-NF-01. Производительность
|
||||
|
||||
- Дополнительный DOM-узел — 1 (`<div>`).
|
||||
- Дополнительный CSS-блок — ≤ 20 строк.
|
||||
- Дополнительный JS — инлайн ≤ 10 строк, выполняется **один раз**
|
||||
до парсинга `<body>`.
|
||||
- Никаких подписок на события, MutationObserver, requestAnimationFrame.
|
||||
|
||||
### REQ-NF-02. Совместимость браузеров
|
||||
|
||||
Те же, что у основного приложения:
|
||||
- Chrome ≥ 110, Firefox ≥ 110, Safari ≥ 16, мобильные Chrome/Safari
|
||||
iOS ≥ 16.
|
||||
- `String.prototype.indexOf` — ES1, поддержано всегда.
|
||||
|
||||
### REQ-NF-03. Логирование
|
||||
|
||||
В нормальной работе скрипт ничего не пишет в консоль.
|
||||
В исключительной — молча проглатывает (`try/catch` без `console.warn`).
|
||||
Это смягчение для тестов, которые ассертят «no console.error».
|
||||
|
||||
### REQ-NF-04. Локализация
|
||||
|
||||
Текст `ET-008 ✓` не локализуется. Это технический идентификатор,
|
||||
одинаковый во всех языках.
|
||||
|
||||
### REQ-NF-05. Безопасность
|
||||
|
||||
- Никаких пользовательских данных в маркере.
|
||||
- Никакого `innerHTML` / `eval` / `Function(...)`.
|
||||
- Никаких внешних URL.
|
||||
|
||||
## 4. Структура данных
|
||||
|
||||
### REQ-D-01. URL-параметры
|
||||
|
||||
| Параметр | Тип | Значение | Эффект |
|
||||
|-----------------------|----------|---------------------------|-----------------------------------------|
|
||||
| `?smoke=et-008` | query | строго `et-008` | `html.classList.add('smoke-mode')` |
|
||||
| `#smoke=et-008` | fragment | строго `et-008` | то же самое |
|
||||
| (нет параметра) | — | — | маркер `display:none` |
|
||||
| `?smoke=...` иное | query | любое отличное от `et-008`| маркер `display:none` |
|
||||
| `#smoke=...` иное | fragment | любое отличное от `et-008`| маркер `display:none` |
|
||||
|
||||
### REQ-D-02. Классы CSS
|
||||
|
||||
| Класс | Селектор где | Назначение |
|
||||
|----------------------|-------------------------------|-------------------------------------|
|
||||
| `smoke-mode` | на `<html>` | флаг видимости маркера |
|
||||
|
||||
## 5. UI / UX контракт
|
||||
|
||||
| Элемент | Местоположение | Поведение |
|
||||
|---------------------|-----------------------------------------------------------------|------------------------------------------------------------------------|
|
||||
| `#pipeline-smoke` | `<body>`, после `#map`, до `<!-- Scripts -->` | По умолчанию `display:none`. В smoke-режиме — fixed left:8 bottom:8 |
|
||||
| Содержимое | Текстовый узел `ET-008 ✓` | Не меняется в рантайме |
|
||||
| Фон | `rgba(20,20,28,0.7)` | Полупрозрачный, чтобы видеть карту под ним |
|
||||
| Текст | `#e7e7e7`, 11px | Контраст ≥ 4.5:1 над тёмным фоном маркера |
|
||||
| Курсор / фокус | `pointer-events: none`, не фокусируется | Не мешает кликам по карте под ним |
|
||||
|
||||
## 6. Тестируемость
|
||||
|
||||
- **Unit**: проверка наличия CSS-блока и DOM-узла через парсинг файлов
|
||||
(без запуска браузера).
|
||||
- **Integration**: запуск страницы в jsdom с поддельным `location`,
|
||||
проверка добавления класса.
|
||||
- **E2E (Playwright)**: загрузка test-окружения с `?smoke=et-008`
|
||||
и без, проверка видимости/скрытости, отсутствия сетевых запросов,
|
||||
отсутствия console.error.
|
||||
- **UI (Playwright скриншоты)**: см. `04b-ui-test-cases.md`.
|
||||
|
||||
## 7. Совместимость и миграции
|
||||
|
||||
- БД: миграций нет.
|
||||
- API: новых эндпоинтов нет.
|
||||
- Конфиги: новых ENV не добавляем.
|
||||
- Существующие work item: не затрагиваются (только статические файлы,
|
||||
никаких JS-символов).
|
||||
- CI: новые тесты добавляются как файл
|
||||
`tests/web/e2e/pipeline-smoke.spec.ts`, существующая команда
|
||||
`make test` подхватывает их без изменения конфигов.
|
||||
|
||||
## 8. Откат
|
||||
|
||||
В случае проблем:
|
||||
1. В `src/web/index.html` удалить инлайн-`<script>` из `<head>`
|
||||
(REQ-F-02).
|
||||
2. В `src/web/index.html` удалить `<div id="pipeline-smoke">…</div>`
|
||||
из `<body>` (REQ-F-01).
|
||||
3. В `src/web/app.css` удалить блок с правилами для `#pipeline-smoke`
|
||||
(REQ-F-03 и REQ-F-04).
|
||||
|
||||
Полный откат — один коммит, без побочных эффектов и без изменения
|
||||
JS / API / БД.
|
||||
177
docs/work-items/ET-008/03-acceptance-criteria.md
Normal file
177
docs/work-items/ET-008/03-acceptance-criteria.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
type: acceptance-criteria
|
||||
work_item_id: ET-008
|
||||
title: "AC: Smoke test analyst integration"
|
||||
version: 1
|
||||
status: draft
|
||||
created_at: 2026-05-31
|
||||
updated_at: 2026-05-31
|
||||
authors:
|
||||
- "agent:analyst"
|
||||
depends_on:
|
||||
- "ET-008/01-brd.md"
|
||||
- "ET-008/02-trz.md"
|
||||
---
|
||||
|
||||
# Критерии приёмки — ET-008: Smoke test analyst integration
|
||||
|
||||
Формат: Gherkin. Сценарии — в браузере приложения, на test-окружении
|
||||
`https://openclaw.mva154.duckdns.org/enduro/`, если не указано иное.
|
||||
|
||||
## AC-01. Маркер присутствует в DOM при любой загрузке
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение в браузере без query-параметров
|
||||
When страница полностью загружена
|
||||
Then в DOM существует элемент с id="pipeline-smoke"
|
||||
And его textContent.trim() == "ET-008 ✓"
|
||||
And у элемента aria-hidden="true"
|
||||
And у элемента role="presentation"
|
||||
```
|
||||
|
||||
## AC-02. Маркер скрыт по умолчанию
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение без параметра smoke
|
||||
When страница загружена
|
||||
Then getComputedStyle(#pipeline-smoke).display == "none"
|
||||
And элемент не виден визуально (boundingClientRect.height == 0)
|
||||
```
|
||||
|
||||
## AC-03. Маркер виден при ?smoke=et-008 в query
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение с URL "...?smoke=et-008"
|
||||
When страница загружена
|
||||
Then у элемента <html> присутствует класс "smoke-mode"
|
||||
And getComputedStyle(#pipeline-smoke).display == "inline-block"
|
||||
And маркер визуально расположен в левом нижнем углу
|
||||
(left ≈ 8px, bottom ≈ 8px от края viewport)
|
||||
```
|
||||
|
||||
## AC-04. Маркер виден при #smoke=et-008 в hash
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение с URL "...#smoke=et-008"
|
||||
When страница загружена
|
||||
Then у элемента <html> присутствует класс "smoke-mode"
|
||||
And маркер визуально виден в левом нижнем углу
|
||||
```
|
||||
|
||||
## AC-05. Маркер скрыт при неверном значении параметра
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение с URL "...?smoke=et-007"
|
||||
When страница загружена
|
||||
Then у элемента <html> класса "smoke-mode" НЕТ
|
||||
And getComputedStyle(#pipeline-smoke).display == "none"
|
||||
```
|
||||
|
||||
## AC-06. Маркер скрыт при неверном имени параметра
|
||||
|
||||
```
|
||||
Given пользователь открывает приложение с URL "...?smoketest=et-008"
|
||||
When страница загружена
|
||||
Then у элемента <html> класса "smoke-mode" НЕТ
|
||||
And маркер не виден
|
||||
```
|
||||
|
||||
## AC-07. Корректность ARIA
|
||||
|
||||
```
|
||||
Given маркер видим (?smoke=et-008)
|
||||
When ассистивная технология сканирует страницу
|
||||
Then узел #pipeline-smoke не попадает в accessibility tree
|
||||
(aria-hidden="true")
|
||||
And screen reader не озвучивает "ET-008 ✓"
|
||||
```
|
||||
|
||||
## AC-08. Совместимость с переключением темы
|
||||
|
||||
```
|
||||
Given маркер видим (?smoke=et-008) в светлой теме
|
||||
When пользователь нажимает #btn-theme (включение тёмной темы)
|
||||
Then тема приложения меняется (body.theme-dark)
|
||||
And маркер #pipeline-smoke остаётся видимым
|
||||
And его background и color не изменились
|
||||
And обратное переключение темы не скрывает маркер
|
||||
```
|
||||
|
||||
## AC-09. Маркер не перекрывает важные элементы UI
|
||||
|
||||
```
|
||||
Given маркер видим
|
||||
When пользователь смотрит на интерфейс
|
||||
Then маркер не перекрывает #map-controls-r
|
||||
And не перекрывает .maplibregl-ctrl-attrib
|
||||
And при открытии bottom-sheet маркер либо остаётся под sheet,
|
||||
либо вообще исчезает за ним (sheet z-index выше)
|
||||
And клики «сквозь» маркер по карте проходят
|
||||
(pointer-events: none на маркере)
|
||||
```
|
||||
|
||||
## AC-10. Отсутствие сетевых запросов от ET-008
|
||||
|
||||
```
|
||||
Given Playwright перехватывает все запросы
|
||||
When страница загружена с ?smoke=et-008
|
||||
Then ни одного НОВОГО HTTP-запроса не порождено логикой ET-008
|
||||
(только базовые тайлы, app.js, units.js, gpx.js, app.css)
|
||||
And в частности нет запросов к /api/smoke/* или подобному
|
||||
```
|
||||
|
||||
## AC-11. Отсутствие console.error
|
||||
|
||||
```
|
||||
Given включён сбор console-сообщений
|
||||
When страница загружена с ?smoke=et-008 (или без)
|
||||
Then в течение 10 секунд после load нет ни одного console.error
|
||||
And console.warn от ET-008 (наш try/catch) не выстреливает
|
||||
в нормальной работе
|
||||
```
|
||||
|
||||
## AC-12. Маркер показывается ДО DOMContentLoaded
|
||||
|
||||
```
|
||||
Given пользователь грузит страницу с ?smoke=et-008 в медленной сети
|
||||
When браузер ещё парсит <body>
|
||||
Then инлайн-скрипт в <head> уже выставил html.smoke-mode
|
||||
And нет FOUC (маркер не мигает «скрыт → видим» после загрузки)
|
||||
```
|
||||
|
||||
## AC-13. Не ломает существующий функционал
|
||||
|
||||
```
|
||||
Given изменения ET-008 применены
|
||||
When пользователь использует
|
||||
роутинг (Маршрут), связку, красивый, разведку, линейку,
|
||||
поиск, метку, GPX, единицы измерения (км/мили),
|
||||
переключение темы, тени рельефа, переключение POI
|
||||
Then все режимы работают как до изменений
|
||||
And нет регрессий в существующих E2E (ET-001..ET-007)
|
||||
And нет ошибок в console.error при базовом сценарии
|
||||
```
|
||||
|
||||
## AC-14. Откатываемость
|
||||
|
||||
```
|
||||
Given изменения ET-008 применены и работают
|
||||
When все упомянутые в TRZ §8 правки откатываются
|
||||
Then приложение возвращается к состоянию до ET-008
|
||||
And ни один тест из существующего набора не падает
|
||||
And в DOM нет осиротевших элементов
|
||||
And в CSS нет неиспользуемых правил для #pipeline-smoke
|
||||
```
|
||||
|
||||
## AC-15. Изоляция диффа
|
||||
|
||||
```
|
||||
Given коммит реализации ET-008
|
||||
When анализируется его diff
|
||||
Then изменены только два файла:
|
||||
- src/web/index.html
|
||||
- src/web/app.css
|
||||
And app.js / units.js / gpx.js / style.json / style-dark.json
|
||||
не затронуты
|
||||
And ни одна строка backend, миграций, Docker-конфигов не изменена
|
||||
```
|
||||
300
docs/work-items/ET-008/04-test-plan.yaml
Normal file
300
docs/work-items/ET-008/04-test-plan.yaml
Normal file
@@ -0,0 +1,300 @@
|
||||
---
|
||||
type: test-plan
|
||||
work_item_id: ET-008
|
||||
title: "Test Plan: Smoke test analyst integration"
|
||||
version: 1
|
||||
status: draft
|
||||
created_at: 2026-05-31
|
||||
updated_at: 2026-05-31
|
||||
authors:
|
||||
- "agent:analyst"
|
||||
depends_on:
|
||||
- "ET-008/02-trz.md"
|
||||
- "ET-008/03-acceptance-criteria.md"
|
||||
---
|
||||
|
||||
# План функциональных тестов — ET-008
|
||||
|
||||
scope:
|
||||
- src/web/index.html
|
||||
- src/web/app.css
|
||||
|
||||
out_of_scope:
|
||||
- src/web/app.js
|
||||
- src/web/units.js
|
||||
- src/web/gpx.js
|
||||
- src/web/style.json
|
||||
- src/web/style-dark.json
|
||||
- src/api/**
|
||||
- migrations/**
|
||||
- tests/api/**
|
||||
|
||||
test_suites:
|
||||
|
||||
- id: unit
|
||||
name: "Unit-тесты статической структуры файлов"
|
||||
runner: "node:test (без браузера)"
|
||||
location: "tests/web/unit/pipeline-smoke.test.js"
|
||||
cases:
|
||||
|
||||
- id: UT-01
|
||||
title: "index.html содержит инлайн-скрипт активации smoke-mode"
|
||||
ac_refs: [AC-03, AC-04, AC-12]
|
||||
given:
|
||||
- "файл src/web/index.html прочитан как строка"
|
||||
when:
|
||||
- "ищется подстрока 'smoke=et-008'"
|
||||
- "ищется подстрока \"classList.add('smoke-mode')\""
|
||||
then:
|
||||
- "обе подстроки найдены"
|
||||
- "скрипт расположен внутри <head> (по offset раньше </head>)"
|
||||
|
||||
- id: UT-02
|
||||
title: "index.html содержит элемент #pipeline-smoke"
|
||||
ac_refs: [AC-01]
|
||||
given:
|
||||
- "файл src/web/index.html прочитан как строка"
|
||||
when:
|
||||
- "ищется регулярка /id=\"pipeline-smoke\"/"
|
||||
- "ищется текст 'ET-008 ✓'"
|
||||
- "ищется atrribute aria-hidden=\"true\""
|
||||
- "ищется attribute role=\"presentation\""
|
||||
then:
|
||||
- "все четыре поиска успешны"
|
||||
- "элемент расположен внутри <body>, до <!-- Scripts -->"
|
||||
|
||||
- id: UT-03
|
||||
title: "app.css содержит правила для #pipeline-smoke"
|
||||
ac_refs: [AC-02, AC-03]
|
||||
given:
|
||||
- "файл src/web/app.css прочитан как строка"
|
||||
when:
|
||||
- "ищется селектор '#pipeline-smoke'"
|
||||
- "ищется селектор 'html.smoke-mode #pipeline-smoke'"
|
||||
- "ищется свойство 'display: none' для первого селектора"
|
||||
- "ищется свойство 'position: fixed' для второго селектора"
|
||||
then:
|
||||
- "все четыре поиска успешны"
|
||||
|
||||
- id: UT-04
|
||||
title: "Запрещённые файлы не изменены (whitelist diff)"
|
||||
ac_refs: [AC-15]
|
||||
given:
|
||||
- "git diff feature/ET-008-... main"
|
||||
when:
|
||||
- "анализируется список изменённых файлов"
|
||||
then:
|
||||
- "ни один из {app.js, units.js, gpx.js, style.json, style-dark.json} не в diff"
|
||||
- "ни один из {src/api/**, migrations/**, Dockerfile, docker-compose*.yml} не в diff"
|
||||
- "в diff присутствуют только {src/web/index.html, src/web/app.css, docs/work-items/ET-008/**, tests/web/**/pipeline-smoke*}"
|
||||
|
||||
- id: integration
|
||||
name: "Интеграционные тесты в jsdom"
|
||||
runner: "node:test + jsdom"
|
||||
location: "tests/web/integration/pipeline-smoke.test.js"
|
||||
cases:
|
||||
|
||||
- id: IT-01
|
||||
title: "Без smoke-параметра — класс не ставится"
|
||||
ac_refs: [AC-02, AC-05, AC-06]
|
||||
given:
|
||||
- "jsdom инициализирован с URL https://localhost/enduro/"
|
||||
- "загружен src/web/index.html (инлайн-скрипт исполнится синхронно)"
|
||||
when:
|
||||
- "проверяется document.documentElement.classList"
|
||||
then:
|
||||
- "класса 'smoke-mode' нет"
|
||||
|
||||
- id: IT-02
|
||||
title: "С ?smoke=et-008 — класс ставится"
|
||||
ac_refs: [AC-03]
|
||||
given:
|
||||
- "jsdom инициализирован с URL https://localhost/enduro/?smoke=et-008"
|
||||
when:
|
||||
- "загружен src/web/index.html"
|
||||
then:
|
||||
- "document.documentElement.classList.contains('smoke-mode') == true"
|
||||
|
||||
- id: IT-03
|
||||
title: "С #smoke=et-008 в hash — класс ставится"
|
||||
ac_refs: [AC-04]
|
||||
given:
|
||||
- "jsdom инициализирован с URL https://localhost/enduro/#smoke=et-008"
|
||||
when:
|
||||
- "загружен src/web/index.html"
|
||||
then:
|
||||
- "document.documentElement.classList.contains('smoke-mode') == true"
|
||||
|
||||
- id: IT-04
|
||||
title: "С ?smoke=et-007 — класс не ставится"
|
||||
ac_refs: [AC-05]
|
||||
given:
|
||||
- "jsdom URL .../?smoke=et-007"
|
||||
when:
|
||||
- "загружен index.html"
|
||||
then:
|
||||
- "классa 'smoke-mode' нет"
|
||||
|
||||
- id: IT-05
|
||||
title: "С ?smoketest=et-008 — класс не ставится"
|
||||
ac_refs: [AC-06]
|
||||
given:
|
||||
- "jsdom URL .../?smoketest=et-008"
|
||||
when:
|
||||
- "загружен index.html"
|
||||
then:
|
||||
- "класса 'smoke-mode' нет"
|
||||
|
||||
- id: IT-06
|
||||
title: "Регистр имеет значение: ?smoke=ET-008 не активирует"
|
||||
ac_refs: [AC-05]
|
||||
given:
|
||||
- "jsdom URL .../?smoke=ET-008"
|
||||
when:
|
||||
- "загружен index.html"
|
||||
then:
|
||||
- "класса 'smoke-mode' нет"
|
||||
|
||||
- id: e2e
|
||||
name: "E2E (Playwright) — функциональные сценарии"
|
||||
runner: "playwright"
|
||||
location: "tests/web/e2e/pipeline-smoke.spec.ts"
|
||||
base_url: "https://openclaw.mva154.duckdns.org/enduro/"
|
||||
notes:
|
||||
- "UI-визуальные тесты вынесены в 04b-ui-test-cases.md."
|
||||
- "Эти тесты проверяют DOM-состояние и сетевые/console-эффекты, без скриншот-сравнений."
|
||||
cases:
|
||||
|
||||
- id: E2E-01
|
||||
title: "Маркер скрыт при чистой загрузке"
|
||||
ac_refs: [AC-01, AC-02]
|
||||
steps:
|
||||
- "navigate base_url"
|
||||
- "wait map idle (4000 ms)"
|
||||
expect:
|
||||
- "selector #pipeline-smoke exists"
|
||||
- "evaluate: document.querySelector('#pipeline-smoke').textContent.trim() == 'ET-008 ✓'"
|
||||
- "evaluate: getComputedStyle(document.querySelector('#pipeline-smoke')).display == 'none'"
|
||||
- "evaluate: !document.documentElement.classList.contains('smoke-mode')"
|
||||
|
||||
- id: E2E-02
|
||||
title: "Маркер видим при ?smoke=et-008"
|
||||
ac_refs: [AC-03]
|
||||
steps:
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait map idle (4000 ms)"
|
||||
expect:
|
||||
- "evaluate: document.documentElement.classList.contains('smoke-mode')"
|
||||
- "evaluate: getComputedStyle(document.querySelector('#pipeline-smoke')).display == 'inline-block'"
|
||||
- "boundingClientRect(#pipeline-smoke).height > 0"
|
||||
|
||||
- id: E2E-03
|
||||
title: "Маркер видим при #smoke=et-008"
|
||||
ac_refs: [AC-04]
|
||||
steps:
|
||||
- "navigate base_url + '#smoke=et-008'"
|
||||
- "wait map idle (4000 ms)"
|
||||
expect:
|
||||
- "evaluate: document.documentElement.classList.contains('smoke-mode')"
|
||||
- "evaluate: getComputedStyle(document.querySelector('#pipeline-smoke')).display == 'inline-block'"
|
||||
|
||||
- id: E2E-04
|
||||
title: "Маркер скрыт при неверном значении (?smoke=et-007)"
|
||||
ac_refs: [AC-05]
|
||||
steps:
|
||||
- "navigate base_url + '?smoke=et-007'"
|
||||
- "wait map idle (4000 ms)"
|
||||
expect:
|
||||
- "evaluate: !document.documentElement.classList.contains('smoke-mode')"
|
||||
- "evaluate: getComputedStyle(document.querySelector('#pipeline-smoke')).display == 'none'"
|
||||
|
||||
- id: E2E-05
|
||||
title: "Совместимость с переключением темы"
|
||||
ac_refs: [AC-08]
|
||||
steps:
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait map idle (4000 ms)"
|
||||
- "click #btn-theme"
|
||||
- "wait 1500 ms"
|
||||
- "click #btn-theme"
|
||||
- "wait 1500 ms"
|
||||
expect:
|
||||
- "после каждого переключения темы getComputedStyle(#pipeline-smoke).display == 'inline-block'"
|
||||
- "background-color и color #pipeline-smoke не зависят от темы"
|
||||
|
||||
- id: E2E-06
|
||||
title: "Отсутствие новых сетевых запросов"
|
||||
ac_refs: [AC-10]
|
||||
steps:
|
||||
- "register page.on('request') accumulator"
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait map idle (4000 ms)"
|
||||
expect:
|
||||
- "среди собранных URL нет /api/smoke, /api/et-008, /smoke/*"
|
||||
- "количество запросов сопоставимо с базовой загрузкой без ET-008 (± 5%)"
|
||||
|
||||
- id: E2E-07
|
||||
title: "Отсутствие console.error / console.warn от ET-008"
|
||||
ac_refs: [AC-11]
|
||||
steps:
|
||||
- "register page.on('console')"
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait 10000 ms"
|
||||
expect:
|
||||
- "0 console.error сообщений за время теста"
|
||||
- "0 console.warn сообщений, чей text содержит 'ET-008' или 'smoke'"
|
||||
|
||||
- id: E2E-08
|
||||
title: "ARIA-атрибуты выставлены корректно"
|
||||
ac_refs: [AC-07]
|
||||
steps:
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait 4000 ms"
|
||||
expect:
|
||||
- "getAttribute(#pipeline-smoke, 'aria-hidden') == 'true'"
|
||||
- "getAttribute(#pipeline-smoke, 'role') == 'presentation'"
|
||||
|
||||
- id: E2E-09
|
||||
title: "Клики проходят сквозь маркер"
|
||||
ac_refs: [AC-09]
|
||||
steps:
|
||||
- "navigate base_url + '?smoke=et-008'"
|
||||
- "wait 4000 ms"
|
||||
- "позиционировать курсор на координаты левого нижнего угла (10, 90vh)"
|
||||
- "click"
|
||||
expect:
|
||||
- "клик зарегистрирован картой (например, map.on('click') триггерится)"
|
||||
- "маркер не получил focus, не вызвал событий"
|
||||
|
||||
- id: E2E-10
|
||||
title: "Не ломает существующий набор E2E"
|
||||
ac_refs: [AC-13]
|
||||
steps:
|
||||
- "запустить полный набор tests/web/e2e/**"
|
||||
expect:
|
||||
- "все ранее зелёные тесты остаются зелёными"
|
||||
|
||||
coverage_matrix:
|
||||
AC-01: [UT-02, E2E-01]
|
||||
AC-02: [UT-03, IT-01, E2E-01]
|
||||
AC-03: [UT-01, UT-03, IT-02, E2E-02]
|
||||
AC-04: [UT-01, IT-03, E2E-03]
|
||||
AC-05: [IT-04, IT-06, E2E-04]
|
||||
AC-06: [IT-05]
|
||||
AC-07: [UT-02, E2E-08]
|
||||
AC-08: [E2E-05]
|
||||
AC-09: [E2E-09]
|
||||
AC-10: [E2E-06]
|
||||
AC-11: [E2E-07]
|
||||
AC-12: [UT-01]
|
||||
AC-13: [E2E-10]
|
||||
AC-14: "manual (revert + rerun E2E-10)"
|
||||
AC-15: [UT-04]
|
||||
|
||||
exit_criteria:
|
||||
- "Все unit-тесты UT-01..UT-04 зелёные"
|
||||
- "Все integration-тесты IT-01..IT-06 зелёные"
|
||||
- "Все E2E E2E-01..E2E-10 зелёные на test-окружении"
|
||||
- "Существующий набор UI/E2E не имеет регрессий"
|
||||
- "Покрытие AC ≥ 14 из 15 автотестами (AC-14 — ручная проверка отката)"
|
||||
- "git diff показывает изменения только в src/web/index.html, src/web/app.css, docs/work-items/ET-008/**, tests/web/**/pipeline-smoke*"
|
||||
230
docs/work-items/ET-008/04b-ui-test-cases.md
Normal file
230
docs/work-items/ET-008/04b-ui-test-cases.md
Normal file
@@ -0,0 +1,230 @@
|
||||
---
|
||||
type: ui-test-cases
|
||||
work_item_id: ET-008
|
||||
title: "UI Test Cases: Smoke test analyst integration"
|
||||
version: 1
|
||||
status: draft
|
||||
created_at: 2026-05-31
|
||||
updated_at: 2026-05-31
|
||||
authors:
|
||||
- "agent:analyst"
|
||||
depends_on:
|
||||
- "ET-008/02-trz.md"
|
||||
- "ET-008/03-acceptance-criteria.md"
|
||||
---
|
||||
|
||||
# UI Test Cases — ET-008: Smoke test analyst integration
|
||||
|
||||
Playwright-сценарии для визуального тестирования. Базовый URL для всех
|
||||
кейсов: `https://openclaw.mva154.duckdns.org/enduro/` (с добавлением
|
||||
параметра smoke там, где это указано в шагах).
|
||||
|
||||
Селекторы взяты из текущего `src/web/index.html` и проектируемой
|
||||
разметки нового маркера (`#pipeline-smoke`).
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-01 — Маркер скрыт при чистой загрузке (desktop)
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 4000
|
||||
3. check-visual: "В левом нижнем углу карты НЕТ маркера 'ET-008 ✓'. Привычный UI не изменился: компас, GPX, локация, рельеф, тема — сверху-справа; нижний #toolbar центрирован"
|
||||
4. screenshot: "et008-tc01-default-no-marker-desktop"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-02 — Маркер скрыт при чистой загрузке (mobile)
|
||||
|
||||
тип: ui
|
||||
viewport: mobile
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 4000
|
||||
3. check-visual: "В левом нижнем углу НЕТ маркера. Тулбар снизу и кнопки справа выглядят как обычно"
|
||||
4. screenshot: "et008-tc02-default-no-marker-mobile"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-03 — Маркер виден при ?smoke=et-008 (desktop)
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "В левом нижнем углу появился маленький полупрозрачный лейбл с текстом 'ET-008 ✓'. Высота ~16-20px, шрифт мелкий, фон тёмно-серый полупрозрачный"
|
||||
4. screenshot: "et008-tc03-smoke-marker-visible-desktop"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-04 — Маркер виден при #smoke=et-008 (desktop)
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/#smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "Маркер 'ET-008 ✓' в левом нижнем углу присутствует, как и в TC-UI-03"
|
||||
4. screenshot: "et008-tc04-smoke-marker-via-hash"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-05 — Маркер виден на мобильном
|
||||
|
||||
тип: ui
|
||||
viewport: mobile
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "Маркер виден в левом нижнем углу, не перекрывает #toolbar (тулбар центрирован, маркер слева). Размер маркера такой же, как на desktop"
|
||||
4. screenshot: "et008-tc05-smoke-marker-mobile"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-06 — Маркер скрыт при неверном значении
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-007
|
||||
2. wait: 4000
|
||||
3. check-visual: "В левом нижнем углу НЕТ маркера 'ET-008 ✓' (значение параметра не наш)"
|
||||
4. screenshot: "et008-tc06-wrong-value-hidden"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-07 — Маркер в светлой теме
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. click: "#btn-theme"
|
||||
4. wait: 2000
|
||||
5. check-visual: "Тема стала светлой (карта и панели светлые); маркер 'ET-008 ✓' в левом нижнем углу остался с тёмным полупрозрачным фоном, текст светлый — читается"
|
||||
6. screenshot: "et008-tc07-smoke-marker-light-theme"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-08 — Маркер в тёмной теме
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "Дефолтная тёмная тема: маркер 'ET-008 ✓' читается на тёмной карте за счёт собственного фона и контрастного текста"
|
||||
4. screenshot: "et008-tc08-smoke-marker-dark-theme"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-09 — Не конфликтует с атрибуцией MapLibre
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "Маркер слева внизу, атрибуция MapLibre справа внизу — они не перекрываются и не сливаются. Между ними чистая карта"
|
||||
4. screenshot: "et008-tc09-no-overlap-with-attrib"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-10 — Не конфликтует с открытым sheet
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. click: "#tb-route"
|
||||
4. wait: 1500
|
||||
5. check-visual: "Открылся bottom-sheet 'Маршрут'. Маркер либо полностью скрыт за sheet, либо виден только если sheet занимает не весь низ — никаких 'торчащих углов' маркера поверх sheet"
|
||||
6. screenshot: "et008-tc10-sheet-overlap-route"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-11 — Не ломает кнопки правой панели
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. check-visual: "Правая панель кнопок #map-controls-r (компас, GPX, локация, рельеф, тема) в прежнем виде; маркер слева внизу её не касается"
|
||||
4. screenshot: "et008-tc11-right-controls-intact"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-12 — Не ломает GPX-панель
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. click: "#tb-gpx"
|
||||
4. wait: 1500
|
||||
5. check-visual: "Bottom-sheet #sheet-gpx открыт, подсказка 'Нажми кнопку загрузки GPX...' читается. Маркер либо скрыт за sheet, либо виден слева и не пересекается с подсказкой"
|
||||
6. screenshot: "et008-tc12-gpx-sheet-with-smoke"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-13 — Не ломает поиск
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 4000
|
||||
3. click: "#tb-search"
|
||||
4. wait: 1500
|
||||
5. check-visual: "Поисковая панель/sheet открыт; маркер ET-008 слева внизу не мешает вводу и подсказкам"
|
||||
6. screenshot: "et008-tc13-search-with-smoke"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-14 — Маркер виден при первом кадре (no FOUC)
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/?smoke=et-008
|
||||
2. wait: 500
|
||||
3. screenshot: "et008-tc14-early-frame"
|
||||
4. wait: 4000
|
||||
5. screenshot: "et008-tc14-late-frame"
|
||||
6. check-visual: "На обоих скриншотах (~500ms и ~4500ms) маркер ET-008 ✓ присутствует и стабильно расположен; никакого мигания между ранним и поздним кадром"
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-15 — Регрессия: переключение темы без smoke (маркер всё ещё скрыт)
|
||||
|
||||
тип: ui
|
||||
viewport: desktop
|
||||
|
||||
шаги:
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 4000
|
||||
3. click: "#btn-theme"
|
||||
4. wait: 2000
|
||||
5. check-visual: "Тема переключилась; маркера 'ET-008 ✓' нет ни в одной из тем (поскольку smoke-параметра в URL не было)"
|
||||
6. screenshot: "et008-tc15-no-smoke-after-theme-toggle"
|
||||
Reference in New Issue
Block a user