feat(web-test): test-раннер пишет человеческий отчёт в stdout, JSON по --report=-

Команда `test` приведена к поведению тест-раннеров (jest/pytest/playwright):
человеческий отчёт со сводкой в последней строке идёт в stdout, а машинный
JSON/JUnit — опционально через `--report=-` (Unix-конвенция `-` = stdout),
при этом прогресс уезжает в stderr. Убран безусловный дамп JSON в stdout,
из-за которого `test … | tail` хоронил сводку под отчётом.

- test.mjs: writer выбирается по режиму (--report=- → stderr-прогресс);
  развилка `-` в обеих ветках записи (json и junit), чтобы не плодить файл "-";
  валидация: --report=- несовместимо с --format=allure (каталог, не поток).
- util.mjs: строка --report=- в справке.
- Документация (spec/guide/regress/README) приведена к фактическому
  английскому выводу и описывает матрицу потоков stdout/stderr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-31 14:17:52 +03:00
parent f424d2ac70
commit 547f336cf8
6 changed files with 48 additions and 19 deletions
@@ -1,4 +1,4 @@
// web-test cli/commands/test v1.0 — regression test runner
// web-test cli/commands/test v1.1 — regression test runner
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, writeFileSync, mkdirSync } from 'fs';
import { resolve, dirname, basename, relative } from 'path';
@@ -96,9 +96,15 @@ export async function cmdTest(rawArgs) {
if (opts.format === 'junit' && !opts.report) {
die('--format=junit requires --report=path.xml');
}
// `--report=-` means "machine report to stdout" (Unix `-` convention).
// Only meaningful for streamable formats (json/junit); allure is a directory.
const reportToStdout = opts.report === '-';
if (reportToStdout && opts.format === 'allure') {
die('--report=- (stdout) is not valid with --format=allure: allure emits a directory of files, not a single stream. Use --report-dir=<dir> instead.');
}
const reportDir = opts.reportDir
? resolve(opts.reportDir)
: (opts.report ? dirname(resolve(opts.report)) : testDir);
: (opts.report && !reportToStdout ? dirname(resolve(opts.report)) : testDir);
if (opts.screenshot !== 'off') {
try { mkdirSync(reportDir, { recursive: true }); } catch {}
}
@@ -154,8 +160,9 @@ export async function cmdTest(rawArgs) {
hooks = await import('file:///' + hooksPath.replace(/\\/g, '/'));
}
// Console header
const W = process.stderr;
// Human-readable report goes to stdout (test-runner convention: jest/pytest/playwright).
// In `--report -` mode the machine JSON/XML takes over stdout, so progress moves to stderr.
const W = reportToStdout ? process.stderr : process.stdout;
W.write(`\nweb-test -- ${url}\n`);
W.write(`Running ${filtered.length} tests from ${relative(process.cwd(), testDir).replace(/\\/g, '/') || '.'}/\n\n`);
@@ -418,13 +425,14 @@ export async function cmdTest(rawArgs) {
summary: { total: results.length, passed: passCount, failed: failCount, skipped: skipCount },
tests: results,
};
out(report);
if (opts.format === 'allure') {
writeAllure(results, reportDir, severityIndex);
syncAllureExtras(testDir, reportDir);
} else if (opts.format === 'junit') {
writeFileSync(resolve(opts.report), buildJUnit(report, testDir));
if (reportToStdout) process.stdout.write(buildJUnit(report, testDir) + '\n');
else writeFileSync(resolve(opts.report), buildJUnit(report, testDir));
} else if (reportToStdout) {
out(report);
} else if (opts.report) {
writeFileSync(resolve(opts.report), JSON.stringify(report, null, 2));
}
+3 -2
View File
@@ -1,4 +1,4 @@
// web-test cli/util v1.0 — generic helpers for CLI commands
// web-test cli/util v1.1 — generic helpers for CLI commands
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
export function out(obj) {
@@ -100,7 +100,8 @@ Options for test:
--bail Stop on first failure
--retry=N Retry failed tests N times
--timeout=ms Per-test timeout (default: 30000)
--report=path Write JSON report to file
--report=path Write machine report (JSON/JUnit) to file
--report=- Write machine report to stdout (progress moves to stderr)
--report-dir=path Directory for screenshots and other artifacts
--screenshot=mode on-failure (default) | every-step | off
--format=fmt json (default) | allure | junit