365 lines
11 KiB
JavaScript
Executable File
365 lines
11 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Gherkin Test Report Generator
|
|
*
|
|
* Generates Gherkin format test cases from Jest test results
|
|
* and updates Linear TC issues with Gherkin descriptions
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Test case mapping to functional areas
|
|
const FUNCTIONAL_AREAS = {
|
|
'contact': 'Kapcsolat Űrlap',
|
|
'navigation': 'Navigáció Rendszer',
|
|
'homepage': 'Kezdőlap Funkcionalitás',
|
|
'responsive': 'Responsive Design',
|
|
'performance': 'Teljesítmény',
|
|
'security': 'Biztonság',
|
|
'accessibility': 'Accessibility (A11y)',
|
|
'api': 'API Endpoints'
|
|
};
|
|
|
|
// Gherkin templates for different test types
|
|
const GHERKIN_TEMPLATES = {
|
|
'validation': {
|
|
feature: 'Validáció',
|
|
user: 'weboldal látogató',
|
|
want: 'érvényes adatokat küldeni',
|
|
value: 'sikeresen kapcsolatot felvenni'
|
|
},
|
|
'navigation': {
|
|
feature: 'Navigáció',
|
|
user: 'weboldal látogató',
|
|
want: 'könnyen navigálni az oldalak között',
|
|
value: 'gyorsan megtalálni a kívánt információt'
|
|
},
|
|
'performance': {
|
|
feature: 'Teljesítmény',
|
|
user: 'weboldal látogató',
|
|
want: 'gyorsan betöltődő weboldalt',
|
|
value: 'ne várjak a tartalom megjelenésére'
|
|
},
|
|
'security': {
|
|
feature: 'Biztonság',
|
|
user: 'weboldal rendszergazdája',
|
|
want: 'megvédeni a rendszert támadásoktól',
|
|
value: 'biztonságos működést biztosítani'
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Extract test case ID from test title
|
|
*/
|
|
function extractTestCaseId(title) {
|
|
const match = title.match(/^(TC-\d+):/);
|
|
return match ? match[1] : null;
|
|
}
|
|
|
|
/**
|
|
* Determine functional area from test file path and title
|
|
*/
|
|
function determineFunctionalArea(testFilePath, title) {
|
|
const filePath = testFilePath.toLowerCase();
|
|
|
|
if (filePath.includes('contact') || title.toLowerCase().includes('contact')) {
|
|
return 'contact';
|
|
}
|
|
if (filePath.includes('header') || title.toLowerCase().includes('navigation')) {
|
|
return 'navigation';
|
|
}
|
|
if (filePath.includes('page') || title.toLowerCase().includes('homepage')) {
|
|
return 'homepage';
|
|
}
|
|
if (title.toLowerCase().includes('responsive') || title.toLowerCase().includes('mobile')) {
|
|
return 'responsive';
|
|
}
|
|
if (title.toLowerCase().includes('performance') || title.toLowerCase().includes('lighthouse')) {
|
|
return 'performance';
|
|
}
|
|
if (title.toLowerCase().includes('security') || title.toLowerCase().includes('spam')) {
|
|
return 'security';
|
|
}
|
|
if (title.toLowerCase().includes('accessibility') || title.toLowerCase().includes('a11y')) {
|
|
return 'accessibility';
|
|
}
|
|
if (filePath.includes('api') || title.toLowerCase().includes('api')) {
|
|
return 'api';
|
|
}
|
|
|
|
return 'general';
|
|
}
|
|
|
|
/**
|
|
* Generate Gherkin scenario from test case
|
|
*/
|
|
function generateGherkinScenario(test, functionalArea) {
|
|
const template = GHERKIN_TEMPLATES[functionalArea] || GHERKIN_TEMPLATES['validation'];
|
|
|
|
// Extract test steps from title and description
|
|
const title = test.title.replace(/^(TC-\d+):\s*/, '');
|
|
const steps = parseTestSteps(title, test);
|
|
|
|
return `Feature: ${template.feature}
|
|
As a ${template.user}
|
|
I want to ${template.want}
|
|
So that ${template.value}
|
|
|
|
Background:
|
|
Given a weboldal betöltött állapotban van
|
|
|
|
Scenario: ${title}
|
|
${steps.map(step => ` ${step}`).join('\n')}
|
|
|
|
# Test Execution Details
|
|
# Status: ${test.status.toUpperCase()}
|
|
# Duration: ${test.duration}ms
|
|
# Last Run: ${new Date().toISOString()}
|
|
# File: ${test.file}`;
|
|
}
|
|
|
|
/**
|
|
* Parse test steps from title and generate Gherkin steps
|
|
*/
|
|
function parseTestSteps(title, test) {
|
|
const steps = [];
|
|
const titleLower = title.toLowerCase();
|
|
|
|
// Common patterns for Given/When/Then
|
|
if (titleLower.includes('should') || titleLower.includes('validates')) {
|
|
steps.push('Given a felhasználó a weboldalon van');
|
|
steps.push('When a megfelelő műveletet végzi');
|
|
steps.push('Then a várt eredmény következik be');
|
|
}
|
|
|
|
if (titleLower.includes('email') && titleLower.includes('validation')) {
|
|
steps.push('Given a felhasználó a kapcsolat űrlapon van');
|
|
steps.push('When érvénytelen email címet ad meg');
|
|
steps.push('Then hibaüzenet jelenik meg');
|
|
steps.push('And az űrlap nem kerül elküldésre');
|
|
}
|
|
|
|
if (titleLower.includes('rate limiting')) {
|
|
steps.push('Given a felhasználó elérte a rate limitet');
|
|
steps.push('When új kérést próbál küldeni');
|
|
steps.push('Then 429 Too Many Requests választ kap');
|
|
steps.push('And a kérés nem kerül feldolgozásra');
|
|
}
|
|
|
|
if (titleLower.includes('responsive') || titleLower.includes('mobile')) {
|
|
steps.push('Given a felhasználó mobil eszközön van');
|
|
steps.push('When megnyitja a weboldalt');
|
|
steps.push('Then a hamburger menü látható');
|
|
steps.push('And a layout mobilra optimalizált');
|
|
}
|
|
|
|
if (titleLower.includes('performance') || titleLower.includes('lighthouse')) {
|
|
steps.push('Given a Lighthouse audit futtatásra kerül');
|
|
steps.push('When a teljesítmény mérés befejeződik');
|
|
steps.push('Then a Performance score ≥ 90');
|
|
steps.push('And a betöltési idő < 3 másodperc');
|
|
}
|
|
|
|
// Default steps if no pattern matches
|
|
if (steps.length === 0) {
|
|
steps.push('Given a felhasználó a weboldalon van');
|
|
steps.push('When a megfelelő műveletet végzi');
|
|
steps.push('Then a várt eredmény következik be');
|
|
}
|
|
|
|
return steps;
|
|
}
|
|
|
|
/**
|
|
* Generate functional area analysis
|
|
*/
|
|
function generateFunctionalAnalysis(testResults) {
|
|
const analysis = {};
|
|
|
|
// Handle different test result formats
|
|
const testSuites = testResults.testResults || [];
|
|
|
|
testSuites.forEach(suite => {
|
|
const tests = suite.assertionResults || suite.testResults || [];
|
|
tests.forEach(test => {
|
|
const tcId = extractTestCaseId(test.title);
|
|
if (!tcId) return;
|
|
|
|
const functionalArea = determineFunctionalArea(suite.name || suite.testFilePath, test.title);
|
|
const areaName = FUNCTIONAL_AREAS[functionalArea] || 'Általános';
|
|
|
|
if (!analysis[areaName]) {
|
|
analysis[areaName] = {
|
|
total: 0,
|
|
passed: 0,
|
|
failed: 0,
|
|
skipped: 0,
|
|
tests: []
|
|
};
|
|
}
|
|
|
|
analysis[areaName].total++;
|
|
analysis[areaName][test.status]++;
|
|
analysis[areaName].tests.push({
|
|
id: tcId,
|
|
title: test.title,
|
|
status: test.status,
|
|
duration: test.duration
|
|
});
|
|
});
|
|
});
|
|
|
|
return analysis;
|
|
}
|
|
|
|
/**
|
|
* Generate coverage dashboard
|
|
*/
|
|
function generateCoverageDashboard(analysis) {
|
|
let dashboard = `# Test Coverage Dashboard - ${new Date().toISOString().split('T')[0]}
|
|
|
|
## 📊 Összefoglaló
|
|
`;
|
|
|
|
let totalTests = 0;
|
|
let totalPassed = 0;
|
|
let totalFailed = 0;
|
|
let totalSkipped = 0;
|
|
|
|
Object.values(analysis).forEach(area => {
|
|
totalTests += area.total;
|
|
totalPassed += area.passed;
|
|
totalFailed += area.failed;
|
|
totalSkipped += area.skipped;
|
|
});
|
|
|
|
const successRate = totalTests > 0 ? Math.round((totalPassed / totalTests) * 100) : 0;
|
|
|
|
dashboard += `- **Összes teszt**: ${totalTests}
|
|
- **Sikeres**: ${totalPassed} (${successRate}%)
|
|
- **Sikertelen**: ${totalFailed} (${Math.round((totalFailed / totalTests) * 100)}%)
|
|
- **Kihagyott**: ${totalSkipped} (${Math.round((totalSkipped / totalTests) * 100)}%)
|
|
|
|
## 🎯 Területenkénti Elemzés
|
|
|
|
`;
|
|
|
|
Object.entries(analysis).forEach(([areaName, data]) => {
|
|
const successRate = data.total > 0 ? Math.round((data.passed / data.total) * 100) : 0;
|
|
let status = '✅ Kiváló';
|
|
|
|
if (successRate < 80) status = '🔴 Kritikus';
|
|
else if (successRate < 90) status = '⚠️ Figyelendő';
|
|
|
|
dashboard += `### ${areaName}
|
|
- **Tesztesetek**: ${data.total}
|
|
- **Sikeres**: ${data.passed} (${successRate}%)
|
|
- **Sikertelen**: ${data.failed} (${Math.round((data.failed / data.total) * 100)}%)
|
|
- **Státusz**: ${status}
|
|
- **Lemaradás**: ${data.failed > 0 ? 'Van' : 'Nincs'}
|
|
|
|
`;
|
|
});
|
|
|
|
// Critical issues
|
|
const criticalIssues = Object.entries(analysis)
|
|
.filter(([_, data]) => data.failed > 0)
|
|
.map(([areaName, data]) => `${areaName}: ${data.failed} sikertelen teszt`);
|
|
|
|
if (criticalIssues.length > 0) {
|
|
dashboard += `## 🚨 Kritikus Lemaradások
|
|
${criticalIssues.map(issue => `1. **${issue}**`).join('\n')}
|
|
|
|
`;
|
|
}
|
|
|
|
dashboard += `## 📈 Javaslatok
|
|
1. Sikertelen tesztek javítása
|
|
2. Hiányzó tesztesetek implementálása
|
|
3. Performance optimalizálás
|
|
4. Monitoring beállítása
|
|
|
|
---
|
|
*Generálva: ${new Date().toISOString()}*
|
|
`;
|
|
|
|
return dashboard;
|
|
}
|
|
|
|
/**
|
|
* Main execution
|
|
*/
|
|
async function main() {
|
|
console.log('🥒 Generating Gherkin test reports...');
|
|
|
|
try {
|
|
// Read test results
|
|
const resultsPath = process.argv[2] || 'proto/test-results.json';
|
|
const testResults = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
|
|
|
|
// Generate functional analysis
|
|
const analysis = generateFunctionalAnalysis(testResults);
|
|
|
|
// Generate Gherkin scenarios for each test case
|
|
const gherkinScenarios = {};
|
|
|
|
const testSuites = testResults.testResults || [];
|
|
testSuites.forEach(suite => {
|
|
const tests = suite.assertionResults || suite.testResults || [];
|
|
tests.forEach(test => {
|
|
const tcId = extractTestCaseId(test.title);
|
|
if (!tcId) return;
|
|
|
|
const functionalArea = determineFunctionalArea(suite.name || suite.testFilePath, test.title);
|
|
const gherkin = generateGherkinScenario(test, functionalArea);
|
|
|
|
gherkinScenarios[tcId] = {
|
|
gherkin,
|
|
functionalArea,
|
|
test: {
|
|
...test,
|
|
file: suite.name || suite.testFilePath
|
|
}
|
|
};
|
|
});
|
|
});
|
|
|
|
// Generate coverage dashboard
|
|
const dashboard = generateCoverageDashboard(analysis);
|
|
|
|
// Save reports
|
|
fs.writeFileSync('gherkin-scenarios.json', JSON.stringify(gherkinScenarios, null, 2));
|
|
fs.writeFileSync('test-coverage-dashboard.md', dashboard);
|
|
|
|
console.log('✅ Gherkin reports generated successfully!');
|
|
console.log(`📊 Functional areas analyzed: ${Object.keys(analysis).length}`);
|
|
console.log(`🥒 Gherkin scenarios generated: ${Object.keys(gherkinScenarios).length}`);
|
|
console.log(`📈 Coverage dashboard: test-coverage-dashboard.md`);
|
|
|
|
// Display summary
|
|
console.log('\n📋 Summary:');
|
|
Object.entries(analysis).forEach(([areaName, data]) => {
|
|
const successRate = Math.round((data.passed / data.total) * 100);
|
|
console.log(` ${areaName}: ${data.passed}/${data.total} (${successRate}%)`);
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error generating Gherkin reports:', error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
module.exports = {
|
|
extractTestCaseId,
|
|
determineFunctionalArea,
|
|
generateGherkinScenario,
|
|
generateFunctionalAnalysis,
|
|
generateCoverageDashboard
|
|
};
|