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/*.