mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-20 17:40:59 +03:00
feat(web-test): runner v1.11 — -- separator + spec §6.1
В CLI раннера всё после `--` собирается в массив hookArgs и
передаётся в инфра-хуки prepare/cleanup без интерпретации со
стороны раннера. Сигнатура расширена до { hookArgs, log, config }:
log — структурированный вывод раннера, config — разобранный
webtest.config.mjs. Шаблон «всё после `--` принадлежит вложенному
инструменту» — стандартная shell-конвенция (npm, cargo, pytest).
Спека §6 обновлена под новую сигнатуру, §6.1 закрепляет контракт
`--` ↔ hookArgs с примером. Help-строка раннера упоминает
разделитель.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
// web-test run v1.10 — CLI runner for 1C web client automation
|
// web-test run v1.11 — CLI runner for 1C web client automation
|
||||||
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
/**
|
/**
|
||||||
* CLI runner for 1C web client automation.
|
* CLI runner for 1C web client automation.
|
||||||
@@ -356,11 +356,18 @@ function cmdStatus() {
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function cmdTest(rawArgs) {
|
async function cmdTest(rawArgs) {
|
||||||
|
// Split off everything after `--` — those args belong to user-defined hooks
|
||||||
|
// (see spec §6: "all arguments after `--` are forwarded verbatim to _hooks.mjs
|
||||||
|
// via the hookArgs field; the runner does not interpret them").
|
||||||
|
const sepIdx = rawArgs.indexOf('--');
|
||||||
|
const ownArgs = sepIdx >= 0 ? rawArgs.slice(0, sepIdx) : rawArgs;
|
||||||
|
const hookArgs = sepIdx >= 0 ? rawArgs.slice(sepIdx + 1) : [];
|
||||||
|
|
||||||
// Parse flags
|
// Parse flags
|
||||||
const opts = { bail: false, retry: 0, timeout: 30000, report: null, format: 'json', screenshot: null, reportDir: null, record: false };
|
const opts = { bail: false, retry: 0, timeout: 30000, report: null, format: 'json', screenshot: null, reportDir: null, record: false };
|
||||||
let tags = null, grep = null;
|
let tags = null, grep = null;
|
||||||
const positional = [];
|
const positional = [];
|
||||||
for (const a of rawArgs) {
|
for (const a of ownArgs) {
|
||||||
if (a.startsWith('--tags=')) tags = a.slice(7).split(',');
|
if (a.startsWith('--tags=')) tags = a.slice(7).split(',');
|
||||||
else if (a.startsWith('--grep=')) grep = new RegExp(a.slice(7), 'i');
|
else if (a.startsWith('--grep=')) grep = new RegExp(a.slice(7), 'i');
|
||||||
else if (a === '--bail') opts.bail = true;
|
else if (a === '--bail') opts.bail = true;
|
||||||
@@ -417,8 +424,8 @@ async function cmdTest(rawArgs) {
|
|||||||
|
|
||||||
// Apply config defaults (CLI flags override)
|
// Apply config defaults (CLI flags override)
|
||||||
if (!tags && config.tags) tags = config.tags;
|
if (!tags && config.tags) tags = config.tags;
|
||||||
opts.timeout = rawArgs.some(a => a.startsWith('--timeout=')) ? opts.timeout : (config.timeout || opts.timeout);
|
opts.timeout = ownArgs.some(a => a.startsWith('--timeout=')) ? opts.timeout : (config.timeout || opts.timeout);
|
||||||
opts.retry = rawArgs.some(a => a.startsWith('--retry=')) ? opts.retry : (config.retries || opts.retry);
|
opts.retry = ownArgs.some(a => a.startsWith('--retry=')) ? opts.retry : (config.retries || opts.retry);
|
||||||
opts.record = opts.record || !!config.record;
|
opts.record = opts.record || !!config.record;
|
||||||
opts.screenshot = opts.screenshot || config.screenshot || 'on-failure';
|
opts.screenshot = opts.screenshot || config.screenshot || 'on-failure';
|
||||||
if (!['on-failure', 'every-step', 'off'].includes(opts.screenshot)) {
|
if (!['on-failure', 'every-step', 'off'].includes(opts.screenshot)) {
|
||||||
@@ -498,7 +505,10 @@ async function cmdTest(rawArgs) {
|
|||||||
let passCount = 0, failCount = 0, skipCount = 0;
|
let passCount = 0, failCount = 0, skipCount = 0;
|
||||||
|
|
||||||
// Prepare: infrastructure hooks (no browser)
|
// Prepare: infrastructure hooks (no browser)
|
||||||
if (hooks.prepare) await hooks.prepare();
|
// Spec §6: prepare receives { hookArgs, log, config } — see ExternalDoc.
|
||||||
|
const hookLog = (...a) => W.write(`[hooks] ${a.map(String).join(' ')}\n`);
|
||||||
|
const hookEnv = { hookArgs, log: hookLog, config };
|
||||||
|
if (hooks.prepare) await hooks.prepare(hookEnv);
|
||||||
|
|
||||||
// Lazy context creation: ensures the named browser context exists, creating it on first request.
|
// Lazy context creation: ensures the named browser context exists, creating it on first request.
|
||||||
async function ensureContext(name) {
|
async function ensureContext(name) {
|
||||||
@@ -692,8 +702,8 @@ async function cmdTest(rawArgs) {
|
|||||||
} finally {
|
} finally {
|
||||||
// Disconnect
|
// Disconnect
|
||||||
try { await browser.disconnect(); } catch {}
|
try { await browser.disconnect(); } catch {}
|
||||||
// Cleanup: infrastructure hooks
|
// Cleanup: infrastructure hooks (same signature as prepare)
|
||||||
if (hooks.cleanup) try { await hooks.cleanup(); } catch {}
|
if (hooks.cleanup) try { await hooks.cleanup(hookEnv); } catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const finishedAt = new Date().toISOString();
|
const finishedAt = new Date().toISOString();
|
||||||
@@ -1002,5 +1012,8 @@ Options for test:
|
|||||||
--report-dir=path Directory for screenshots and other artifacts
|
--report-dir=path Directory for screenshots and other artifacts
|
||||||
--screenshot=mode on-failure (default) | every-step | off
|
--screenshot=mode on-failure (default) | every-step | off
|
||||||
--format=fmt json (default) | allure | junit
|
--format=fmt json (default) | allure | junit
|
||||||
--record Record video for each test (mp4 in report-dir)`);
|
--record Record video for each test (mp4 in report-dir)
|
||||||
|
-- <hook-args...> Everything after \`--\` is forwarded to _hooks.mjs
|
||||||
|
prepare/cleanup as hookArgs (runner does not parse it).
|
||||||
|
Example: ... tests/web-test/ -- --rebuild-stand`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,8 +269,15 @@ assert.noErrors(state, msg)
|
|||||||
### Два уровня
|
### Два уровня
|
||||||
|
|
||||||
**Инфраструктурный уровень** (без браузера):
|
**Инфраструктурный уровень** (без браузера):
|
||||||
- `prepare()` -- до подключения (восстановление БД, публикация, загрузка данных)
|
- `prepare({ hookArgs, log, config })` -- до подключения (восстановление БД, публикация, загрузка данных)
|
||||||
- `cleanup()` -- после отключения (удаление публикации, очистка)
|
- `cleanup({ hookArgs, log, config })` -- после отключения (удаление публикации, очистка)
|
||||||
|
|
||||||
|
Поля:
|
||||||
|
- `hookArgs: string[]` -- всё что в командной строке передано после разделителя `--`,
|
||||||
|
без интерпретации со стороны раннера. Хук парсит сам (см. §6.1 ниже).
|
||||||
|
- `log: (...args) => void` -- функция логирования раннера (структурированный вывод
|
||||||
|
с префиксом `[hooks]`). Использовать вместо `console.log` чтобы не ломать формат отчёта.
|
||||||
|
- `config: object` -- разобранный `webtest.config.mjs` (URL контекстов, isolation, etc.).
|
||||||
|
|
||||||
**Тестовый уровень** (с контекстом браузера):
|
**Тестовый уровень** (с контекстом браузера):
|
||||||
- `beforeAll(ctx)` -- после подключения, перед первым тестом
|
- `beforeAll(ctx)` -- после подключения, перед первым тестом
|
||||||
@@ -317,12 +324,17 @@ while (есть открытые формы) {
|
|||||||
```js
|
```js
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
export async function prepare() {
|
export async function prepare({ hookArgs, log, config }) {
|
||||||
|
// Простой парсер ad-hoc флагов: hookArgs приходит как есть, без интерпретации
|
||||||
|
// раннером (см. §6.1 ниже).
|
||||||
|
const force = hookArgs.includes('--rebuild-stand');
|
||||||
|
log('preparing stand, force=', force);
|
||||||
execSync('powershell.exe -File scripts/restore-db.ps1');
|
execSync('powershell.exe -File scripts/restore-db.ps1');
|
||||||
execSync('powershell.exe -File scripts/publish.ps1');
|
execSync('powershell.exe -File scripts/publish.ps1');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function cleanup() {
|
export async function cleanup({ log }) {
|
||||||
|
log('cleaning up stand');
|
||||||
execSync('powershell.exe -File scripts/unpublish.ps1');
|
execSync('powershell.exe -File scripts/unpublish.ps1');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +347,27 @@ export async function afterEach({ closeForm }) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 6.1. Проброс пользовательских флагов через `--`
|
||||||
|
|
||||||
|
Раннер не знает о пользовательских флагах хуков. Чтобы хуки получили ad-hoc
|
||||||
|
параметры без правки `webtest.config.mjs` или окружения, используется стандартная
|
||||||
|
shell-конвенция `--` (как у `npm`, `cargo`, `pytest`): всё что идёт после `--`
|
||||||
|
в CLI раннера передаётся в `prepare`/`cleanup` через поле `hookArgs: string[]`
|
||||||
|
без интерпретации.
|
||||||
|
|
||||||
|
```
|
||||||
|
node run.mjs test tests/web-test/ --bail -- --rebuild-stand --reload-data
|
||||||
|
└─ runner ─┘ └──── hookArgs ────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
В этом примере раннер получает `--bail`, а `hookArgs` хуков становится
|
||||||
|
`['--rebuild-stand', '--reload-data']`. Парсинг этого массива — ответственность
|
||||||
|
хуков.
|
||||||
|
|
||||||
|
Если разделитель `--` не указан, `hookArgs` — пустой массив. Это позволяет
|
||||||
|
раннеру и хукам эволюционировать независимо: новый builtin-флаг раннера
|
||||||
|
никогда не пересечётся с пользовательским.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Файл конфигурации
|
## 7. Файл конфигурации
|
||||||
|
|||||||
Reference in New Issue
Block a user