import type { FeatureTestStatus, ScenarioTestResult } from '../src/shared/types/gherkin'; interface CucumberScenario { id: string; name: string; steps: Array<{ result: { status: 'passed' | 'failed' | 'skipped' | 'pending' | 'undefined'; duration?: number; error_message?: string; }; }>; } interface CucumberFeature { id: string; uri: string; name: string; elements: CucumberScenario[]; } export async function parseTestResults(): Promise> { const reportPath = 'reports/cucumber-report.json'; const file = Bun.file(reportPath); if (!await file.exists()) { console.log('No test report found at', reportPath); return new Map(); } const content = await file.text(); const features: CucumberFeature[] = JSON.parse(content); const results = new Map(); for (const feature of features) { // Extract feature ID from URI (e.g., features/user/us-9-visualiser-photo.feature -> us-9) const match = feature.uri.match(/us-(\d+)/i); const featureId = match ? `us-${match[1]}` : feature.id; const scenarios = feature.elements.filter(el => el.name); // Filter out Background let passed = 0; let failed = 0; let skipped = 0; const scenarioResults: ScenarioTestResult[] = []; for (const scenario of scenarios) { const { status: scenarioStatus, errorMessage } = getScenarioStatusAndError(scenario); if (scenarioStatus === 'passed') passed++; else if (scenarioStatus === 'failed') failed++; else skipped++; scenarioResults.push({ name: scenario.name, status: scenarioStatus, errorMessage, }); } results.set(featureId, { featureId, totalScenarios: scenarios.length, passed, failed, skipped, lastRun: new Date(), scenarios: scenarioResults, }); } return results; } function getScenarioStatusAndError(scenario: CucumberScenario): { status: 'passed' | 'failed' | 'skipped'; errorMessage?: string } { for (const step of scenario.steps) { if (step.result.status === 'failed') { return { status: 'failed', errorMessage: step.result.error_message }; } if (step.result.status === 'skipped' || step.result.status === 'pending' || step.result.status === 'undefined') { return { status: 'skipped' }; } } return { status: 'passed' }; } // Generate TypeScript file with test results async function generateTestResultsFile() { const results = await parseTestResults(); const resultsArray = Array.from(results.entries()).map(([id, status]) => ({ ...status, lastRun: status.lastRun?.toISOString(), })); const output = `// Auto-generated by scripts/parse-test-results.ts // Do not edit manually - run "bun run test:results" to regenerate import type { FeatureTestStatus, ScenarioTestResult } from '../types/gherkin'; interface RawFeatureTestStatus { featureId: string; totalScenarios: number; passed: number; failed: number; skipped: number; lastRun?: string; scenarios?: ScenarioTestResult[]; } const rawResults: RawFeatureTestStatus[] = ${JSON.stringify(resultsArray, null, 2)}; export const testResults: Map = new Map( rawResults.map(r => [r.featureId, { ...r, lastRun: r.lastRun ? new Date(r.lastRun) : undefined }]) ); export function getTestStatus(featureId: string): FeatureTestStatus | undefined { return testResults.get(featureId); } export function getScenarioResults(featureId: string): ScenarioTestResult[] { return testResults.get(featureId)?.scenarios ?? []; } export function getAllTestResults(): FeatureTestStatus[] { return Array.from(testResults.values()); } export function getTestSummary() { const results = getAllTestResults(); const firstResult = results[0]; return { totalFeatures: results.length, totalScenarios: results.reduce((acc, r) => acc + r.totalScenarios, 0), passed: results.reduce((acc, r) => acc + r.passed, 0), failed: results.reduce((acc, r) => acc + r.failed, 0), skipped: results.reduce((acc, r) => acc + r.skipped, 0), lastRun: firstResult?.lastRun, }; } `; await Bun.write('src/shared/data/testResults.ts', output); console.log(`Generated test results for ${results.size} features`); // Print summary let totalPassed = 0, totalFailed = 0, totalSkipped = 0; results.forEach(r => { totalPassed += r.passed; totalFailed += r.failed; totalSkipped += r.skipped; }); console.log(`Summary: ${totalPassed} passed, ${totalFailed} failed, ${totalSkipped} skipped`); } generateTestResultsFile().catch(console.error);