Пишите UI-тесты на Playwright.
Прогоняйте их без Node.
Playwright-тестам нужны Node и npm-пакеты на каждом CI-агенте, и каждый прогон начинается с запуска раннера и браузера.
greedy один раз сохраняет зелёный прогон в кристалл — JSON-файл с шагами и селекторами из трассы Playwright. Дальше кристалл проигрывает Go-бинарник: подключается по CDP (протоколу Chrome DevTools) к горячему Chrome — уже запущенному браузеру, например в Selenoid, — и проходит шаги сам.
- Один бинарник на агентеНе нужно ставить и обновлять Node, npm-пакеты и браузеры Playwright.
- Без ожидания браузераChrome уже запущен, прогон сразу идёт по шагам.
- Без ИИ в прогонеКристалл — фиксированные шаги и селекторы: прогон не зависит от модели и не тратит токены.
go install greedy.guru/greedy/cmd/greedy@latest Как это работает
Что внутри кристалла
Не код теста, а то, что реально произошло в зелёном прогоне: шаги и селекторы из трассы Playwright. Операций семь. Пять crystallize снимает с трассы: navigate, wait, fill, click, text. Две пишутся руками: park оставляет вкладку на нужном URL, eval выполняет JavaScript на странице. Этого хватает на логин, регистрацию и главную.
{ "id": "example", "kind": "cdp", "version": 1, "steps": [
{ "op": "navigate", "url": "/login" },
{ "op": "wait", "selector": "[data-testid=login-username]", "timeout_ms": 5000 },
{ "op": "fill", "selector": "[data-testid=login-username]", "value": "user1" },
{ "op": "fill", "selector": "[data-testid=login-password]", "value": "password1" },
{ "op": "click", "selector": "[data-testid=login-submit]" },
{ "op": "text", "selector": "[data-testid=home-welcome]", "value": "Welcome, user1!" }
] }
Сокращено: без блока source и шага park. Целиком — crystals/login.example.json; рабочие кристаллы лежат рядом с тестами в tests-go-cdp. Проигрывает их тонкий CDP-клиент внутри бинарника — без chromedp и playwright-go.
Замеры
—
Это замер на статичной странице из репозитория. На живом SPA-приложении тот же логин идёт дольше. Таблица ниже — сколько занимает пачка логинов на одном Chrome по очереди и на нескольких параллельно, на Mac и на ферме Selenoid.
Сырые прогоны — bench-matrix.json, одиночный замер — bench.json.
Где запускать
greedy run не запускает Chrome сам — ему нужен адрес уже работающего браузера: флаг --cdp, переменная GREEDY_CDP или пул браузеров.
greedy run --cdp http://127.0.0.1:9222 \ --base-url https://your-app/ login.json
1 · В CI
Jenkins-джоба по очереди гоняет кристаллы login, logout, register и home. Chrome — контейнер Selenoid, который не закрывается между запусками: его держит демон на агенте, он же вызывает greedy run. Итоги уходят в Allure TestOps.
2 · На ферме браузеров
greedy run --parallel 5 или greedy bench берёт у пула пять свободных Chrome и гоняет кристаллы параллельно, по одному на браузер. Так сняты цифры фермы в таблице замеров.
3 · Локально
Один Chrome на своей машине — Chrome.app или Docker-образ с Chromium — и статичная страница из репозитория. Так снят замер из bench.json.
Кто решает, что кристалл готов
Кристалл не попадает в прогоны сам. Когда тест на Playwright набирает три зелёных прогона, его кейс в Allure TestOps уходит на ревью. Человек смотрит, что изменилось в шагах (greedy diff), и одобряет: greedy approve ставит кейсу статус Live и записывает JSON кристалла. Поменяли тест — кристалл снова идёт на ревью. Без ревью в Live переходит только логин (кейс 50707).
Все команды и флаги — в README.