Update qkf/stepRegistry.js
This commit is contained in:
@@ -1,125 +1,137 @@
|
|||||||
@echo off
|
// qkf/stepRegistry.js
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
REM ============================
|
function escapeRegex(s) {
|
||||||
REM QKF – Full Test Runner
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
REM ============================
|
}
|
||||||
|
|
||||||
echo.
|
function normalizeText(t) {
|
||||||
echo ============================
|
return String(t || "").trim().replace(/\s+/g, " ");
|
||||||
echo QKF Test Execution
|
}
|
||||||
echo ============================
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM ----------------------------
|
function literalToRegex(lit) {
|
||||||
REM Arguments
|
// Escape + make spaces flexible
|
||||||
REM ----------------------------
|
return escapeRegex(normalizeText(lit)).replace(/\s+/g, "\\s+");
|
||||||
set FORCE_INSTALL=false
|
}
|
||||||
if "%1"=="--install" set FORCE_INSTALL=true
|
|
||||||
|
|
||||||
REM ----------------------------
|
/**
|
||||||
REM Config (edit if needed)
|
* Pattern supports "{string}" placeholders.
|
||||||
REM ----------------------------
|
* Matches:
|
||||||
set QKF_BROWSER=chrome
|
* - "quoted value"
|
||||||
set QKF_HEADLESS=false
|
* - 'quoted value'
|
||||||
set QKF_TEST_TIMEOUT_MS=120000
|
* - unquoted value (single token or multi-word)
|
||||||
set QKF_BASE_URL=http://gitea.cloud.qacg/user/login
|
*
|
||||||
|
* Unquoted capture:
|
||||||
|
* - if there is a next literal => capture lazily until that literal (lookahead)
|
||||||
|
* - if last placeholder => capture rest of line
|
||||||
|
*/
|
||||||
|
function patternToRegex(pattern) {
|
||||||
|
const parts = String(pattern).split("{string}");
|
||||||
|
const litParts = parts.map((p) => literalToRegex(p));
|
||||||
|
|
||||||
REM ----------------------------
|
// Each placeholder yields 3 capturing groups: dbl, sgl, unquoted
|
||||||
REM Paths
|
const QUOTED_OR_UNQUOTED = (nextLiteralRegex) => {
|
||||||
REM ----------------------------
|
const dbl = `"([^"]+)"`;
|
||||||
set FEATURES_DIR=features
|
const sgl = `'([^']+)'`;
|
||||||
set GENERATED_DIR=test\generated
|
|
||||||
set ALLURE_RESULTS=allure-results
|
|
||||||
set ALLURE_REPORT=allure-report
|
|
||||||
|
|
||||||
REM ----------------------------
|
if (nextLiteralRegex && nextLiteralRegex.length > 0) {
|
||||||
REM Node dependencies
|
// Capture up to the next literal (lazy) without consuming it
|
||||||
REM ----------------------------
|
// Allow optional whitespace before the next literal
|
||||||
if not exist "node_modules" (
|
const unq = `(.+?)(?=\\s*${nextLiteralRegex})`;
|
||||||
echo.
|
return `(?:${dbl}|${sgl}|${unq})`;
|
||||||
echo node_modules not found — running npm install...
|
}
|
||||||
npm install
|
|
||||||
if errorlevel 1 (
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
REM ----------------------------
|
// Last placeholder: capture rest of line
|
||||||
REM Clean previous output
|
const unqLast = `(.+)`;
|
||||||
REM ----------------------------
|
return `(?:${dbl}|${sgl}|${unqLast})`;
|
||||||
if exist "%GENERATED_DIR%" (
|
};
|
||||||
echo Cleaning generated specs...
|
|
||||||
rmdir /s /q "%GENERATED_DIR%"
|
|
||||||
)
|
|
||||||
|
|
||||||
if exist "%ALLURE_RESULTS%" (
|
let re = "^\\s*";
|
||||||
echo Cleaning Allure results...
|
|
||||||
rmdir /s /q "%ALLURE_RESULTS%"
|
|
||||||
)
|
|
||||||
|
|
||||||
if exist "%ALLURE_REPORT%" (
|
for (let i = 0; i < litParts.length; i++) {
|
||||||
echo Cleaning Allure report...
|
const lit = litParts[i];
|
||||||
rmdir /s /q "%ALLURE_REPORT%"
|
|
||||||
)
|
|
||||||
|
|
||||||
REM ----------------------------
|
// Add the literal segment (if any)
|
||||||
REM Generate specs
|
if (lit) re += lit;
|
||||||
REM ----------------------------
|
|
||||||
echo.
|
|
||||||
echo [1/4] Generating specs from Gherkin...
|
|
||||||
node scripts\transform.js --features "%FEATURES_DIR%" --verbose
|
|
||||||
|
|
||||||
if errorlevel 1 (
|
// If a placeholder follows this literal:
|
||||||
echo ❌ Spec generation failed
|
if (i < litParts.length - 1) {
|
||||||
exit /b 1
|
const nextLit = litParts[i + 1];
|
||||||
)
|
|
||||||
|
|
||||||
REM ----------------------------
|
// Allow whitespace between literal and value
|
||||||
REM Run tests
|
re += "\\s+";
|
||||||
REM ----------------------------
|
re += QUOTED_OR_UNQUOTED(nextLit);
|
||||||
echo.
|
// IMPORTANT: whitespace after value is optional; next literal (if any) will handle it
|
||||||
echo [2/4] Running Mocha + Selenium + Allure...
|
re += "\\s*";
|
||||||
npx mocha ^
|
}
|
||||||
--timeout %QKF_TEST_TIMEOUT_MS% ^
|
}
|
||||||
--reporter allure-mocha ^
|
|
||||||
"%GENERATED_DIR%\*.spec.js"
|
|
||||||
|
|
||||||
if errorlevel 1 (
|
re += "\\s*$";
|
||||||
echo ⚠️ Tests finished with failures (continuing to report generation)
|
return new RegExp(re, "i");
|
||||||
)
|
}
|
||||||
|
|
||||||
REM ----------------------------
|
function createStepRegistry(initialCtx = {}) {
|
||||||
REM Generate Allure report
|
const defs = [];
|
||||||
REM ----------------------------
|
|
||||||
echo.
|
|
||||||
echo [3/4] Generating Allure report...
|
|
||||||
allure generate "%ALLURE_RESULTS%" -o "%ALLURE_REPORT%" --clean
|
|
||||||
|
|
||||||
if errorlevel 1 (
|
function register(pattern, fn, meta = {}) {
|
||||||
echo ❌ Allure report generation failed
|
defs.push({
|
||||||
exit /b 1
|
pattern: String(pattern),
|
||||||
)
|
regex: patternToRegex(pattern),
|
||||||
|
fn,
|
||||||
|
meta,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
REM ----------------------------
|
// DSL helpers
|
||||||
REM Open Allure report
|
function WHEN(pattern, fn) { register(pattern, fn, { keyword: "WHEN" }); }
|
||||||
REM ----------------------------
|
function AND(pattern, fn) { register(pattern, fn, { keyword: "AND" }); }
|
||||||
echo.
|
function THEN(pattern, fn) { register(pattern, fn, { keyword: "THEN" }); }
|
||||||
echo [4/4] Opening Allure report...
|
function GIVEN(pattern, fn){ register(pattern, fn, { keyword: "GIVEN" }); }
|
||||||
allure open "%ALLURE_REPORT%"
|
function BUT(pattern, fn) { register(pattern, fn, { keyword: "BUT" }); }
|
||||||
|
|
||||||
echo.
|
async function run(stepText, extraCtx = {}) {
|
||||||
echo ✅ Done.
|
const text = normalizeText(stepText);
|
||||||
endlocal
|
|
||||||
|
for (const d of defs) {
|
||||||
|
const m = d.regex.exec(text);
|
||||||
|
if (!m) continue;
|
||||||
|
|
||||||
|
// Each {string} adds 3 capture groups: dbl, sgl, unquoted
|
||||||
|
const captures = [];
|
||||||
|
for (let i = 1; i < m.length; i += 3) {
|
||||||
|
const v = m[i] || m[i + 1] || m[i + 2] || "";
|
||||||
|
captures.push(normalizeText(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = { ...initialCtx, ...extraCtx };
|
||||||
|
|
||||||
|
// Auto-await QKF calls (if you implemented these hooks)
|
||||||
|
if (ctx.qkf && typeof ctx.qkf.__beginStep === "function") ctx.qkf.__beginStep();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = d.fn.apply(null, [...captures, ctx]);
|
||||||
|
await res;
|
||||||
|
|
||||||
|
if (ctx.qkf && typeof ctx.qkf.__endStep === "function") {
|
||||||
|
await ctx.qkf.__endStep();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (err) {
|
||||||
|
try {
|
||||||
|
if (ctx.qkf && typeof ctx.qkf.__endStep === "function") {
|
||||||
|
await ctx.qkf.__endStep();
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const available = defs.map((x) => `- ${x.pattern}`).join("\n");
|
||||||
|
throw new Error(
|
||||||
|
`No step definition matched:\n "${text}"\n\nAvailable definitions:\n${available}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { defs, register, run, WHEN, AND, THEN, GIVEN, BUT };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { createStepRegistry };
|
||||||
|
|||||||
Reference in New Issue
Block a user