first commit
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
// Extract step definitions from feature files and generate a data file with source code
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
interface StepDefinition {
|
||||
pattern: string;
|
||||
keyword: 'Given' | 'When' | 'Then';
|
||||
file: string;
|
||||
sourceCode: string;
|
||||
lineNumber: number;
|
||||
}
|
||||
|
||||
const stepFiles = [
|
||||
'features/step_definitions/navigation.steps.ts',
|
||||
'features/step_definitions/form.steps.ts',
|
||||
'features/step_definitions/screen.steps.ts',
|
||||
];
|
||||
|
||||
function extractStepDefinitions(): StepDefinition[] {
|
||||
const definitions: StepDefinition[] = [];
|
||||
|
||||
for (const filePath of stepFiles) {
|
||||
const fullPath = path.join(process.cwd(), filePath);
|
||||
if (!fs.existsSync(fullPath)) continue;
|
||||
|
||||
const content = fs.readFileSync(fullPath, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
const fileName = path.basename(filePath);
|
||||
|
||||
// Find step definitions line by line
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
// Match Given/When/Then at the start of a line
|
||||
const match = line.match(/^(Given|When|Then)\s*\(\s*['"`]([^'"`]+)['"`]/);
|
||||
if (match) {
|
||||
const keyword = match[1] as 'Given' | 'When' | 'Then';
|
||||
const pattern = match[2];
|
||||
|
||||
// Extract the full function body
|
||||
const sourceCode = extractFunctionBody(lines, i);
|
||||
|
||||
definitions.push({
|
||||
pattern,
|
||||
keyword,
|
||||
file: fileName,
|
||||
sourceCode,
|
||||
lineNumber: i + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
function extractFunctionBody(lines: string[], startLine: number): string {
|
||||
// Look for the closing }); which marks the end of a step definition
|
||||
for (let i = startLine; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line === '});' || line.endsWith('});')) {
|
||||
const extracted = lines.slice(startLine, i + 1);
|
||||
return extracted.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: return just the start line if we couldn't find the end
|
||||
return lines[startLine] || '';
|
||||
}
|
||||
|
||||
async function generateStepDefinitionsFile() {
|
||||
const definitions = extractStepDefinitions();
|
||||
|
||||
const findFunctionCode = `export function findStepDefinition(stepText: string): StepDefinitionInfo | null {
|
||||
for (const def of stepDefinitions) {
|
||||
// Convert Cucumber expression to regex
|
||||
// {string} -> "[^"]+"
|
||||
// {int} -> \\\\d+
|
||||
const regexPattern = def.pattern
|
||||
.replace(/\\{string\\}/g, '"[^"]+"')
|
||||
.replace(/\\{int\\}/g, '\\\\d+');
|
||||
|
||||
try {
|
||||
const regex = new RegExp(regexPattern);
|
||||
if (regex.test(stepText)) {
|
||||
return def;
|
||||
}
|
||||
} catch {
|
||||
// If pattern fails, try simple includes
|
||||
const simplified = def.pattern.replace(/\\{string\\}/g, '').replace(/\\{int\\}/g, '').trim();
|
||||
if (stepText.includes(simplified)) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}`;
|
||||
|
||||
const output = `// Auto-generated by scripts/extract-step-definitions.ts
|
||||
// Do not edit manually - run "bun run steps:extract" to regenerate
|
||||
|
||||
export interface StepDefinitionInfo {
|
||||
pattern: string;
|
||||
keyword: 'Given' | 'When' | 'Then';
|
||||
file: string;
|
||||
sourceCode: string;
|
||||
lineNumber: number;
|
||||
}
|
||||
|
||||
export const stepDefinitions: StepDefinitionInfo[] = ${JSON.stringify(definitions, null, 2)};
|
||||
|
||||
${findFunctionCode}
|
||||
`;
|
||||
|
||||
await Bun.write('src/data/stepDefinitions.ts', output);
|
||||
console.log(`Generated ${definitions.length} step definitions`);
|
||||
}
|
||||
|
||||
generateStepDefinitionsFile().catch(console.error);
|
||||
Reference in New Issue
Block a user