diff --git a/.claude/skills/web-test/scripts/cli/commands/test.mjs b/.claude/skills/web-test/scripts/cli/commands/test.mjs
index ff2e1f8d..448e87de 100644
--- a/.claude/skills/web-test/scripts/cli/commands/test.mjs
+++ b/.claude/skills/web-test/scripts/cli/commands/test.mjs
@@ -1,4 +1,4 @@
-// web-test cli/commands/test v1.2 — regression test runner
+// web-test cli/commands/test v1.3 — 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';
@@ -20,11 +20,12 @@ export async function cmdTest(rawArgs) {
// Parse flags
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, urlFlag = null;
const positional = [];
for (const a of ownArgs) {
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('--url=')) urlFlag = a.slice(6);
else if (a === '--bail') opts.bail = true;
else if (a.startsWith('--retry=')) opts.retry = parseInt(a.slice(8)) || 0;
else if (a.startsWith('--timeout=')) opts.timeout = parseInt(a.slice(10)) || 30000;
@@ -36,20 +37,28 @@ export async function cmdTest(rawArgs) {
else if (!a.startsWith('--')) positional.push(a);
}
- // Determine URL and test path
- let url, testPath;
- if (positional.length === 2) {
- url = positional[0];
- testPath = resolve(positional[1]);
- } else if (positional.length === 1) {
- testPath = resolve(positional[0]);
- } else {
- die('Usage: node run.mjs test [url]
[--tags=...] [--bail] [--retry=N] [--timeout=ms] [--report=path]');
+ // Positional args are ALWAYS test paths (one or many). URL comes from --url= or config
+ // (see webtest.config.mjs). This matches pytest/jest/playwright; a positional that looks
+ // like a URL is a mistake → fail fast with a hint instead of feeding it to page.goto().
+ const isUrl = (s) => /^https?:\/\//i.test(s);
+ let url = urlFlag || null;
+ const testPaths = [...positional];
+ if (testPaths.length === 0) {
+ die('Usage: node run.mjs test ... [--url=URL] [--tags=...] [--grep=...] [--bail] [--retry=N] [--timeout=ms] [--report=path]');
+ }
+ for (const p of testPaths) {
+ if (existsSync(resolve(p))) continue;
+ if (isUrl(p)) {
+ die(`"${p}" looks like a URL — use --url=; positional args are test paths.`);
+ }
+ die(`Test path not found: "${p}". To run a subset use --grep= / --tags=, or pass an existing dir/file.`);
}
- // Load config if exists
- const isFile = testPath.endsWith('.test.mjs');
- const testDir = isFile ? dirname(testPath) : testPath;
+ // Load config if exists. config (webtest.config.mjs) and hooks (_hooks.mjs) resolve from
+ // the FIRST path's directory — list paths from the same suite folder.
+ const firstPath = resolve(testPaths[0]);
+ const isFile = firstPath.endsWith('.test.mjs');
+ const testDir = isFile ? dirname(firstPath) : firstPath;
const configPath = resolve(testDir, 'webtest.config.mjs');
let config = {};
if (existsSync(configPath)) {
@@ -110,8 +119,8 @@ export async function cmdTest(rawArgs) {
}
// Discover test files
- const testFiles = discoverTests(testPath);
- if (!testFiles.length) die(`No *.test.mjs files found in ${testPath}`);
+ const testFiles = discoverTests(testPaths);
+ if (!testFiles.length) die(`No *.test.mjs files found in ${testPaths.join(', ')}`);
// Import and filter tests
const tests = [];
diff --git a/.claude/skills/web-test/scripts/cli/test-runner/discover.mjs b/.claude/skills/web-test/scripts/cli/test-runner/discover.mjs
index bffbe8e9..558a6eb6 100644
--- a/.claude/skills/web-test/scripts/cli/test-runner/discover.mjs
+++ b/.claude/skills/web-test/scripts/cli/test-runner/discover.mjs
@@ -1,10 +1,14 @@
-// web-test cli/test-runner/discover v1.0 — test file discovery + state reset between tests
+// web-test cli/test-runner/discover v1.1 — test file discovery + state reset between tests
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { existsSync, readdirSync } from 'fs';
import { resolve } from 'path';
-export function discoverTests(testPath) {
- if (testPath.endsWith('.test.mjs')) return existsSync(testPath) ? [testPath] : [];
+// Accepts a single path or an array of paths (files and/or dirs). Each .test.mjs file is
+// taken directly; each directory is walked recursively (skipping _ / . prefixes). Results
+// are deduped and sorted — sorting preserves the numeric-prefix order the suite relies on
+// (00-, 01-, …) even when paths are listed out of order.
+export function discoverTests(testPaths) {
+ const paths = Array.isArray(testPaths) ? testPaths : [testPaths];
const files = [];
function walk(dir) {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
@@ -14,8 +18,15 @@ export function discoverTests(testPath) {
else if (entry.name.endsWith('.test.mjs')) files.push(full);
}
}
- walk(testPath);
- return files.sort();
+ for (const p of paths) {
+ const full = resolve(p);
+ if (full.endsWith('.test.mjs')) {
+ if (existsSync(full)) files.push(full);
+ } else if (existsSync(full)) {
+ walk(full);
+ }
+ }
+ return [...new Set(files)].sort();
}
export async function resetState(ctx) {
diff --git a/.claude/skills/web-test/scripts/cli/util.mjs b/.claude/skills/web-test/scripts/cli/util.mjs
index 0bc1c913..c497d4b9 100644
--- a/.claude/skills/web-test/scripts/cli/util.mjs
+++ b/.claude/skills/web-test/scripts/cli/util.mjs
@@ -1,4 +1,4 @@
-// web-test cli/util v1.1 — generic helpers for CLI commands
+// web-test cli/util v1.2 — generic helpers for CLI commands
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
export function out(obj) {
@@ -85,7 +85,7 @@ Commands:
shot [file] Take screenshot (default: shot.png)
stop Logout and close browser
status Check session status
- test [url] Run regression tests (*.test.mjs)
+ test ... Run regression tests (*.test.mjs); accepts multiple paths
Options for exec:
--no-record Skip video recording (record() becomes no-op)
@@ -95,6 +95,7 @@ Global options (any command):
Default: on (env: WEB_TEST_PRESERVE_CLIPBOARD=0 to disable globally).
Options for test:
+ --url=URL Override the base URL (default: from webtest.config.mjs)
--tags=smoke,crud Filter tests by tags
--grep=pattern Filter tests by name (regex)
--bail Stop on first failure
diff --git a/.claude/skills/web-test/scripts/run.mjs b/.claude/skills/web-test/scripts/run.mjs
index 7fb2e1e6..da1fef62 100644
--- a/.claude/skills/web-test/scripts/run.mjs
+++ b/.claude/skills/web-test/scripts/run.mjs
@@ -1,5 +1,5 @@
#!/usr/bin/env node
-// web-test run v1.17 — CLI entry-point (распилено по cli/)
+// web-test run v1.18 — CLI entry-point (распилено по cli/)
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
/**
* CLI runner for 1C web client automation.
@@ -14,7 +14,7 @@
* node src/run.mjs shot [file] — take screenshot
* node src/run.mjs stop — logout + close browser
* node src/run.mjs status — check session
- * node src/run.mjs test [url] — run regression tests
+ * node src/run.mjs test ... [--url] — run regression tests
*
* Внутренности живут в cli/: util, session, exec-context, server,
* commands/{start,run,exec,shot,stop,status,test}, test-runner/*.