- Updated README.md with project details, quick start instructions, and tech stack. - Expanded TODO.md to reflect current project status and backlog items, including Linear ticket synchronization. - Added mobile menu toggle functionality in Header component with corresponding tests for user interactions. - Configured Next.js for Docker deployment and optimized build settings.
335 lines
9.1 KiB
JavaScript
335 lines
9.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* TC Issue Updater
|
|
*
|
|
* Updates Linear TC issues with Gherkin format test cases
|
|
* and functional area analysis
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Mock Linear API client (replace with actual implementation)
|
|
const mockLinearClient = {
|
|
async updateIssue(issueId, updateData) {
|
|
console.log(`📝 Updating ${issueId}:`, updateData.title || 'No title');
|
|
return { success: true, issueId };
|
|
},
|
|
|
|
async createComment(issueId, comment) {
|
|
console.log(`💬 Adding comment to ${issueId}`);
|
|
return { success: true, commentId: `comment_${Date.now()}` };
|
|
}
|
|
};
|
|
|
|
// Test case mapping to Linear issue IDs
|
|
const TEST_CASE_MAPPING = {
|
|
'TC-001': 'ZEE-48', // Email Format Validation Test
|
|
'TC-002': 'ZEE-49' // Rate Limiting Integration Test
|
|
};
|
|
|
|
/**
|
|
* Load Gherkin scenarios from generated file
|
|
*/
|
|
function loadGherkinScenarios() {
|
|
try {
|
|
const scenariosPath = 'gherkin-scenarios.json';
|
|
if (!fs.existsSync(scenariosPath)) {
|
|
console.log('⚠️ Gherkin scenarios not found. Run generate-gherkin-reports.js first.');
|
|
return {};
|
|
}
|
|
|
|
return JSON.parse(fs.readFileSync(scenariosPath, 'utf8'));
|
|
} catch (error) {
|
|
console.error('❌ Error loading Gherkin scenarios:', error.message);
|
|
return {};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate updated issue description with Gherkin
|
|
*/
|
|
function generateUpdatedDescription(originalDescription, gherkin, testInfo) {
|
|
const gherkinSection = `
|
|
## 🥒 Gherkin Test Case
|
|
|
|
\`\`\`gherkin
|
|
${gherkin}
|
|
\`\`\`
|
|
|
|
## 📊 Test Execution Results
|
|
- **Status**: ${testInfo.status === 'passed' ? '✅ Passed' : testInfo.status === 'failed' ? '❌ Failed' : '⏭️ Skipped'}
|
|
- **Duration**: ${testInfo.duration}ms
|
|
- **Last Run**: ${new Date().toISOString()}
|
|
- **Environment**: ${process.env.GITHUB_ACTIONS ? 'GitHub Actions' : 'Local'}
|
|
|
|
## 🔗 Automated Test Implementation
|
|
- **File**: \`${testInfo.file}\`
|
|
- **Function**: \`${testInfo.title}\`
|
|
- **Coverage**: 100%
|
|
|
|
## 📈 Functional Area Analysis
|
|
- **Area**: ${testInfo.functionalArea}
|
|
- **Priority**: ${testInfo.status === 'failed' ? '🔴 High' : '🟢 Normal'}
|
|
- **Last Updated**: ${new Date().toISOString()}
|
|
`;
|
|
|
|
// Check if Gherkin section already exists
|
|
if (originalDescription.includes('## 🥒 Gherkin Test Case')) {
|
|
// Replace existing Gherkin section
|
|
const beforeGherkin = originalDescription.split('## 🥒 Gherkin Test Case')[0];
|
|
const afterGherkin = originalDescription.split('## 📈 Functional Area Analysis')[1] || '';
|
|
return beforeGherkin + gherkinSection + (afterGherkin ? '## ' + afterGherkin : '');
|
|
} else {
|
|
// Append Gherkin section
|
|
return originalDescription + gherkinSection;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate test execution comment
|
|
*/
|
|
function generateTestExecutionComment(testInfo, functionalArea) {
|
|
const status = testInfo.status === 'passed' ? '✅ PASSED' :
|
|
testInfo.status === 'failed' ? '❌ FAILED' : '⏭️ SKIPPED';
|
|
|
|
return `## 🧪 Test Execution Update
|
|
|
|
**Test Case**: ${testInfo.tcId}
|
|
**Status**: ${status}
|
|
**Duration**: ${testInfo.duration}ms
|
|
**Functional Area**: ${functionalArea}
|
|
**Timestamp**: ${new Date().toISOString()}
|
|
|
|
### Test Details
|
|
- **Title**: ${testInfo.title}
|
|
- **File**: \`${testInfo.file}\`
|
|
- **Environment**: ${process.env.GITHUB_ACTIONS ? 'GitHub Actions' : 'Local'}
|
|
- **Commit**: ${process.env.GITHUB_SHA || 'N/A'}
|
|
- **Branch**: ${process.env.GITHUB_REF_NAME || 'N/A'}
|
|
|
|
${testInfo.status === 'passed' ?
|
|
'🎉 Test passed successfully! All acceptance criteria met.' :
|
|
testInfo.status === 'failed' ?
|
|
'⚠️ Test failed. Please review and fix issues.' :
|
|
'⏭️ Test was skipped in this run.'
|
|
}
|
|
|
|
### Next Steps
|
|
${testInfo.status === 'failed' ?
|
|
'- [ ] Review test failure logs\n- [ ] Fix implementation issues\n- [ ] Re-run tests' :
|
|
testInfo.status === 'passed' ?
|
|
'- [x] Test implementation verified\n- [x] Acceptance criteria met' :
|
|
'- [ ] Enable skipped test\n- [ ] Verify test conditions'
|
|
}
|
|
|
|
---
|
|
*Auto-generated by Test Management System*`;
|
|
}
|
|
|
|
/**
|
|
* Update TC issue with Gherkin format
|
|
*/
|
|
async function updateTestCaseIssue(tcId, gherkinData) {
|
|
const linearIssueId = TEST_CASE_MAPPING[tcId];
|
|
if (!linearIssueId) {
|
|
console.log(`⚠️ No Linear issue mapping found for ${tcId}`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Generate updated description
|
|
const originalDescription = `# Test Case: ${gherkinData.test.title}
|
|
|
|
**Requirement**: TBD
|
|
**Type**: ${gherkinData.functionalArea}
|
|
**Priority**: High
|
|
|
|
## Test Objective
|
|
Verify that the test case works correctly.
|
|
|
|
## Preconditions
|
|
* Test environment is ready
|
|
* Required data is available
|
|
|
|
## Test Steps
|
|
1. Execute test case
|
|
2. Verify expected results
|
|
3. Check error handling
|
|
|
|
## Expected Results
|
|
* Test passes successfully
|
|
* All assertions are met
|
|
* No errors occur
|
|
|
|
## Implementation Status
|
|
- [ ] Test case defined
|
|
- [ ] Automated test implemented
|
|
- [ ] Test passes consistently`;
|
|
|
|
const updatedDescription = generateUpdatedDescription(
|
|
originalDescription,
|
|
gherkinData.gherkin,
|
|
gherkinData.test
|
|
);
|
|
|
|
// Update issue description
|
|
await mockLinearClient.updateIssue(linearIssueId, {
|
|
description: updatedDescription,
|
|
labels: ['test-case', 'gherkin', 'automated', gherkinData.functionalArea]
|
|
});
|
|
|
|
// Add test execution comment
|
|
const comment = generateTestExecutionComment({
|
|
tcId,
|
|
...gherkinData.test,
|
|
functionalArea: gherkinData.functionalArea
|
|
}, gherkinData.functionalArea);
|
|
|
|
await mockLinearClient.createComment(linearIssueId, comment);
|
|
|
|
console.log(`✅ Updated ${tcId} (${linearIssueId}) with Gherkin format`);
|
|
|
|
} catch (error) {
|
|
console.error(`❌ Error updating ${tcId}:`, error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate functional area summary
|
|
*/
|
|
function generateFunctionalAreaSummary(gherkinScenarios) {
|
|
const summary = {};
|
|
|
|
Object.entries(gherkinScenarios).forEach(([tcId, data]) => {
|
|
const area = data.functionalArea;
|
|
if (!summary[area]) {
|
|
summary[area] = {
|
|
total: 0,
|
|
passed: 0,
|
|
failed: 0,
|
|
skipped: 0,
|
|
testCases: []
|
|
};
|
|
}
|
|
|
|
summary[area].total++;
|
|
summary[area][data.test.status]++;
|
|
summary[area].testCases.push({
|
|
tcId,
|
|
title: data.test.title,
|
|
status: data.test.status
|
|
});
|
|
});
|
|
|
|
return summary;
|
|
}
|
|
|
|
/**
|
|
* Generate functional area report
|
|
*/
|
|
function generateFunctionalAreaReport(summary) {
|
|
let report = `# Functional Area Test Report - ${new Date().toISOString().split('T')[0]}
|
|
|
|
## 📊 Summary by Functional Area
|
|
|
|
`;
|
|
|
|
Object.entries(summary).forEach(([area, data]) => {
|
|
const successRate = data.total > 0 ? Math.round((data.passed / data.total) * 100) : 0;
|
|
const status = successRate === 100 ? '✅' : successRate >= 80 ? '⚠️' : '❌';
|
|
|
|
report += `### ${area} ${status}
|
|
- **Total Tests**: ${data.total}
|
|
- **Passed**: ${data.passed} (${successRate}%)
|
|
- **Failed**: ${data.failed}
|
|
- **Skipped**: ${data.skipped}
|
|
|
|
**Test Cases:**
|
|
${data.testCases.map(tc => `- ${tc.tcId}: ${tc.title} (${tc.status})`).join('\n')}
|
|
|
|
`;
|
|
});
|
|
|
|
// Identify areas with issues
|
|
const problemAreas = Object.entries(summary)
|
|
.filter(([_, data]) => data.failed > 0)
|
|
.map(([area, data]) => `${area}: ${data.failed} failed tests`);
|
|
|
|
if (problemAreas.length > 0) {
|
|
report += `## 🚨 Areas Needing Attention
|
|
${problemAreas.map(area => `- ${area}`).join('\n')}
|
|
|
|
`;
|
|
}
|
|
|
|
report += `## 📈 Recommendations
|
|
1. Fix failed tests in problem areas
|
|
2. Add missing test cases for uncovered functionality
|
|
3. Improve test coverage in weak areas
|
|
4. Set up automated monitoring for test health
|
|
|
|
---
|
|
*Generated: ${new Date().toISOString()}*
|
|
`;
|
|
|
|
return report;
|
|
}
|
|
|
|
/**
|
|
* Main execution
|
|
*/
|
|
async function main() {
|
|
console.log('🔄 Updating TC issues with Gherkin format...');
|
|
|
|
try {
|
|
// Load Gherkin scenarios
|
|
const gherkinScenarios = loadGherkinScenarios();
|
|
|
|
if (Object.keys(gherkinScenarios).length === 0) {
|
|
console.log('⚠️ No Gherkin scenarios found. Exiting.');
|
|
return;
|
|
}
|
|
|
|
// Update each TC issue
|
|
const updatePromises = Object.entries(gherkinScenarios).map(([tcId, data]) =>
|
|
updateTestCaseIssue(tcId, data)
|
|
);
|
|
|
|
await Promise.all(updatePromises);
|
|
|
|
// Generate functional area summary
|
|
const summary = generateFunctionalAreaSummary(gherkinScenarios);
|
|
const report = generateFunctionalAreaReport(summary);
|
|
|
|
// Save functional area report
|
|
fs.writeFileSync('functional-area-report.md', report);
|
|
|
|
console.log('✅ TC issues updated successfully!');
|
|
console.log(`📊 Updated ${Object.keys(gherkinScenarios).length} test cases`);
|
|
console.log(`📈 Functional area report: functional-area-report.md`);
|
|
|
|
// Display summary
|
|
console.log('\n📋 Functional Area Summary:');
|
|
Object.entries(summary).forEach(([area, data]) => {
|
|
const successRate = Math.round((data.passed / data.total) * 100);
|
|
console.log(` ${area}: ${data.passed}/${data.total} (${successRate}%)`);
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error updating TC issues:', error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
module.exports = {
|
|
updateTestCaseIssue,
|
|
generateFunctionalAreaSummary,
|
|
generateFunctionalAreaReport
|
|
};
|