617 lines
22 KiB
Markdown
617 lines
22 KiB
Markdown
# 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-агент*
|