Files
websitedev/scripts/generate-gherkin-reports.js
T

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
};