auto-sync: 2026-05-13 00:20:01
This commit is contained in:
616
tasks/ui-test-skill/DEV_TASK.md
Normal file
616
tasks/ui-test-skill/DEV_TASK.md
Normal file
@@ -0,0 +1,616 @@
|
||||
# DEV TASK: UI/UX Auto-Testing Skill
|
||||
|
||||
**Статус:** Ready for dev
|
||||
**Проект:** ui-test-skill
|
||||
**BRD:** `tasks/ui-test-skill/BRD.md`
|
||||
|
||||
---
|
||||
|
||||
## Цель
|
||||
|
||||
> Скилл для автономного UI/UX тестирования веб-приложений: запуск Chromium через Playwright, выполнение сценариев, скриншоты, анализ через vision-модель, отчёт.
|
||||
|
||||
## Архитектура
|
||||
|
||||
Playwright (Node.js) запускает Chromium headless shell напрямую (без OpenClaw browser plugin). Скрипт-раннер читает тест-кейсы из markdown, выполняет шаги, делает скриншоты. Стрим анализирует скриншоты через `image` tool и формирует отчёт.
|
||||
|
||||
```
|
||||
SKILL.md (инструкции для Стрим)
|
||||
↓
|
||||
scripts/run_tests.js (раннер) ← TEST_CASES_*.md
|
||||
↓
|
||||
Playwright + Chromium headless shell
|
||||
↓
|
||||
screenshots/ → Стрим анализирует через image tool
|
||||
↓
|
||||
report.md (результат)
|
||||
```
|
||||
|
||||
## Стек / Зависимости
|
||||
|
||||
- Node.js (уже есть: v24.14.0)
|
||||
- Playwright (уже установлен: `npx playwright`)
|
||||
- Chromium headless shell (уже скачан: `~/.cache/ms-playwright/chromium_headless_shell-1223/`)
|
||||
- Системные .so библиотеки (уже извлечены: `~/chromium-libs/libs/`)
|
||||
|
||||
---
|
||||
|
||||
## Инфраструктура
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Workspace | `/home/node/.openclaw/workspace/skills/ui-test/` |
|
||||
| Chromium | `~/.cache/ms-playwright/chromium_headless_shell-1223/chrome-headless-shell-linux64/chrome-headless-shell` |
|
||||
| LD_LIBRARY_PATH | `~/chromium-libs/libs/usr/lib/x86_64-linux-gnu:~/chromium-libs/libs/lib/x86_64-linux-gnu` |
|
||||
| Screenshots | `tasks/{project}/reports/screenshots/` |
|
||||
| Reports | `tasks/{project}/reports/` |
|
||||
|
||||
---
|
||||
|
||||
## Файловая карта
|
||||
|
||||
| Действие | Файл | Ответственность |
|
||||
|----------|------|-----------------|
|
||||
| Создать | `skills/ui-test/SKILL.md` | Инструкции для Стрим |
|
||||
| Создать | `skills/ui-test/scripts/run_tests.js` | Раннер тестов (Playwright) |
|
||||
| Создать | `skills/ui-test/scripts/parse_testcases.js` | Парсер markdown тест-кейсов |
|
||||
| Создать | `skills/ui-test/scripts/package.json` | Зависимости (playwright) |
|
||||
| Создать | `skills/ui-test/scripts/health_check.js` | Проверка готовности окружения |
|
||||
| Создать | `skills/ui-test/examples/TEST_CASES_EXAMPLE.md` | Пример формата тест-кейсов |
|
||||
|
||||
---
|
||||
|
||||
## Задачи
|
||||
|
||||
### Task 1: Health check скрипт
|
||||
|
||||
**Файлы:**
|
||||
- Создать: `skills/ui-test/scripts/health_check.js`
|
||||
|
||||
**Шаги:**
|
||||
|
||||
- [ ] **1.1** Создать скрипт проверки окружения:
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
// health_check.js — проверяет что всё готово для UI-тестирования
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const CHROMIUM_PATH = path.join(
|
||||
process.env.HOME,
|
||||
'.cache/ms-playwright/chromium_headless_shell-1223/chrome-headless-shell-linux64/chrome-headless-shell'
|
||||
);
|
||||
|
||||
const LIB_PATH = path.join(process.env.HOME, 'chromium-libs/libs/usr/lib/x86_64-linux-gnu');
|
||||
|
||||
const checks = [];
|
||||
|
||||
// 1. Chromium binary exists
|
||||
if (fs.existsSync(CHROMIUM_PATH)) {
|
||||
checks.push({ name: 'Chromium binary', status: 'OK' });
|
||||
} else {
|
||||
checks.push({ name: 'Chromium binary', status: 'FAIL', detail: `Not found: ${CHROMIUM_PATH}` });
|
||||
}
|
||||
|
||||
// 2. Libraries exist
|
||||
if (fs.existsSync(LIB_PATH)) {
|
||||
const libs = fs.readdirSync(LIB_PATH).filter(f => f.endsWith('.so') || f.includes('.so.'));
|
||||
checks.push({ name: 'Shared libraries', status: libs.length > 20 ? 'OK' : 'FAIL', detail: `${libs.length} .so files` });
|
||||
} else {
|
||||
checks.push({ name: 'Shared libraries', status: 'FAIL', detail: `Not found: ${LIB_PATH}` });
|
||||
}
|
||||
|
||||
// 3. Chromium launches
|
||||
try {
|
||||
const env = { ...process.env, LD_LIBRARY_PATH: `${LIB_PATH}:${path.join(process.env.HOME, 'chromium-libs/libs/lib/x86_64-linux-gnu')}` };
|
||||
execSync(`"${CHROMIUM_PATH}" --headless --disable-gpu --no-sandbox --dump-dom about:blank`, { env, timeout: 10000, stdio: 'pipe' });
|
||||
checks.push({ name: 'Chromium launches', status: 'OK' });
|
||||
} catch (e) {
|
||||
checks.push({ name: 'Chromium launches', status: 'FAIL', detail: e.message.slice(0, 100) });
|
||||
}
|
||||
|
||||
// 4. Playwright available
|
||||
try {
|
||||
require('playwright-core');
|
||||
checks.push({ name: 'Playwright module', status: 'OK' });
|
||||
} catch {
|
||||
checks.push({ name: 'Playwright module', status: 'FAIL', detail: 'npm install playwright-core needed' });
|
||||
}
|
||||
|
||||
// Output
|
||||
const allOk = checks.every(c => c.status === 'OK');
|
||||
console.log(allOk ? '✅ All checks passed' : '❌ Some checks failed');
|
||||
checks.forEach(c => {
|
||||
const icon = c.status === 'OK' ? '✓' : '✗';
|
||||
console.log(` ${icon} ${c.name}: ${c.status}${c.detail ? ' — ' + c.detail : ''}`);
|
||||
});
|
||||
process.exit(allOk ? 0 : 1);
|
||||
```
|
||||
|
||||
- [ ] **1.2** Проверить:
|
||||
|
||||
```bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts && node health_check.js
|
||||
# Ожидаемый результат: ✅ All checks passed
|
||||
```
|
||||
|
||||
**Критерий готовности:** Скрипт запускается, все 4 проверки зелёные.
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Парсер тест-кейсов
|
||||
|
||||
**Файлы:**
|
||||
- Создать: `skills/ui-test/scripts/parse_testcases.js`
|
||||
|
||||
**Шаги:**
|
||||
|
||||
- [ ] **2.1** Создать парсер markdown → JSON:
|
||||
|
||||
Формат входного markdown:
|
||||
```markdown
|
||||
### TC-XX — Название теста
|
||||
**Тип:** ui
|
||||
**Viewport:** desktop | mobile | both
|
||||
**URL:** https://example.com/
|
||||
|
||||
**Шаги:**
|
||||
1. navigate: {url}
|
||||
2. wait: 3000
|
||||
3. click: "#button-id"
|
||||
4. screenshot: "step-name"
|
||||
5. check-visual: "Описание что проверяем"
|
||||
|
||||
**Визуальные критерии:**
|
||||
- Нет пустых белых/чёрных областей
|
||||
- Текст читаем
|
||||
```
|
||||
|
||||
Формат выхода (JSON):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "TC-XX",
|
||||
"name": "Название теста",
|
||||
"type": "ui",
|
||||
"viewport": "both",
|
||||
"url": "https://example.com/",
|
||||
"steps": [
|
||||
{ "action": "navigate", "value": "{url}" },
|
||||
{ "action": "wait", "value": 3000 },
|
||||
{ "action": "click", "value": "#button-id" },
|
||||
{ "action": "screenshot", "value": "step-name" },
|
||||
{ "action": "check-visual", "value": "Описание что проверяем" }
|
||||
],
|
||||
"criteria": ["Нет пустых белых/чёрных областей", "Текст читаем"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Парсер должен:
|
||||
- Читать файл markdown
|
||||
- Извлекать только тест-кейсы с `**Тип:** ui`
|
||||
- Игнорировать тесты без типа `ui` (они для curl/grep)
|
||||
- Выводить JSON в stdout
|
||||
|
||||
```bash
|
||||
node parse_testcases.js /path/to/TEST_CASES.md
|
||||
```
|
||||
|
||||
- [ ] **2.2** Проверить на примере:
|
||||
|
||||
```bash
|
||||
node parse_testcases.js ../examples/TEST_CASES_EXAMPLE.md | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.length + ' tests parsed')"
|
||||
# Ожидаемый результат: N tests parsed (N > 0)
|
||||
```
|
||||
|
||||
**Критерий готовности:** Парсер корректно извлекает UI тест-кейсы из markdown в JSON.
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Раннер тестов (основной скрипт)
|
||||
|
||||
**Файлы:**
|
||||
- Создать: `skills/ui-test/scripts/run_tests.js`
|
||||
- Создать: `skills/ui-test/scripts/package.json`
|
||||
|
||||
**Шаги:**
|
||||
|
||||
- [ ] **3.1** Создать `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ui-test-runner",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"playwright-core": "^1.52.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **3.2** Установить зависимости:
|
||||
|
||||
```bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts && npm install
|
||||
```
|
||||
|
||||
- [ ] **3.3** Создать `run_tests.js`:
|
||||
|
||||
Скрипт должен:
|
||||
1. Принимать аргументы: `node run_tests.js <test-cases.md> <output-dir>`
|
||||
2. Парсить тест-кейсы через `parse_testcases.js`
|
||||
3. Запускать Chromium через playwright-core с правильным `LD_LIBRARY_PATH`
|
||||
4. Для каждого теста:
|
||||
- Установить viewport (desktop: 1280×720, mobile: 375×812)
|
||||
- Выполнить шаги: navigate, wait, click, scroll, screenshot
|
||||
- Сохранить скриншоты в `<output-dir>/screenshots/`
|
||||
5. Сформировать JSON-отчёт: `<output-dir>/results.json`
|
||||
|
||||
Ключевые моменты реализации:
|
||||
|
||||
```javascript
|
||||
const { chromium } = require('playwright-core');
|
||||
const path = require('path');
|
||||
|
||||
const CHROMIUM_PATH = path.join(
|
||||
process.env.HOME,
|
||||
'.cache/ms-playwright/chromium_headless_shell-1223/chrome-headless-shell-linux64/chrome-headless-shell'
|
||||
);
|
||||
|
||||
const LIB_PATH = [
|
||||
path.join(process.env.HOME, 'chromium-libs/libs/usr/lib/x86_64-linux-gnu'),
|
||||
path.join(process.env.HOME, 'chromium-libs/libs/lib/x86_64-linux-gnu')
|
||||
].join(':');
|
||||
|
||||
async function launchBrowser(viewport) {
|
||||
const browser = await chromium.launch({
|
||||
executablePath: CHROMIUM_PATH,
|
||||
headless: true,
|
||||
args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],
|
||||
env: { ...process.env, LD_LIBRARY_PATH: LIB_PATH }
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: viewport === 'mobile'
|
||||
? { width: 375, height: 812 }
|
||||
: { width: 1280, height: 720 },
|
||||
deviceScaleFactor: viewport === 'mobile' ? 2 : 1,
|
||||
isMobile: viewport === 'mobile',
|
||||
userAgent: viewport === 'mobile'
|
||||
? 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15'
|
||||
: undefined
|
||||
});
|
||||
return { browser, context };
|
||||
}
|
||||
|
||||
async function executeStep(page, step, screenshotDir, testId) {
|
||||
switch (step.action) {
|
||||
case 'navigate':
|
||||
await page.goto(step.value, { waitUntil: 'networkidle', timeout: 30000 });
|
||||
break;
|
||||
case 'wait':
|
||||
await page.waitForTimeout(parseInt(step.value));
|
||||
break;
|
||||
case 'click':
|
||||
await page.click(step.value, { timeout: 5000 });
|
||||
break;
|
||||
case 'scroll':
|
||||
await page.evaluate((px) => window.scrollBy(0, parseInt(px)), step.value);
|
||||
break;
|
||||
case 'screenshot':
|
||||
const filename = `${testId}-${step.value}.png`;
|
||||
await page.screenshot({ path: path.join(screenshotDir, filename), fullPage: false });
|
||||
return { screenshot: filename };
|
||||
break;
|
||||
case 'check-visual':
|
||||
// Скриншот для визуальной проверки (будет анализироваться Стрим через image tool)
|
||||
const checkFile = `${testId}-check-${Date.now()}.png`;
|
||||
await page.screenshot({ path: path.join(screenshotDir, checkFile), fullPage: false });
|
||||
return { screenshot: checkFile, checkDescription: step.value };
|
||||
break;
|
||||
case 'resize':
|
||||
const [w, h] = step.value.split('x').map(Number);
|
||||
await page.setViewportSize({ width: w, height: h });
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
Формат `results.json`:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-05-12T21:00:00Z",
|
||||
"testFile": "TEST_CASES_TERRAIN.md",
|
||||
"results": [
|
||||
{
|
||||
"id": "TC-07",
|
||||
"name": "Кнопка terrain",
|
||||
"viewport": "desktop",
|
||||
"status": "completed",
|
||||
"screenshots": ["TC-07-desktop-initial.png", "TC-07-desktop-after-click.png"],
|
||||
"checks": [
|
||||
{ "description": "Попап виден", "screenshot": "TC-07-desktop-check-1715...png" }
|
||||
],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **3.4** Проверить на тестовом URL:
|
||||
|
||||
```bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts
|
||||
node run_tests.js ../examples/TEST_CASES_EXAMPLE.md /tmp/ui-test-output
|
||||
ls /tmp/ui-test-output/screenshots/
|
||||
cat /tmp/ui-test-output/results.json | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.results.length + ' tests completed')"
|
||||
```
|
||||
|
||||
**Критерий готовности:** Раннер запускает Chromium, выполняет шаги, сохраняет скриншоты и results.json.
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Пример тест-кейсов
|
||||
|
||||
**Файлы:**
|
||||
- Создать: `skills/ui-test/examples/TEST_CASES_EXAMPLE.md`
|
||||
|
||||
**Шаги:**
|
||||
|
||||
- [ ] **4.1** Создать пример с 3 тест-кейсами для enduro-trails:
|
||||
|
||||
```markdown
|
||||
# UI Test Cases: Enduro Trails (Example)
|
||||
|
||||
### TC-UI-01 — Загрузка карты
|
||||
**Тип:** ui
|
||||
**Viewport:** both
|
||||
**URL:** https://openclaw.mva154.duckdns.org/enduro/
|
||||
|
||||
**Шаги:**
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 3000
|
||||
3. screenshot: "initial-load"
|
||||
4. check-visual: "Карта загружена, тайлы отрисованы, нет белых пустот. Toolbar виден внизу."
|
||||
|
||||
**Визуальные критерии:**
|
||||
- Карта занимает весь экран
|
||||
- Нет белых/серых незагруженных областей
|
||||
- Toolbar с кнопками виден
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-02 — Переключение темы
|
||||
**Тип:** ui
|
||||
**Viewport:** desktop
|
||||
**URL:** https://openclaw.mva154.duckdns.org/enduro/
|
||||
|
||||
**Шаги:**
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 3000
|
||||
3. screenshot: "before-theme-switch"
|
||||
4. click: "#theme-toggle"
|
||||
5. wait: 2000
|
||||
6. screenshot: "after-theme-switch"
|
||||
7. check-visual: "Тема переключилась: фон карты изменился (светлый↔тёмный), кнопки toolbar сменили цвет"
|
||||
|
||||
**Визуальные критерии:**
|
||||
- Скриншоты before/after визуально отличаются
|
||||
- Карта не пустая после переключения
|
||||
- Toolbar адаптировался к новой теме
|
||||
|
||||
---
|
||||
|
||||
### TC-UI-03 — Terrain попап (мобильный)
|
||||
**Тип:** ui
|
||||
**Viewport:** mobile
|
||||
**URL:** https://openclaw.mva154.duckdns.org/enduro/
|
||||
|
||||
**Шаги:**
|
||||
1. navigate: https://openclaw.mva154.duckdns.org/enduro/
|
||||
2. wait: 3000
|
||||
3. click: "#terrain-btn"
|
||||
4. wait: 1000
|
||||
5. screenshot: "terrain-popup-mobile"
|
||||
6. check-visual: "Попап terrain виден полностью, не обрезан снизу. Чекбоксы кликабельного размера (>44px)."
|
||||
|
||||
**Визуальные критерии:**
|
||||
- Попап не выходит за границы экрана
|
||||
- Чекбоксы достаточного размера для тапа
|
||||
- Текст читаем
|
||||
```
|
||||
|
||||
**Критерий готовности:** Файл существует, парсер корректно извлекает 3 теста.
|
||||
|
||||
---
|
||||
|
||||
### Task 5: SKILL.md
|
||||
|
||||
**Файлы:**
|
||||
- Создать: `skills/ui-test/SKILL.md`
|
||||
|
||||
**Шаги:**
|
||||
|
||||
- [ ] **5.1** Создать SKILL.md с полными инструкциями:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: ui-test
|
||||
description: "Автономное UI/UX тестирование веб-приложений через Playwright + vision analysis. Запуск тестов, скриншоты, визуальный анализ, отчёт."
|
||||
---
|
||||
|
||||
# UI/UX Auto-Testing Skill
|
||||
|
||||
## Когда использовать
|
||||
|
||||
- После деплоя новой фичи — проверить что ничего не сломалось
|
||||
- По запросу Славы — "проверь UI"
|
||||
- Перед релизом фазы — регрессионный прогон всех тестов
|
||||
|
||||
## Порядок тестирования
|
||||
|
||||
1. Unit/integration тесты (curl/grep, API)
|
||||
2. UI/UX тесты (этот скилл) — ПОСЛЕДНИМИ
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
### 1. Проверить готовность
|
||||
|
||||
\`\`\`bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts && node health_check.js
|
||||
\`\`\`
|
||||
|
||||
Все проверки должны быть ✅. Если нет — см. раздел "Установка".
|
||||
|
||||
### 2. Запустить тесты
|
||||
|
||||
\`\`\`bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts
|
||||
node run_tests.js /path/to/TEST_CASES.md /path/to/output-dir
|
||||
\`\`\`
|
||||
|
||||
Пример для enduro-trails:
|
||||
\`\`\`bash
|
||||
node run_tests.js \
|
||||
/home/node/.openclaw/workspace/tasks/enduro-trails/TEST_CASES_UI.md \
|
||||
/home/node/.openclaw/workspace/tasks/enduro-trails/reports
|
||||
\`\`\`
|
||||
|
||||
### 3. Проанализировать скриншоты
|
||||
|
||||
После запуска раннера — проанализировать скриншоты через `image` tool:
|
||||
|
||||
Для каждого check из `results.json`:
|
||||
- Открыть скриншот через image tool
|
||||
- Промпт: "Ты — QA-инженер. Проанализируй скриншот. {check.description}. Есть ли визуальные проблемы? Ответь: pass/fail + описание проблем если есть."
|
||||
- Записать результат в отчёт
|
||||
|
||||
### 4. Сформировать отчёт
|
||||
|
||||
Создать `reports/ui-test-YYYY-MM-DD.md`:
|
||||
|
||||
\`\`\`markdown
|
||||
# UI Test Report: {project}
|
||||
**Дата:** {date}
|
||||
**Тесты:** {total} | ✅ {passed} | ❌ {failed}
|
||||
|
||||
| # | Тест | Desktop | Mobile | Проблемы |
|
||||
|---|------|---------|--------|----------|
|
||||
| TC-XX | Название | ✅/❌ | ✅/❌ | описание |
|
||||
\`\`\`
|
||||
|
||||
### 5. Отправить результат Славе
|
||||
|
||||
Всегда отправлять результат — даже если всё зелёное.
|
||||
|
||||
## Формат тест-кейсов
|
||||
|
||||
Файл: `TEST_CASES_UI.md` (или секция в общем TEST_CASES файле)
|
||||
|
||||
\`\`\`markdown
|
||||
### TC-XX — Название
|
||||
**Тип:** ui
|
||||
**Viewport:** desktop | mobile | both
|
||||
**URL:** https://...
|
||||
|
||||
**Шаги:**
|
||||
1. navigate: {url}
|
||||
2. wait: {ms}
|
||||
3. click: "{selector}"
|
||||
4. scroll: {pixels}
|
||||
5. resize: {width}x{height}
|
||||
6. screenshot: "{name}"
|
||||
7. check-visual: "{описание проверки}"
|
||||
|
||||
**Визуальные критерии:**
|
||||
- Критерий 1
|
||||
- Критерий 2
|
||||
\`\`\`
|
||||
|
||||
### Доступные действия
|
||||
|
||||
| Действие | Формат | Описание |
|
||||
|----------|--------|----------|
|
||||
| navigate | `navigate: {url}` | Перейти на URL |
|
||||
| wait | `wait: {ms}` | Подождать N миллисекунд |
|
||||
| click | `click: "{selector}"` | Кликнуть по CSS-селектору |
|
||||
| scroll | `scroll: {pixels}` | Прокрутить вниз на N пикселей |
|
||||
| resize | `resize: {w}x{h}` | Изменить viewport |
|
||||
| screenshot | `screenshot: "{name}"` | Сделать скриншот |
|
||||
| check-visual | `check-visual: "{desc}"` | Скриншот + пометка для vision-анализа |
|
||||
|
||||
## Установка (если health_check падает)
|
||||
|
||||
### Chromium headless shell
|
||||
\`\`\`bash
|
||||
npx --yes playwright install chromium
|
||||
\`\`\`
|
||||
|
||||
### Системные библиотеки (без root)
|
||||
\`\`\`bash
|
||||
# Библиотеки уже извлечены в ~/chromium-libs/libs/
|
||||
# Если нет — скачать deb-пакеты и извлечь через dpkg-deb:
|
||||
mkdir -p ~/chromium-libs && cd ~/chromium-libs
|
||||
# ... (список URL в BRD)
|
||||
for deb in *.deb; do dpkg-deb -x "$deb" libs/; done
|
||||
\`\`\`
|
||||
|
||||
### Node.js зависимости
|
||||
\`\`\`bash
|
||||
cd /home/node/.openclaw/workspace/skills/ui-test/scripts && npm install
|
||||
\`\`\`
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Chromium headless — нет GPU рендеринга (WebGL карты могут выглядеть иначе)
|
||||
- Vision-анализ субъективен — false positives возможны
|
||||
- MapLibre тайлы грузятся по сети — нужен wait 3-5 сек после navigate
|
||||
- Мобильный viewport эмулирует размер, но не touch-события
|
||||
```
|
||||
|
||||
**Критерий готовности:** SKILL.md содержит полные инструкции: быстрый старт, формат тестов, установка, ограничения.
|
||||
|
||||
---
|
||||
|
||||
## Проверка (Acceptance)
|
||||
|
||||
| # | Проверка | Команда / Действие | Ожидаемый результат |
|
||||
|---|----------|-------------------|---------------------|
|
||||
| 1 | Health check | `node health_check.js` | ✅ All checks passed |
|
||||
| 2 | Парсер | `node parse_testcases.js examples/TEST_CASES_EXAMPLE.md` | Валидный JSON, 3 теста |
|
||||
| 3 | Раннер desktop | `node run_tests.js examples/TEST_CASES_EXAMPLE.md /tmp/test1` | screenshots/ содержит PNG файлы |
|
||||
| 4 | Раннер mobile | Тест с viewport: mobile | Скриншот 375×812 |
|
||||
| 5 | results.json | `cat /tmp/test1/results.json` | Валидный JSON со статусами |
|
||||
| 6 | Реальный URL | Тест на openclaw.mva154.duckdns.org/enduro/ | Скриншот с картой (не пустой) |
|
||||
|
||||
---
|
||||
|
||||
## Ограничения и контекст
|
||||
|
||||
- ⚠️ Chromium запускается с `LD_LIBRARY_PATH` — обязательно передавать env в `chromium.launch()`
|
||||
- ⚠️ `--no-sandbox` обязателен (контейнер без root)
|
||||
- ⚠️ `--disable-dev-shm-usage` — /dev/shm маленький в контейнере
|
||||
- ⚠️ MapLibre карта грузит тайлы по сети — wait минимум 3000ms после navigate
|
||||
- ⚠️ Headless shell не поддерживает `--headless=new` — использовать просто `headless: true`
|
||||
- 🚫 НЕ использовать OpenClaw browser tool — работаем через Playwright напрямую
|
||||
- 🚫 НЕ устанавливать ничего через apt/sudo — всё уже есть
|
||||
|
||||
---
|
||||
|
||||
## Деплой-чеклист
|
||||
|
||||
- [ ] `scripts/health_check.js` — работает
|
||||
- [ ] `scripts/parse_testcases.js` — парсит markdown
|
||||
- [ ] `scripts/run_tests.js` — запускает тесты, делает скриншоты
|
||||
- [ ] `scripts/package.json` + `node_modules/` — playwright-core установлен
|
||||
- [ ] `examples/TEST_CASES_EXAMPLE.md` — пример тестов
|
||||
- [ ] `SKILL.md` — полные инструкции
|
||||
- [ ] Тест на реальном URL — скриншот не пустой
|
||||
|
||||
---
|
||||
|
||||
*Создано: 2026-05-12 | Автор ТЗ: Стрим | Исполнитель: Dev-агент*
|
||||
Reference in New Issue
Block a user