Update qkf/stepRegistry.js
This commit is contained in:
@@ -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 };
|
|
||||||
|
|||||||
Reference in New Issue
Block a user