Update qkf/stepRegistry.js

This commit is contained in:
2026-02-08 21:19:29 -06:00
parent f6eb926660
commit fb8642794f

View File

@@ -1,111 +1,125 @@
// qkf/stepRegistry.js @echo off
setlocal enabledelayedexpansion
function escapeRegex(s) { REM ============================
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); REM QKF Full Test Runner
} REM ============================
function normalizeText(t) { echo.
return String(t || "").trim().replace(/\s+/g, " "); echo ============================
} echo QKF Test Execution
echo ============================
echo.
function patternToRegex(pattern) { REM ----------------------------
// Supports: REM Arguments
// - {string} -> "value" OR 'value' OR bareWord(s) REM ----------------------------
// Also normalizes whitespace set FORCE_INSTALL=false
const norm = normalizeText(pattern); if "%1"=="--install" set FORCE_INSTALL=true
// Split around {string} REM ----------------------------
const parts = norm.split("{string}").map((p) => escapeRegex(p)); REM Config (edit if needed)
REM ----------------------------
set QKF_BROWSER=chrome
set QKF_HEADLESS=false
set QKF_TEST_TIMEOUT_MS=120000
set QKF_BASE_URL=http://gitea.cloud.qacg/user/login
// Capture: REM ----------------------------
// - "..." or '...' or unquoted token(s) (until end) REM Paths
// We make it non-greedy and allow extra spaces. REM ----------------------------
const CAPTURE = `(?:"([^"]+)"|'([^']+)'|([^]+?))`; set FEATURES_DIR=features
set GENERATED_DIR=test\generated
set ALLURE_RESULTS=allure-results
set ALLURE_REPORT=allure-report
let regexStr = "^"; REM ----------------------------
for (let i = 0; i < parts.length; i++) { REM Node dependencies
regexStr += parts[i]; REM ----------------------------
if (i < parts.length - 1) { if not exist "node_modules" (
// allow flexible whitespace around the capture echo.
regexStr += "\\s+" + CAPTURE + "\\s+"; echo node_modules not found running npm install...
} npm install
} if errorlevel 1 (
regexStr += "$"; echo npm install failed
exit /b 1
)
) else if "%FORCE_INSTALL%"=="true" (
echo.
echo --install flag detected running npm install...
npm install
if errorlevel 1 (
echo npm install failed
exit /b 1
)
) else (
echo.
echo node_modules already present skipping npm install
)
return new RegExp(regexStr.replace(/\s+/g, "\\s+"), "i"); REM ----------------------------
} REM Clean previous output
REM ----------------------------
if exist "%GENERATED_DIR%" (
echo Cleaning generated specs...
rmdir /s /q "%GENERATED_DIR%"
)
if exist "%ALLURE_RESULTS%" (
echo Cleaning Allure results...
rmdir /s /q "%ALLURE_RESULTS%"
)
function createStepRegistry(initialCtx = {}) { if exist "%ALLURE_REPORT%" (
const defs = []; echo Cleaning Allure report...
rmdir /s /q "%ALLURE_REPORT%"
)
function register(pattern, fn, meta = {}) { REM ----------------------------
defs.push({ REM Generate specs
pattern: String(pattern), REM ----------------------------
regex: patternToRegex(pattern), echo.
fn, echo [1/4] Generating specs from Gherkin...
meta, node scripts\transform.js --features "%FEATURES_DIR%" --verbose
});
}
function WHEN(pattern, fn) { register(pattern, fn, { keyword: "WHEN" }); } if errorlevel 1 (
function AND(pattern, fn) { register(pattern, fn, { keyword: "AND" }); } echo Spec generation failed
function THEN(pattern, fn) { register(pattern, fn, { keyword: "THEN" }); } exit /b 1
function GIVEN(pattern, fn){ register(pattern, fn, { keyword: "GIVEN" }); } )
function BUT(pattern, fn) { register(pattern, fn, { keyword: "BUT" }); }
async function run(stepText, extraCtx = {}) { REM ----------------------------
const text = normalizeText(stepText); REM Run tests
REM ----------------------------
echo.
echo [2/4] Running Mocha + Selenium + Allure...
npx mocha ^
--timeout %QKF_TEST_TIMEOUT_MS% ^
--reporter allure-mocha ^
"%GENERATED_DIR%\*.spec.js"
for (const d of defs) { if errorlevel 1 (
const m = d.regex.exec(text); echo Tests finished with failures (continuing to report generation)
if (!m) continue; )
const captures = []; REM ----------------------------
for (let i = 1; i < m.length; i += 3) { REM Generate Allure report
const v = m[i] || m[i + 1] || m[i + 2] || ""; REM ----------------------------
captures.push(normalizeText(v)); echo.
} echo [3/4] Generating Allure report...
const ctx = { ...initialCtx, ...extraCtx }; allure generate "%ALLURE_RESULTS%" -o "%ALLURE_REPORT%" --clean
// ✅ Begin step tracking so QKF calls are awaited even if step defs don't `await` if errorlevel 1 (
if (ctx.qkf && typeof ctx.qkf.__beginStep === "function") ctx.qkf.__beginStep(); echo Allure report generation failed
exit /b 1
)
try { REM ----------------------------
// Step defs get (...captures, ctx) REM Open Allure report
const res = d.fn.apply(null, [...captures, ctx]); REM ----------------------------
// Await the step function itself (if it's async) echo.
await res; echo [4/4] Opening Allure report...
// ✅ Then await all QKF actions triggered during the step allure open "%ALLURE_REPORT%"
if (ctx.qkf && typeof ctx.qkf.__endStep === "function") await ctx.qkf.__endStep();
return;
} catch (err) {
// try to flush pending actions so failures surface cleanly
try {
if (ctx.qkf && typeof ctx.qkf.__endStep === "function") await ctx.qkf.__endStep();
} catch (_) {
// ignore secondary errors
}
throw err;
}
}
const available = defs.map((d) => `- ${d.pattern}`).join("\n"); echo.
throw new Error( echo Done.
`No step definition matched:\n "${text}"\n\nAvailable definitions:\n${available}` endlocal
);
}
return {
defs,
register,
run,
WHEN,
AND,
THEN,
GIVEN,
BUT,
};
}
module.exports = { createStepRegistry };