@playq/core 0.2.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/bin/playq.js +175 -0
- package/cucumber.js +10 -0
- package/dist/exec/featureFileCache.d.ts +21 -0
- package/dist/exec/featureFileCache.js +124 -0
- package/dist/exec/featureFilePreProcess.d.ts +12 -0
- package/dist/exec/featureFilePreProcess.js +208 -0
- package/dist/exec/preLoader.d.ts +1 -0
- package/dist/exec/preLoader.js +72 -0
- package/dist/exec/preProcessEntry.d.ts +1 -0
- package/dist/exec/preProcessEntry.js +83 -0
- package/dist/exec/preProcess_old_todelete.d.ts +1 -0
- package/dist/exec/preProcess_old_todelete.js +258 -0
- package/dist/exec/runner.d.ts +1 -0
- package/dist/exec/runner.js +221 -0
- package/dist/exec/runner_orchestrator.d.ts +1 -0
- package/dist/exec/runner_orchestrator.js +85 -0
- package/dist/exec/sgGenerator.d.ts +11 -0
- package/dist/exec/sgGenerator.js +310 -0
- package/dist/global.d.ts +15 -0
- package/dist/global.js +185 -0
- package/dist/helper/actions/api/apiRequestActions.d.ts +117 -0
- package/dist/helper/actions/api/apiRequestActions.js +374 -0
- package/dist/helper/actions/api/apiValidationActions.d.ts +119 -0
- package/dist/helper/actions/api/apiValidationActions.js +615 -0
- package/dist/helper/actions/apiActions.d.ts +18 -0
- package/dist/helper/actions/apiActions.js +34 -0
- package/dist/helper/actions/apiStepDefs.d.ts +1 -0
- package/dist/helper/actions/apiStepDefs.js +64 -0
- package/dist/helper/actions/comm/commonActions.d.ts +58 -0
- package/dist/helper/actions/comm/commonActions.js +198 -0
- package/dist/helper/actions/comm/utilityActions.d.ts +131 -0
- package/dist/helper/actions/comm/utilityActions.js +351 -0
- package/dist/helper/actions/commActions.d.ts +18 -0
- package/dist/helper/actions/commActions.js +34 -0
- package/dist/helper/actions/commStepDefs.d.ts +1 -0
- package/dist/helper/actions/commStepDefs.js +57 -0
- package/dist/helper/actions/stepGroupStepDefs.d.ts +1 -0
- package/dist/helper/actions/stepGroupStepDefs.js +15 -0
- package/dist/helper/actions/web/alertActions.d.ts +61 -0
- package/dist/helper/actions/web/alertActions.js +224 -0
- package/dist/helper/actions/web/cookieActions.d.ts +45 -0
- package/dist/helper/actions/web/cookieActions.js +186 -0
- package/dist/helper/actions/web/downloadActions.d.ts +40 -0
- package/dist/helper/actions/web/downloadActions.js +153 -0
- package/dist/helper/actions/web/elementReaderActions.d.ts +95 -0
- package/dist/helper/actions/web/elementReaderActions.js +326 -0
- package/dist/helper/actions/web/formActions.d.ts +122 -0
- package/dist/helper/actions/web/formActions.js +423 -0
- package/dist/helper/actions/web/iframeActions.d.ts +23 -0
- package/dist/helper/actions/web/iframeActions.js +108 -0
- package/dist/helper/actions/web/javascriptActions.d.ts +14 -0
- package/dist/helper/actions/web/javascriptActions.js +77 -0
- package/dist/helper/actions/web/keyboardActions.d.ts +35 -0
- package/dist/helper/actions/web/keyboardActions.js +118 -0
- package/dist/helper/actions/web/localStorageActions.d.ts +51 -0
- package/dist/helper/actions/web/localStorageActions.js +163 -0
- package/dist/helper/actions/web/mouseActions.d.ts +240 -0
- package/dist/helper/actions/web/mouseActions.js +609 -0
- package/dist/helper/actions/web/reportingActions.d.ts +34 -0
- package/dist/helper/actions/web/reportingActions.js +58 -0
- package/dist/helper/actions/web/screenshotActions.d.ts +34 -0
- package/dist/helper/actions/web/screenshotActions.js +151 -0
- package/dist/helper/actions/web/testDataActions.d.ts +21 -0
- package/dist/helper/actions/web/testDataActions.js +211 -0
- package/dist/helper/actions/web/validationActions.d.ts +547 -0
- package/dist/helper/actions/web/validationActions.js +1754 -0
- package/dist/helper/actions/web/waitActions.d.ts +191 -0
- package/dist/helper/actions/web/waitActions.js +589 -0
- package/dist/helper/actions/web/webNavigation.d.ts +104 -0
- package/dist/helper/actions/web/webNavigation.js +288 -0
- package/dist/helper/actions/webActions.d.ts +32 -0
- package/dist/helper/actions/webActions.js +48 -0
- package/dist/helper/actions/webStepDefs.d.ts +1 -0
- package/dist/helper/actions/webStepDefs.js +455 -0
- package/dist/helper/browsers/browserManager.d.ts +1 -0
- package/dist/helper/browsers/browserManager.js +56 -0
- package/dist/helper/bundle/defaultEntries.d.ts +6 -0
- package/dist/helper/bundle/defaultEntries.js +200 -0
- package/dist/helper/bundle/env.d.ts +1 -0
- package/dist/helper/bundle/env.js +157 -0
- package/dist/helper/bundle/vars.d.ts +9 -0
- package/dist/helper/bundle/vars.js +375 -0
- package/dist/helper/faker/customFaker.d.ts +55 -0
- package/dist/helper/faker/customFaker.js +45 -0
- package/dist/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/dist/helper/faker/modules/dateTime.d.ts +18 -0
- package/dist/helper/faker/modules/dateTime.js +106 -0
- package/dist/helper/faker/modules/mobile.d.ts +4 -0
- package/dist/helper/faker/modules/mobile.js +59 -0
- package/dist/helper/faker/modules/nric.d.ts +32 -0
- package/dist/helper/faker/modules/nric.js +84 -0
- package/dist/helper/faker/modules/passport.d.ts +3 -0
- package/dist/helper/faker/modules/passport.js +36 -0
- package/dist/helper/faker/modules/person.d.ts +14 -0
- package/dist/helper/faker/modules/person.js +73 -0
- package/dist/helper/faker/modules/postcode.d.ts +6 -0
- package/dist/helper/faker/modules/postcode.js +47 -0
- package/dist/helper/fixtures/locAggregate.d.ts +7 -0
- package/dist/helper/fixtures/locAggregate.js +94 -0
- package/dist/helper/fixtures/logFixture.d.ts +8 -0
- package/dist/helper/fixtures/logFixture.js +56 -0
- package/dist/helper/fixtures/webFixture.d.ts +19 -0
- package/dist/helper/fixtures/webFixture.js +186 -0
- package/dist/helper/fixtures/webLocFixture.d.ts +2 -0
- package/dist/helper/fixtures/webLocFixture.js +144 -0
- package/dist/helper/report/allureStepLogger.d.ts +0 -0
- package/dist/helper/report/allureStepLogger.js +25 -0
- package/dist/helper/report/customiseReport.d.ts +1 -0
- package/dist/helper/report/customiseReport.js +55 -0
- package/dist/helper/report/init.d.ts +1 -0
- package/dist/helper/report/init.js +14 -0
- package/dist/helper/report/report.d.ts +1 -0
- package/dist/helper/report/report.js +102 -0
- package/dist/helper/util/dataLoader.d.ts +10 -0
- package/dist/helper/util/dataLoader.js +73 -0
- package/dist/helper/util/logger.d.ts +4 -0
- package/dist/helper/util/logger.js +61 -0
- package/dist/helper/util/session/sessionUtil.d.ts +26 -0
- package/dist/helper/util/session/sessionUtil.js +729 -0
- package/dist/helper/util/stepHelpers.d.ts +2 -0
- package/dist/helper/util/stepHelpers.js +16 -0
- package/dist/helper/util/test-data/dataLoader.d.ts +7 -0
- package/dist/helper/util/test-data/dataLoader.js +145 -0
- package/dist/helper/util/test-data/dataTest.d.ts +10 -0
- package/dist/helper/util/test-data/dataTest.js +216 -0
- package/dist/helper/util/totp/totpHelper.d.ts +38 -0
- package/dist/helper/util/totp/totpHelper.js +117 -0
- package/dist/helper/util/utilities/cryptoUtil.d.ts +2 -0
- package/dist/helper/util/utilities/cryptoUtil.js +53 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.d.ts +2 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.js +129 -0
- package/dist/helper/util/utils.d.ts +2 -0
- package/dist/helper/util/utils.js +22 -0
- package/dist/helper/wrapper/PlaywrightWrappers.d.ts +8 -0
- package/dist/helper/wrapper/PlaywrightWrappers.js +26 -0
- package/dist/helper/wrapper/assert.d.ts +9 -0
- package/dist/helper/wrapper/assert.js +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +57 -0
- package/dist/scripts/get-versions.d.ts +1 -0
- package/dist/scripts/get-versions.js +98 -0
- package/dist/scripts/posttest.d.ts +1 -0
- package/dist/scripts/posttest.js +29 -0
- package/dist/scripts/pretest.d.ts +1 -0
- package/dist/scripts/pretest.js +57 -0
- package/dist/scripts/util.d.ts +1 -0
- package/dist/scripts/util.js +376 -0
- package/package.json +68 -0
- package/src/exec/featureFileCache.ts +80 -0
- package/src/exec/featureFilePreProcess.ts +239 -0
- package/src/exec/preLoader.ts +72 -0
- package/src/exec/preProcessEntry.ts +59 -0
- package/src/exec/preProcess_old_todelete.ts +289 -0
- package/src/exec/runner.ts +241 -0
- package/src/exec/runnerCuke.js +90 -0
- package/src/exec/runner_orchestrator.ts +91 -0
- package/src/exec/sgGenerator.ts +373 -0
- package/src/global.ts +130 -0
- package/src/helper/actions/api/apiRequestActions.ts +362 -0
- package/src/helper/actions/api/apiValidationActions.ts +594 -0
- package/src/helper/actions/apiActions.ts +18 -0
- package/src/helper/actions/apiStepDefs.ts +80 -0
- package/src/helper/actions/comm/commonActions.ts +165 -0
- package/src/helper/actions/comm/utilityActions.ts +344 -0
- package/src/helper/actions/commActions.ts +18 -0
- package/src/helper/actions/commStepDefs.ts +72 -0
- package/src/helper/actions/stepGroupStepDefs.ts +17 -0
- package/src/helper/actions/web/alertActions.ts +179 -0
- package/src/helper/actions/web/cookieActions.ts +124 -0
- package/src/helper/actions/web/downloadActions.ts +129 -0
- package/src/helper/actions/web/elementReaderActions.ts +323 -0
- package/src/helper/actions/web/formActions.ts +469 -0
- package/src/helper/actions/web/iframeActions.ts +67 -0
- package/src/helper/actions/web/javascriptActions.ts +38 -0
- package/src/helper/actions/web/keyboardActions.ts +101 -0
- package/src/helper/actions/web/localStorageActions.ts +109 -0
- package/src/helper/actions/web/mouseActions.ts +864 -0
- package/src/helper/actions/web/reportingActions.ts +53 -0
- package/src/helper/actions/web/screenshotActions.ts +124 -0
- package/src/helper/actions/web/testDataActions.ts +162 -0
- package/src/helper/actions/web/validationActions.ts +2287 -0
- package/src/helper/actions/web/waitActions.ts +757 -0
- package/src/helper/actions/web/webNavigation.ts +313 -0
- package/src/helper/actions/webActions.ts +33 -0
- package/src/helper/actions/webStepDefs.ts +505 -0
- package/src/helper/browsers/browserManager.ts +23 -0
- package/src/helper/bundle/defaultEntries.ts +208 -0
- package/src/helper/bundle/env.ts +119 -0
- package/src/helper/bundle/vars.ts +368 -0
- package/src/helper/faker/customFaker.ts +107 -0
- package/src/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/src/helper/faker/modules/dateTime.ts +121 -0
- package/src/helper/faker/modules/mobile.ts +58 -0
- package/src/helper/faker/modules/nric.ts +109 -0
- package/src/helper/faker/modules/passport.ts +34 -0
- package/src/helper/faker/modules/person.ts +93 -0
- package/src/helper/faker/modules/postcode.ts +57 -0
- package/src/helper/fixtures/locAggregate.ts +61 -0
- package/src/helper/fixtures/logFixture.ts +57 -0
- package/src/helper/fixtures/webFixture.ts +206 -0
- package/src/helper/fixtures/webLocFixture.ts +143 -0
- package/src/helper/report/allureStepLogger.ts +26 -0
- package/src/helper/report/customiseReport.ts +61 -0
- package/src/helper/report/init.ts +18 -0
- package/src/helper/report/report.ts +72 -0
- package/src/helper/util/dataLoader.ts +42 -0
- package/src/helper/util/logger.ts +32 -0
- package/src/helper/util/session/sessionUtil.ts +839 -0
- package/src/helper/util/stepHelpers.ts +14 -0
- package/src/helper/util/test-data/dataLoader.ts +108 -0
- package/src/helper/util/test-data/dataTest.ts +191 -0
- package/src/helper/util/test-data/registerUser.json +7 -0
- package/src/helper/util/totp/totpHelper.ts +102 -0
- package/src/helper/util/utilities/cryptoUtil.ts +53 -0
- package/src/helper/util/utilities/schemaGeneratorUtil.ts +143 -0
- package/src/helper/util/utils.ts +28 -0
- package/src/helper/wrapper/PlaywrightWrappers.ts +28 -0
- package/src/helper/wrapper/assert.ts +25 -0
- package/src/index.ts +17 -0
- package/src/scripts/get-versions.ts +68 -0
- package/src/scripts/posttest.ts +32 -0
- package/src/scripts/pretest.ts +48 -0
- package/src/scripts/util.ts +406 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
function sha256(content: string): string {
|
|
5
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const stepGroupDir = path.resolve('tests/bdd/step_group');
|
|
9
|
+
const outputFilePath = path.resolve('tests/bdd/steps/_step_group/stepGroup_steps.ts');
|
|
10
|
+
|
|
11
|
+
// ---- Step Group Caching ----
|
|
12
|
+
const cacheFilePath = path.resolve('_Temp/.cache/stepGroupMeta.json');
|
|
13
|
+
|
|
14
|
+
function loadCache(): Record<string, number> {
|
|
15
|
+
if (!fs.existsSync(cacheFilePath)) return {};
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(fs.readFileSync(cacheFilePath, 'utf8'));
|
|
18
|
+
} catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function saveCache(data: Record<string, number>) {
|
|
24
|
+
fs.mkdirSync(path.dirname(cacheFilePath), { recursive: true });
|
|
25
|
+
fs.writeFileSync(cacheFilePath, JSON.stringify(data, null, 2), 'utf8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getStepGroupFiles(): { file: string; fullPath: string; mtimeMs: number }[] {
|
|
29
|
+
if (!fs.existsSync(stepGroupDir)) return [];
|
|
30
|
+
return fs.readdirSync(stepGroupDir)
|
|
31
|
+
.filter(f => f.endsWith('.feature'))
|
|
32
|
+
.map(file => {
|
|
33
|
+
const fullPath = path.join(stepGroupDir, file);
|
|
34
|
+
const stat = fs.statSync(fullPath);
|
|
35
|
+
return { file, fullPath, mtimeMs: stat.mtimeMs };
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Regex for valid StepGroup tag
|
|
40
|
+
const stepGroupTagRegex = /^@StepGroup:([a-zA-Z0-9_]+)\.sg$/;
|
|
41
|
+
const scenarioRegex = /^Scenario:\s*(.*)$/;
|
|
42
|
+
const invalidScenarioRegex = /^Scenario Outline:/;
|
|
43
|
+
|
|
44
|
+
type StepGroup = {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
steps: string[];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function extractStepGroups(fileContent: string, filename: string): StepGroup[] {
|
|
51
|
+
const lines = fileContent.split(/\r?\n/);
|
|
52
|
+
// Ensure @StepGroup tag appears before Feature declaration
|
|
53
|
+
let hasStepGroupTag = false;
|
|
54
|
+
for (let i = 0; i < lines.length; i++) {
|
|
55
|
+
const line = lines[i].trim();
|
|
56
|
+
if (line === '@StepGroup') {
|
|
57
|
+
hasStepGroupTag = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (line.startsWith('Feature:')) break; // Stop if Feature is encountered first
|
|
61
|
+
}
|
|
62
|
+
if (!hasStepGroupTag) {
|
|
63
|
+
console.warn(`⚠️ Skipping file "${filename}" — missing @StepGroup tag before Feature declaration.`);
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const stepGroups: StepGroup[] = [];
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < lines.length; i++) {
|
|
70
|
+
const line = lines[i].trim();
|
|
71
|
+
if (line.startsWith('@StepGroup:') && !stepGroupTagRegex.test(line)) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`❌ Invalid @StepGroup tag format in file ${filename}.\n` +
|
|
74
|
+
` → Offending line: ${line}\n` +
|
|
75
|
+
` → Only alphanumeric and underscores are allowed in group names (e.g., @StepGroup:valid_name.sg)`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const tagMatch = line.match(stepGroupTagRegex);
|
|
80
|
+
if (tagMatch) {
|
|
81
|
+
const rawName = tagMatch[1];
|
|
82
|
+
const groupName = `${rawName}.sg`;
|
|
83
|
+
|
|
84
|
+
// Validate group name: only alphanumeric and underscores allowed
|
|
85
|
+
if (!/^[a-zA-Z0-9_]+$/.test(rawName)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`❌ Invalid step group name "${rawName}" in file ${filename}.\n` +
|
|
88
|
+
` → Step group names must be alphanumeric with underscores only (no spaces, dashes, or special characters).`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Skip empty lines to find Scenario
|
|
93
|
+
let j = i + 1;
|
|
94
|
+
while (j < lines.length && lines[j].trim() === '') j++;
|
|
95
|
+
|
|
96
|
+
if (j < lines.length) {
|
|
97
|
+
const descLine = lines[j].trim();
|
|
98
|
+
|
|
99
|
+
if (invalidScenarioRegex.test(descLine)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`❌ Scenario Outline is not allowed in Step Group files.\n` +
|
|
102
|
+
` → File: ${filename}\n` +
|
|
103
|
+
` → Offending Line: ${j + 1}: ${descLine}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const descMatch = descLine.match(scenarioRegex);
|
|
108
|
+
if (descMatch) {
|
|
109
|
+
const description = descMatch[1].trim();
|
|
110
|
+
// Collect steps until next @ tag or EOF
|
|
111
|
+
const steps: string[] = [];
|
|
112
|
+
let k = j + 1;
|
|
113
|
+
while (k < lines.length && !lines[k].trim().startsWith('@')) {
|
|
114
|
+
const rawLine = lines[k];
|
|
115
|
+
const stepKeywords = ['*', 'Given', 'When', 'Then', 'And', 'But'];
|
|
116
|
+
if (stepKeywords.some(keyword => rawLine.trim().startsWith(keyword))) {
|
|
117
|
+
steps.push(rawLine);
|
|
118
|
+
}
|
|
119
|
+
k++;
|
|
120
|
+
}
|
|
121
|
+
console.log(`🧪 Captured ${steps.length} steps for group: ${groupName}`);
|
|
122
|
+
stepGroups.push({ name: groupName, description, steps });
|
|
123
|
+
i = k - 1; // continue after last processed line
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return stepGroups;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function generateStepDef(group: StepGroup): string {
|
|
133
|
+
const { name, description, steps } = group;
|
|
134
|
+
|
|
135
|
+
const commentBlock = steps.length
|
|
136
|
+
? [
|
|
137
|
+
` /*StepGroup:${name}`,
|
|
138
|
+
...steps.map(s => ` ${s.trimEnd()}`),
|
|
139
|
+
' */'
|
|
140
|
+
].join('\n')
|
|
141
|
+
: ' // No steps defined';
|
|
142
|
+
|
|
143
|
+
return `Given('Step Group: -${name}- -${description}-', async function () {
|
|
144
|
+
${commentBlock}
|
|
145
|
+
});`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function run(options: { force?: boolean } = {}) {
|
|
149
|
+
const cachedTimes = loadCache();
|
|
150
|
+
const filesMeta = getStepGroupFiles();
|
|
151
|
+
const defStat = fs.existsSync(outputFilePath) ? fs.statSync(outputFilePath) : null;
|
|
152
|
+
const cachedDefMtime = cachedTimes["__stepGroupDef"];
|
|
153
|
+
const stepGroupJsonCachePath = path.resolve('_Temp/.cache/stepGroup_cache.json');
|
|
154
|
+
const cacheStat = fs.existsSync(stepGroupJsonCachePath) ? fs.statSync(stepGroupJsonCachePath) : null;
|
|
155
|
+
const cachedJsonDefMtime = cachedTimes["__stepGroupCache"];
|
|
156
|
+
|
|
157
|
+
if (
|
|
158
|
+
!options.force &&
|
|
159
|
+
defStat &&
|
|
160
|
+
defStat.mtimeMs === cachedDefMtime &&
|
|
161
|
+
cacheStat &&
|
|
162
|
+
cacheStat.mtimeMs === cachedJsonDefMtime &&
|
|
163
|
+
filesMeta.every(f => cachedTimes[f.file] === f.mtimeMs)
|
|
164
|
+
) {
|
|
165
|
+
// All step group files, generated output, and cache are up-to-date
|
|
166
|
+
console.log('⏩ Step group definitions are up-to-date. Skipping regeneration.');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const shouldReprocessAll =
|
|
171
|
+
options.force ||
|
|
172
|
+
(defStat && defStat.mtimeMs !== cachedDefMtime) ||
|
|
173
|
+
(cacheStat && cacheStat.mtimeMs !== cachedJsonDefMtime);
|
|
174
|
+
|
|
175
|
+
const changedFiles = shouldReprocessAll
|
|
176
|
+
? filesMeta
|
|
177
|
+
: filesMeta.filter(f => cachedTimes[f.file] !== f.mtimeMs);
|
|
178
|
+
const allGroups: StepGroup[] = [];
|
|
179
|
+
|
|
180
|
+
changedFiles.forEach(({ file, fullPath }) => {
|
|
181
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
182
|
+
const groups = extractStepGroups(content, file);
|
|
183
|
+
allGroups.push(...groups);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const groupListBlock = `/*@StepGroupList\n${JSON.stringify({ groups: allGroups.map(g => g.name) }, null, 2)}\n*/\n\n`;
|
|
187
|
+
|
|
188
|
+
const header = `// ************************** IMPORTANT **************************
|
|
189
|
+
// This file is auto-generated by PlayQ for Step Group.
|
|
190
|
+
// Do not edit it manually. File is auto-generated.
|
|
191
|
+
// Any changes done directly will be lost on the next generation.
|
|
192
|
+
// ***************************************************************
|
|
193
|
+
|
|
194
|
+
import { Given } from '@cucumber/cucumber';
|
|
195
|
+
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
const output = groupListBlock + header + allGroups.map(generateStepDef).join('\n\n') + '\n';
|
|
199
|
+
const stepGroupJsonCache: Record<string, { description: string; steps: string[] }> = {};
|
|
200
|
+
allGroups.forEach(group => {
|
|
201
|
+
stepGroupJsonCache[group.name] = {
|
|
202
|
+
description: group.description,
|
|
203
|
+
steps: group.steps
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// --- Validate existing cache before regeneration ---
|
|
208
|
+
const stepGroupCacheStr = JSON.stringify(stepGroupJsonCache, null, 2);
|
|
209
|
+
if (fs.existsSync(stepGroupJsonCachePath)) {
|
|
210
|
+
const currentCache = fs.readFileSync(stepGroupJsonCachePath, 'utf8');
|
|
211
|
+
const currentHash = sha256(currentCache);
|
|
212
|
+
const newHash = sha256(stepGroupCacheStr);
|
|
213
|
+
if (currentHash !== newHash) {
|
|
214
|
+
console.warn('⚠️ Detected changes in stepGroup_cache.json — file appears to have been modified. It will be regenerated.');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fs.mkdirSync(path.dirname(stepGroupJsonCachePath), { recursive: true });
|
|
219
|
+
fs.writeFileSync(stepGroupJsonCachePath, stepGroupCacheStr, 'utf8');
|
|
220
|
+
|
|
221
|
+
const existingOutput = fs.existsSync(outputFilePath)
|
|
222
|
+
? fs.readFileSync(outputFilePath, 'utf8')
|
|
223
|
+
: '';
|
|
224
|
+
|
|
225
|
+
if (sha256(existingOutput) === sha256(output)) {
|
|
226
|
+
console.log('⏩ No changes in generated output. Skipping file write.');
|
|
227
|
+
} else {
|
|
228
|
+
fs.mkdirSync(path.dirname(outputFilePath), { recursive: true });
|
|
229
|
+
fs.writeFileSync(outputFilePath, output, 'utf8');
|
|
230
|
+
console.log(`✅ Generated ${allGroups.length} Step Group definitions to ${outputFilePath}`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const updatedCache = loadCache(); // Load existing cache
|
|
234
|
+
|
|
235
|
+
// Update feature file mtimes
|
|
236
|
+
filesMeta.forEach(f => {
|
|
237
|
+
updatedCache[f.file] = f.mtimeMs;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Add or update stepGroup_steps.ts mtime
|
|
241
|
+
const finalDefStat = fs.statSync(outputFilePath);
|
|
242
|
+
updatedCache["__stepGroupDef"] = finalDefStat.mtimeMs;
|
|
243
|
+
|
|
244
|
+
// Add or update stepGroup_cache.json mtime (after writing to ensure freshness)
|
|
245
|
+
const finalJsonCacheStat = fs.statSync(stepGroupJsonCachePath);
|
|
246
|
+
updatedCache["__stepGroupCache"] = finalJsonCacheStat.mtimeMs;
|
|
247
|
+
|
|
248
|
+
saveCache(updatedCache);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (require.main === module) {
|
|
252
|
+
run(); // Only run if this file is the entry point (e.g., called via CLI)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
function generateStepGroups(options: { force?: boolean } = {}) {
|
|
257
|
+
run(options);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export { generateStepGroups };
|
|
261
|
+
|
|
262
|
+
// Exported utility to run step group generation, with optional force
|
|
263
|
+
export function generateStepGroupsIfNeeded(force: boolean = false) {
|
|
264
|
+
generateStepGroups({ force });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
// import fs from 'fs';
|
|
269
|
+
// import path from 'path';
|
|
270
|
+
|
|
271
|
+
// const stepGroupDir = path.resolve('test/_step_group');
|
|
272
|
+
// const outputFilePath = path.resolve('test/steps/_step_group/stepGroup_steps.ts');
|
|
273
|
+
|
|
274
|
+
// function extractStepGroups(): {
|
|
275
|
+
// groupName: string;
|
|
276
|
+
// description: string;
|
|
277
|
+
// steps: string[];
|
|
278
|
+
// }[] {
|
|
279
|
+
// const groupPattern = /^@<([\w\-\.]+)\/>$/;
|
|
280
|
+
// const endGroupPattern = /^@<\/([\w\-\.]+)>$/;
|
|
281
|
+
|
|
282
|
+
// const stepGroupFiles = fs.readdirSync(stepGroupDir)
|
|
283
|
+
// .filter(file => /\.(steps\.feature|step\.feature|sg\.feature|steps\.sg\.feature)$/i.test(file));
|
|
284
|
+
|
|
285
|
+
// const stepGroups: {
|
|
286
|
+
// groupName: string;
|
|
287
|
+
// description: string;
|
|
288
|
+
// steps: string[];
|
|
289
|
+
// }[] = [];
|
|
290
|
+
|
|
291
|
+
// stepGroupFiles.forEach(file => {
|
|
292
|
+
// const fullPath = path.join(stepGroupDir, file);
|
|
293
|
+
// const fileContent = fs.readFileSync(fullPath, 'utf-8').trim().split('\n');
|
|
294
|
+
// let currentGroup = "";
|
|
295
|
+
// let groupDesc = "";
|
|
296
|
+
// const groupLines: string[] = [];
|
|
297
|
+
|
|
298
|
+
// fileContent.forEach(line => {
|
|
299
|
+
// const trimmedLine = line.trim();
|
|
300
|
+
// const startMatch = trimmedLine.match(groupPattern);
|
|
301
|
+
// const endMatch = trimmedLine.match(endGroupPattern);
|
|
302
|
+
|
|
303
|
+
// if (startMatch) {
|
|
304
|
+
// currentGroup = startMatch[1];
|
|
305
|
+
// groupDesc = "";
|
|
306
|
+
// return;
|
|
307
|
+
// }
|
|
308
|
+
|
|
309
|
+
// if (trimmedLine.startsWith('@desc:') && currentGroup) {
|
|
310
|
+
// groupDesc = trimmedLine.replace('@desc:', '').trim();
|
|
311
|
+
// return;
|
|
312
|
+
// }
|
|
313
|
+
|
|
314
|
+
// if (endMatch && endMatch[1] === currentGroup) {
|
|
315
|
+
// stepGroups.push({
|
|
316
|
+
// groupName: currentGroup,
|
|
317
|
+
// description: groupDesc,
|
|
318
|
+
// steps: [...groupLines]
|
|
319
|
+
// });
|
|
320
|
+
// currentGroup = "";
|
|
321
|
+
// groupDesc = "";
|
|
322
|
+
// groupLines.length = 0;
|
|
323
|
+
// return;
|
|
324
|
+
// }
|
|
325
|
+
|
|
326
|
+
// if (currentGroup && trimmedLine !== '') {
|
|
327
|
+
// groupLines.push(trimmedLine);
|
|
328
|
+
// }
|
|
329
|
+
// });
|
|
330
|
+
// });
|
|
331
|
+
|
|
332
|
+
// return stepGroups;
|
|
333
|
+
// }
|
|
334
|
+
|
|
335
|
+
// function generateStepDefinitions(stepGroups: {
|
|
336
|
+
// groupName: string;
|
|
337
|
+
// description: string;
|
|
338
|
+
// steps: string[];
|
|
339
|
+
// }[]) {
|
|
340
|
+
// const lines: string[] = [];
|
|
341
|
+
|
|
342
|
+
// lines.push('// ************************** IMPORTANT **************************');
|
|
343
|
+
// lines.push('// This file is auto-generated by PlayQ for Step Group.');
|
|
344
|
+
// lines.push('// Do not edit it manually. File is auto-generated.');
|
|
345
|
+
// lines.push('// Any changes done directly will be lost on the next generation.');
|
|
346
|
+
// lines.push('// ***************************************************************');
|
|
347
|
+
// lines.push('');
|
|
348
|
+
// lines.push("import { Given } from '@cucumber/cucumber';");
|
|
349
|
+
// lines.push('');
|
|
350
|
+
|
|
351
|
+
// stepGroups.forEach(group => {
|
|
352
|
+
// lines.push(`Given('Step Group: -${group.groupName}- -${group.description}-', async function () {`);
|
|
353
|
+
// lines.push(` console.log("Step Group: -${group.groupName}- <${group.description}>");`);
|
|
354
|
+
// lines.push('});');
|
|
355
|
+
// lines.push('');
|
|
356
|
+
// });
|
|
357
|
+
|
|
358
|
+
// fs.mkdirSync(path.dirname(outputFilePath), { recursive: true });
|
|
359
|
+
// fs.writeFileSync(outputFilePath, lines.join('\n'), 'utf-8');
|
|
360
|
+
// console.log(`✅ Step definitions generated: ${outputFilePath}`);
|
|
361
|
+
// }
|
|
362
|
+
|
|
363
|
+
// function run() {
|
|
364
|
+
// const stepGroups = extractStepGroups();
|
|
365
|
+
// if (stepGroups.length === 0) {
|
|
366
|
+
// console.warn('⚠️ No step groups found to generate.');
|
|
367
|
+
// return;
|
|
368
|
+
// }
|
|
369
|
+
|
|
370
|
+
// generateStepDefinitions(stepGroups);
|
|
371
|
+
// }
|
|
372
|
+
|
|
373
|
+
// run();
|
package/src/global.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import * as vars from './helper/bundle/vars';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { webFixture } from './helper/fixtures/webFixture';
|
|
4
|
+
import { logFixture } from './helper/fixtures/logFixture';
|
|
5
|
+
import * as utils from './helper/util/utils';
|
|
6
|
+
import { faker } from './helper/faker/customFaker';
|
|
7
|
+
import { webLocResolver } from './helper/fixtures/webLocFixture';
|
|
8
|
+
import { getLocNamespace } from './helper/fixtures/locAggregate';
|
|
9
|
+
import * as comm from './helper/actions/commActions';
|
|
10
|
+
import * as web from './helper/actions/webActions';
|
|
11
|
+
import * as api from './helper/actions/apiActions';
|
|
12
|
+
import { dataTest } from './helper/util/test-data/dataTest';
|
|
13
|
+
|
|
14
|
+
const addons: any = (() => {
|
|
15
|
+
const root = process.env.PLAYQ_PROJECT_ROOT || process.cwd();
|
|
16
|
+
const tryReq = (id: string) => { try { return require(id); } catch { return undefined; } };
|
|
17
|
+
// Prefer absolute path in new layout, then new alias; no legacy fallbacks
|
|
18
|
+
return (
|
|
19
|
+
tryReq(require('path').join(root, 'playq', 'addons')) ||
|
|
20
|
+
tryReq('@project/addons') ||
|
|
21
|
+
undefined
|
|
22
|
+
);
|
|
23
|
+
})();
|
|
24
|
+
|
|
25
|
+
const engines: any = (() => {
|
|
26
|
+
const root = process.env.PLAYQ_PROJECT_ROOT || process.cwd();
|
|
27
|
+
const tryReq = (id: string) => { try { return require(id); } catch { return undefined; } };
|
|
28
|
+
const pathMod = require('path');
|
|
29
|
+
// Start with index exports to bring in lazy wrappers (patternIq, smartAi)
|
|
30
|
+
const merged: any = {};
|
|
31
|
+
const idxAbs = tryReq(pathMod.join(root, 'playq', 'engines'));
|
|
32
|
+
if (idxAbs) Object.assign(merged, idxAbs);
|
|
33
|
+
const idxAlias = tryReq('@project/engines');
|
|
34
|
+
if (idxAlias) Object.assign(merged, idxAlias);
|
|
35
|
+
// Supplement with direct engines if missing
|
|
36
|
+
const directPattern = [
|
|
37
|
+
pathMod.join(root, 'playq', 'engines', 'patternIq', 'patternIqEngine'),
|
|
38
|
+
'@project/engines/patternIq/patternIqEngine',
|
|
39
|
+
];
|
|
40
|
+
for (const id of directPattern) {
|
|
41
|
+
if (!merged.patternIq) {
|
|
42
|
+
const mod = tryReq(id);
|
|
43
|
+
if (mod) merged.patternIq = (mod as any).patternIq || (mod as any).default || mod;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const directSmart = [
|
|
47
|
+
pathMod.join(root, 'playq', 'engines', 'smartAi', 'smartAiEngine'),
|
|
48
|
+
'@project/engines/smartAi/smartAiEngine',
|
|
49
|
+
];
|
|
50
|
+
for (const id of directSmart) {
|
|
51
|
+
if (!merged.smartAi) {
|
|
52
|
+
const mod = tryReq(id);
|
|
53
|
+
if (mod) merged.smartAi = (mod as any).smartAi || (mod as any).default || mod;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return merged;
|
|
57
|
+
})();
|
|
58
|
+
|
|
59
|
+
const config: any = (() => {
|
|
60
|
+
const pathMod = require('path');
|
|
61
|
+
const root = process.env.PLAYQ_PROJECT_ROOT || process.cwd();
|
|
62
|
+
const configBase = pathMod.join(root, 'resources', 'config');
|
|
63
|
+
let resolvedPath = '';
|
|
64
|
+
let configObj = {};
|
|
65
|
+
try {
|
|
66
|
+
// // Try .js first (for built/production), then .ts (for ts-node/dev)
|
|
67
|
+
// if (require('fs').existsSync(configBase + '.js')) {
|
|
68
|
+
// resolvedPath = configBase + '.js';
|
|
69
|
+
// } else if (require('fs').existsSync(configBase + '.ts')) {
|
|
70
|
+
// resolvedPath = configBase + '.ts';
|
|
71
|
+
// }
|
|
72
|
+
resolvedPath = configBase + '.ts';
|
|
73
|
+
if (resolvedPath) {
|
|
74
|
+
configObj = require(resolvedPath).config || {};
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
configObj = {};
|
|
78
|
+
}
|
|
79
|
+
return configObj;
|
|
80
|
+
})();
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
const testType = process.env.TEST_TYPE;
|
|
87
|
+
const allowedTypes = ['ui', 'api', 'mobile'] as const;
|
|
88
|
+
|
|
89
|
+
globalThis.runType = allowedTypes.includes(testType as any)
|
|
90
|
+
? (testType as typeof allowedTypes[number])
|
|
91
|
+
: 'ui';
|
|
92
|
+
|
|
93
|
+
globalThis.vars = vars;
|
|
94
|
+
globalThis.webLocResolver = webLocResolver;
|
|
95
|
+
globalThis.uiFixture = webFixture;
|
|
96
|
+
globalThis.logFixture = logFixture;
|
|
97
|
+
globalThis.utils = utils;
|
|
98
|
+
globalThis.faker = faker;
|
|
99
|
+
globalThis.comm = comm;
|
|
100
|
+
globalThis.web = web;
|
|
101
|
+
globalThis.api = api;
|
|
102
|
+
globalThis.dataTest = dataTest;
|
|
103
|
+
// Build and expose 'loc' namespace; prefer folder auto-discovery to avoid requiring an index file
|
|
104
|
+
(() => {
|
|
105
|
+
try {
|
|
106
|
+
// First: dynamic aggregator scanning the project folder for *.loc.(ts|js)
|
|
107
|
+
const locNs = getLocNamespace();
|
|
108
|
+
if (locNs && Object.keys(locNs).length > 0) {
|
|
109
|
+
(globalThis as any).loc = locNs;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
} catch { }
|
|
113
|
+
try {
|
|
114
|
+
// Fallback: attempt to load the consumer's loc namespace via tsconfig-paths alias
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
116
|
+
const mod = require('@resources/locators');
|
|
117
|
+
const locNs = mod.default && typeof mod.default === 'object' ? { ...mod.default, ...mod } : mod;
|
|
118
|
+
(globalThis as any).loc = locNs;
|
|
119
|
+
} catch (e: any) {
|
|
120
|
+
console.warn('⚠️ Unable to initialize loc namespace (no folder matches or alias module):', e?.message || e);
|
|
121
|
+
}
|
|
122
|
+
})();
|
|
123
|
+
globalThis.addons = addons;
|
|
124
|
+
globalThis.engines = engines;
|
|
125
|
+
|
|
126
|
+
// Export a stable 'loc' binding for consumers: import { loc } from '@playq/core'
|
|
127
|
+
let loc: any;
|
|
128
|
+
try { loc = (globalThis as any).loc || getLocNamespace() || {}; } catch { loc = {}; }
|
|
129
|
+
|
|
130
|
+
export { vars, webLocResolver, webFixture, logFixture, utils, faker, comm, web, api, dataTest, addons, engines, config, loc };
|