From a7ae1d17386d470708cc0bab51b830c0dcb05e94 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Sat, 25 Apr 2026 09:06:00 +0000 Subject: [PATCH] chore(i18n): refresh uk translations --- docs/uk/reference/test.md | 93 ++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/docs/uk/reference/test.md b/docs/uk/reference/test.md index bfba8294f..63de64fcb 100644 --- a/docs/uk/reference/test.md +++ b/docs/uk/reference/test.md @@ -1,51 +1,52 @@ --- read_when: - Запуск або виправлення тестів -summary: Як локально запускати тести (vitest) і коли використовувати режими force/coverage +summary: Як запускати тести локально (`vitest`) і коли використовувати режими force/coverage title: Тести x-i18n: - generated_at: "2026-04-25T00:03:42Z" + generated_at: "2026-04-25T09:05:05Z" model: gpt-5.4 provider: openai - source_hash: 91009b51cee872f542a9aed0f882359c763cfb88722860eb8ef7deae434a89e7 + source_hash: dc138f5e3543b45598ab27b9f7bc9ce43979510b4508580a0cf95c43f97bac53 source_path: reference/test.md workflow: 15 --- -- Повний набір для тестування (с’юти, live, Docker): [Тестування](/uk/help/testing) +- Повний набір для тестування (набори, live, Docker): [Тестування](/uk/help/testing) -- `pnpm test:force`: Завершує будь-який gateway process, що залишився і тримає стандартний control port, а потім запускає повний набір Vitest з ізольованим port gateway, щоб server-тести не конфліктували із запущеним екземпляром. Використовуйте це, коли попередній запуск gateway залишив зайнятим port 18789. -- `pnpm test:coverage`: Запускає unit-набір із V8 coverage (через `vitest.unit.config.ts`). Це gate unit coverage для завантажених файлів, а не coverage всіх файлів у всьому репозиторії. Порогові значення: 70% для lines/functions/statements і 55% для branches. Оскільки `coverage.all` має значення false, gate вимірює файли, завантажені набором unit coverage, замість того щоб вважати кожен source file із розділених lane-ів непокритим. +- `pnpm test:force`: Завершує будь-який завислий процес gateway, що утримує типовий control port, а потім запускає повний набір Vitest з ізольованим портом gateway, щоб серверні тести не конфліктували із запущеним екземпляром. Використовуйте це, коли попередній запуск gateway залишив зайнятим порт 18789. +- `pnpm test:coverage`: Запускає набір unit-тестів із V8 coverage (через `vitest.unit.config.ts`). Це поріг unit coverage для завантажених файлів, а не coverage всіх файлів у всьому репозиторії. Пороги становлять 70% для lines/functions/statements і 55% для branches. Оскільки `coverage.all` має значення false, поріг вимірює файли, завантажені набором unit coverage, замість того щоб вважати всі файли вихідного коду з розбитих lane непокритими. - `pnpm test:coverage:changed`: Запускає unit coverage лише для файлів, змінених відносно `origin/main`. -- `pnpm test:changed`: розгортає змінені git paths у scoped Vitest lanes, коли diff зачіпає лише routable source/test files. Зміни config/setup і далі переходять до нативного запуску root projects, щоб зміни wiring за потреби повторно запускали ширший набір перевірок. -- `pnpm changed:lanes`: показує архітектурні lanes, що спрацьовують для diff відносно `origin/main`. -- `pnpm check:changed`: запускає розумний changed gate для diff відносно `origin/main`. Він запускає роботу core разом із core test lanes, роботу extension — з extension test lanes, зміни лише в тестах — лише з test typecheck/tests, розширює зміни в публічному Plugin SDK або plugin-contract до одного проходу валідації extension і залишає підвищення версії лише в release metadata на цільових перевірках version/config/root-dependency. -- `pnpm test`: маршрутизує явно вказані цілі file/directory через scoped Vitest lanes. Запуски без цілей використовують фіксовані shard groups і розгортаються до leaf configs для локального паралельного виконання; група extension завжди розгортається до shard configs для окремих extension, а не до одного гігантського процесу root-project. -- Повні запуски і запуски shard-ів extension оновлюють локальні дані часу в `.artifacts/vitest-shard-timings.json`; наступні запуски використовують ці таймінги, щоб балансувати повільні й швидкі shard-и. Установіть `OPENCLAW_TEST_PROJECTS_TIMINGS=0`, щоб ігнорувати локальний артефакт таймінгів. -- Вибрані test files `plugin-sdk` і `commands` тепер маршрутизуються через спеціальні легкі lanes, які залишають лише `test/setup.ts`, а випадки з важчим runtime залишаються у своїх наявних lanes. -- Вибрані helper source files `plugin-sdk` і `commands` також зіставляють `pnpm test:changed` з явними сусідніми tests у цих легких lanes, щоб невеликі зміни helper-ів не спричиняли повторний запуск важких наборів, що залежать від runtime. -- `auto-reply` тепер також розділяється на три окремі configs (`core`, `top-level`, `reply`), щоб harness reply не домінував над легшими tests верхнього рівня для status/token/helper. -- Базова конфігурація Vitest тепер за замовчуванням використовує `pool: "threads"` і `isolate: false`, а спільний неізольований runner увімкнено в усьому наборі configs репозиторію. +- `pnpm test:changed`: розгортає змінені git-шляхи в scoped Vitest lane, коли diff торкається лише routable файлів вихідного коду/тестів. Зміни config/setup, як і раніше, повертаються до нативного запуску root projects, щоб зміни в wiring за потреби повторно запускали ширший набір. +- `pnpm changed:lanes`: показує архітектурні lane, активовані diff відносно `origin/main`. +- `pnpm check:changed`: запускає розумний changed gate для diff відносно `origin/main`. Він запускає core-роботи з core test lanes, роботу extension з extension test lanes, зміни лише в тестах — тільки з test typecheck/tests, розширює зміни public Plugin SDK або plugin-contract до одного проходу валідації extension, а для підвищень версій лише в release metadata залишає цільові перевірки version/config/root-dependencies. +- `pnpm test`: маршрутизує явні цілі файлів/каталогів через scoped Vitest lanes. Запуски без цілей використовують фіксовані shard groups і розгортаються до leaf configs для локального паралельного виконання; група extension завжди розгортається до shard configs для кожного extension, а не до одного великого root-project process. +- Повні запуски та запуски shard для extension оновлюють локальні дані часу в `.artifacts/vitest-shard-timings.json`; наступні запуски використовують ці таймінги, щоб балансувати повільні й швидкі shard. Встановіть `OPENCLAW_TEST_PROJECTS_TIMINGS=0`, щоб ігнорувати локальний артефакт таймінгів. +- Вибрані тестові файли `plugin-sdk` і `commands` тепер маршрутизуються через окремі легкі lane, які залишають лише `test/setup.ts`, а випадки з важким runtime — у наявних lane. +- Вибрані допоміжні файли вихідного коду `plugin-sdk` і `commands` також зіставляють `pnpm test:changed` з явними сусідніми тестами в цих легких lane, щоб невеликі зміни в helper не перезапускали важкі набори, що спираються на runtime. +- `auto-reply` тепер також розділяється на три окремі config (`core`, `top-level`, `reply`), щоб harness для reply не домінував над легшими top-level тестами status/token/helper. +- Базова конфігурація Vitest тепер за замовчуванням використовує `pool: "threads"` і `isolate: false`, а спільний неізольований runner увімкнено в конфігураціях усього репозиторію. - `pnpm test:channels` запускає `vitest.channels.config.ts`. -- `pnpm test:extensions` і `pnpm test extensions` запускають усі shard-и extension/plugin. Важкі channel plugins, plugin browser і OpenAI запускаються як окремі shard-и; інші групи plugin-ів залишаються згрупованими. Використовуйте `pnpm test extensions/` для одного lane bundled plugin. -- `pnpm test:perf:imports`: вмикає звітність Vitest про тривалість імпортів і import-breakdown, при цьому й надалі використовує scoped lane routing для явно вказаних цілей file/directory. -- `pnpm test:perf:imports:changed`: те саме профілювання імпортів, але лише для файлів, змінених відносно `origin/main`. -- `pnpm test:perf:changed:bench -- --ref ` порівнює у режимі benchmark маршрутизований шлях changed-mode з нативним запуском root-project для того самого закоміченого git diff. -- `pnpm test:perf:changed:bench -- --worktree` порівнює у режимі benchmark поточний набір змін у worktree без попереднього коміту. -- `pnpm test:perf:profile:main`: записує CPU profile для main thread Vitest (`.artifacts/vitest-main-profile`). +- `pnpm test:extensions` і `pnpm test extensions` запускають усі shard extension/plugin. Важкі channel plugins, browser plugin і OpenAI виконуються як окремі shard; інші групи plugin залишаються згрупованими. Використовуйте `pnpm test extensions/` для одного lane зібраного plugin. +- `pnpm test:perf:imports`: вмикає звітність Vitest про import-duration та import-breakdown, водночас і далі використовуючи scoped lane routing для явних цілей файлів/каталогів. +- `pnpm test:perf:imports:changed`: таке саме профілювання import, але лише для файлів, змінених відносно `origin/main`. +- `pnpm test:perf:changed:bench -- --ref ` порівнює маршрут changed-mode з нативним запуском root-project для того самого закоміченого git diff. +- `pnpm test:perf:changed:bench -- --worktree` порівнює поточний набір змін у worktree без попереднього commit. +- `pnpm test:perf:profile:main`: записує CPU profile для головного потоку Vitest (`.artifacts/vitest-main-profile`). - `pnpm test:perf:profile:runner`: записує CPU + heap profiles для unit runner (`.artifacts/vitest-runner-profile`). -- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`: послідовно запускає кожен leaf config Vitest для повного набору і записує згруповані дані тривалості плюс JSON/log-артефакти для кожного config. Test Performance Agent використовує це як baseline перед спробою виправити повільні тести. -- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`: порівнює згруповані звіти після змін, спрямованих на продуктивність. -- Інтеграція gateway: вмикається через `OPENCLAW_TEST_INCLUDE_GATEWAY=1 pnpm test` або `pnpm test:gateway`. -- `pnpm test:e2e`: Запускає gateway end-to-end smoke-тести (pairing multi-instance WS/HTTP/node). За замовчуванням використовує `threads` + `isolate: false` з adaptive workers у `vitest.e2e.config.ts`; налаштовуйте через `OPENCLAW_E2E_WORKERS=` і встановлюйте `OPENCLAW_E2E_VERBOSE=1` для докладних логів. -- `pnpm test:live`: Запускає live-тести provider-ів (minimax/zai). Потрібні API keys і `LIVE=1` (або специфічне для provider `*_LIVE_TEST=1`), щоб зняти пропуск. -- `pnpm test:docker:all`: Один раз збирає спільний live-test image і Docker E2E image, а потім запускає Docker smoke lanes з `OPENCLAW_SKIP_DOCKER_BUILD=1` через зважений scheduler. `OPENCLAW_DOCKER_ALL_PARALLELISM=` керує слотами process і за замовчуванням дорівнює 10; `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=` керує tail pool, чутливим до provider, і також за замовчуванням дорівнює 10. Обмеження для важких lanes за замовчуванням: `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=6`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=8` і `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; використовуйте `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` або `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` для більших хостів. Запуски lanes за замовчуванням зсуваються на 2 секунди, щоб уникнути локальних сплесків create-операцій Docker daemon; перевизначайте через `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=`. Runner за замовчуванням виконує preflight для Docker, очищає застарілі OpenClaw E2E containers, виводить status активних lanes кожні 30 секунд і зберігає таймінги lanes у `.artifacts/docker-tests/lane-timings.json` для впорядкування за принципом longest-first у наступних запусках. Використовуйте `OPENCLAW_DOCKER_ALL_DRY_RUN=1`, щоб надрукувати маніфест lanes без запуску Docker, `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=` для налаштування виводу status, або `OPENCLAW_DOCKER_ALL_TIMINGS=0`, щоб вимкнути повторне використання таймінгів. Runner припиняє планування нових pooled lanes після першої помилки, якщо не встановлено `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`, і кожен lane має резервний тайм-аут 120 хвилин, який можна перевизначити через `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`; окремі live/tail lanes використовують жорсткіші обмеження для кожного lane. Логи для кожного lane записуються в `.artifacts/docker-tests//`. -- `pnpm test:docker:openwebui`: Запускає Dockerized OpenClaw + Open WebUI, входить через Open WebUI, перевіряє `/api/models`, а потім виконує реальний проксований чат через `/api/chat/completions`. Потребує придатного ключа live-моделі (наприклад, OpenAI у `~/.profile`), завантажує зовнішній image Open WebUI і не вважається настільки стабільним для CI, як звичайні unit/e2e suites. -- `pnpm test:docker:mcp-channels`: Запускає seeded Gateway container і другий client container, який запускає `openclaw mcp serve`, а потім перевіряє routed conversation discovery, читання transcript, metadata вкладень, поведінку live event queue, маршрутизацію вихідного надсилання та сповіщення про channel + permissions у стилі Claude через реальний міст stdio. Перевірка сповіщень Claude читає сирі stdio MCP frames безпосередньо, щоб smoke відображав те, що міст реально надсилає. +- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`: послідовно запускає кожну leaf config Vitest із повного набору та записує згруповані дані тривалості разом з JSON/log артефактами для кожної config. Агент продуктивності тестів використовує це як baseline перед спробами виправити повільні тести. +- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`: порівнює згруповані звіти після зміни, спрямованої на продуктивність. +- Інтеграція Gateway: вмикається через `OPENCLAW_TEST_INCLUDE_GATEWAY=1 pnpm test` або `pnpm test:gateway`. +- `pnpm test:e2e`: запускає наскрізні smoke-тести gateway (multi-instance WS/HTTP/node pairing). За замовчуванням використовує `threads` + `isolate: false` з адаптивною кількістю workers у `vitest.e2e.config.ts`; налаштовується через `OPENCLAW_E2E_WORKERS=`, а для докладних логів встановіть `OPENCLAW_E2E_VERBOSE=1`. +- `pnpm test:live`: запускає live-тести provider (minimax/zai). Потрібні API keys і `LIVE=1` (або provider-specific `*_LIVE_TEST=1`), щоб зняти пропуск. +- `pnpm test:docker:all`: один раз збирає спільний образ live-test і образ Docker E2E, а потім запускає Docker smoke lanes з `OPENCLAW_SKIP_DOCKER_BUILD=1` через weighted scheduler. `OPENCLAW_DOCKER_ALL_PARALLELISM=` керує слотами процесів і за замовчуванням дорівнює 10; `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=` керує provider-sensitive tail pool і за замовчуванням також дорівнює 10. Обмеження важких lane за замовчуванням: `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` і `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; обмеження provider за замовчуванням дають по одному heavy lane на provider через `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4` і `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4`. Для потужніших хостів використовуйте `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` або `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`. Запуски lane за замовчуванням розтягуються на 2 секунди, щоб уникнути локальних штормів створення в Docker daemon; перевизначайте через `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=`. Runner за замовчуванням виконує preflight Docker, очищає застарілі контейнери OpenClaw E2E, виводить статус активних lane кожні 30 секунд, ділить кеші CLI-інструментів provider між сумісними lane, один раз повторює transient live-provider збої за замовчуванням (`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=`) і зберігає таймінги lane в `.artifacts/docker-tests/lane-timings.json` для подальшого longest-first впорядкування. Використовуйте `OPENCLAW_DOCKER_ALL_DRY_RUN=1`, щоб вивести маніфест lane без запуску Docker, `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=` — щоб налаштувати виведення статусу, або `OPENCLAW_DOCKER_ALL_TIMINGS=0` — щоб вимкнути повторне використання таймінгів. Використовуйте `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip` для лише deterministic/local lane або `OPENCLAW_DOCKER_ALL_LIVE_MODE=only` лише для lane live-provider; package aliases: `pnpm test:docker:local:all` і `pnpm test:docker:live:all`. У режимі лише live основні й tail live lanes зливаються в один longest-first pool, щоб кошики provider могли разом пакувати завдання Claude, Codex і Gemini. Runner припиняє планувати нові pooled lanes після першої помилки, якщо не встановлено `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`, а кожен lane має резервний timeout у 120 хвилин, який можна перевизначити через `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`; для окремих live/tail lane використовуються жорсткіші обмеження на рівні lane. Команди налаштування Docker для CLI backend мають власний timeout через `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS` (за замовчуванням 180). Логи для кожного lane записуються в `.artifacts/docker-tests//`. +- Live Docker probes для CLI backend можна запускати як цільові lane, наприклад `pnpm test:docker:live-cli-backend:codex`, `pnpm test:docker:live-cli-backend:codex:resume` або `pnpm test:docker:live-cli-backend:codex:mcp`. Для Claude і Gemini є відповідні aliases `:resume` і `:mcp`. +- `pnpm test:docker:openwebui`: запускає Dockerized OpenClaw + Open WebUI, входить через Open WebUI, перевіряє `/api/models`, а потім виконує реальний проксійований чат через `/api/chat/completions`. Потрібен придатний ключ live model (наприклад, OpenAI у `~/.profile`), він завантажує зовнішній образ Open WebUI і не вважається стабільним у CI, як звичайні набори unit/e2e. +- `pnpm test:docker:mcp-channels`: запускає seeded контейнер Gateway і другий контейнер клієнта, який запускає `openclaw mcp serve`, а потім перевіряє routed conversation discovery, читання transcript, metadata attachment, поведінку live event queue, outbound send routing, а також сповіщення channel + permission у стилі Claude через реальний міст stdio. Перевірка сповіщень Claude читає сирі stdio MCP frames безпосередньо, щоб smoke відображав те, що міст насправді надсилає. ## Локальний PR gate -Для локальних перевірок перед злиттям PR/gate запускайте: +Для локальних перевірок перед злиттям/gate PR запустіть: - `pnpm check:changed` - `pnpm check` @@ -54,7 +55,7 @@ x-i18n: - `pnpm test` - `pnpm check:docs` -Якщо `pnpm test` дає flake на навантаженому хості, перезапустіть один раз, перш ніж вважати це регресією, а потім ізолюйте через `pnpm test `. Для хостів з обмеженнями пам’яті використовуйте: +Якщо `pnpm test` нестабільно спрацьовує на завантаженому хості, перезапустіть його один раз, перш ніж вважати це регресією, а потім ізолюйте через `pnpm test `. Для хостів з обмеженою пам’яттю використовуйте: - `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test` - `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed` @@ -67,12 +68,12 @@ x-i18n: - `source ~/.profile && pnpm tsx scripts/bench-model.ts --runs 10` - Необов’язкові env: `MINIMAX_API_KEY`, `MINIMAX_BASE_URL`, `MINIMAX_MODEL`, `ANTHROPIC_API_KEY` -- Prompt за замовчуванням: “Reply with a single word: ok. No punctuation or extra text.” +- Промпт за замовчуванням: “Відповідай одним словом: ok. Без розділових знаків чи додаткового тексту.” Останній запуск (2025-12-31, 20 запусків): -- median для minimax: 1279ms (мін. 1114, макс. 2431) -- median для opus: 2454ms (мін. 1224, макс. 3170) +- minimax median 1279ms (min 1114, max 2431) +- opus median 2454ms (min 1224, max 3170) ## Бенч запуску CLI @@ -95,41 +96,41 @@ x-i18n: - `pnpm tsx scripts/bench-cli-startup.ts --preset real --cpu-prof-dir .artifacts/cli-cpu` - `pnpm tsx scripts/bench-cli-startup.ts --json` -Preset-и: +Набори preset: - `startup`: `--version`, `--help`, `health`, `health --json`, `status --json`, `status` - `real`: `health`, `status`, `status --json`, `sessions`, `sessions --json`, `agents list --json`, `gateway status`, `gateway status --json`, `gateway health --json`, `config get gateway.port` -- `all`: обидва preset-и +- `all`: обидва preset Вивід містить `sampleCount`, avg, p50, p95, min/max, розподіл exit-code/signal і підсумки max RSS для кожної команди. Необов’язкові `--cpu-prof-dir` / `--heap-prof-dir` записують V8 profiles для кожного запуску, щоб вимірювання часу й збирання profile використовували той самий harness. -Домовленості щодо збереженого виводу: +Угоди для збереженого виводу: - `pnpm test:startup:bench:smoke` записує цільовий smoke-артефакт у `.artifacts/cli-startup-bench-smoke.json` -- `pnpm test:startup:bench:save` записує артефакт повного набору в `.artifacts/cli-startup-bench-all.json` з параметрами `runs=5` і `warmup=1` -- `pnpm test:startup:bench:update` оновлює закомічений baseline fixture у `test/fixtures/cli-startup-bench.json` з параметрами `runs=5` і `warmup=1` +- `pnpm test:startup:bench:save` записує артефакт повного набору в `.artifacts/cli-startup-bench-all.json` з `runs=5` і `warmup=1` +- `pnpm test:startup:bench:update` оновлює зафіксований у репозиторії baseline fixture у `test/fixtures/cli-startup-bench.json` з `runs=5` і `warmup=1` -Закомічений fixture: +Зафіксований у репозиторії fixture: - `test/fixtures/cli-startup-bench.json` - Оновлення: `pnpm test:startup:bench:update` - Порівняння поточних результатів із fixture: `pnpm test:startup:bench:check` -## E2E онбордингу (Docker) +## Onboarding E2E (Docker) -Docker необов’язковий; це потрібно лише для containerized smoke-тестів онбордингу. +Docker необов’язковий; це потрібно лише для containerized smoke-тестів onboarding. -Повний cold-start flow у чистому Linux container: +Повний потік cold-start у чистому Linux container: ```bash scripts/e2e/onboard-docker.sh ``` -Цей скрипт проводить інтерактивний wizard через pseudo-tty, перевіряє файли config/workspace/session, потім запускає gateway і виконує `openclaw health`. +Цей скрипт керує інтерактивним майстром через pseudo-tty, перевіряє файли config/workspace/session, потім запускає gateway і виконує `openclaw health`. -## QR import smoke (Docker) +## Smoke-тест QR import (Docker) -Гарантує, що підтримуваний helper QR runtime завантажується в підтримуваних Docker Node runtimes (Node 24 за замовчуванням, Node 22 сумісний): +Переконується, що підтримуваний helper середовища виконання QR завантажується в підтримуваних Docker Node runtimes (Node 24 за замовчуванням, Node 22 сумісний): ```bash pnpm test:docker:qr