Skip to content

Weekly Test Reports #46

Weekly Test Reports

Weekly Test Reports #46

name: Weekly Test Reports
on:
schedule:
- cron: '0 18 * * 5'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: 'pages'
cancel-in-progress: true
jobs:
test-and-report:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download current Pages content
run: |
echo "Downloading current pages content..."
mkdir -p public
curl -f -s https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/ > public/index.html 2>/dev/null || echo "Failed to download main page"
curl -f -s https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/coverage-summary.json > previous-coverage.json 2>/dev/null || echo '{"total":{"lines":{"pct":0},"functions":{"pct":0},"branches":{"pct":0},"statements":{"pct":0}}}' > previous-coverage.json
echo "Downloaded files:"
ls -la public/ 2>/dev/null || echo "No public directory yet"
ls -la previous-coverage.json 2>/dev/null || echo "No previous coverage"
- name: Create reports directory structure
run: |
mkdir -p public/weekly-reports/coverage
mkdir -p public/weekly-reports/tests
- name: Run tests with coverage
run: |
echo "Running tests with coverage..."
npm run test:coverage-report || true
echo "Listing all files after test run:"
ls -la
echo "Checking for coverage directory:"
if [ -d "coverage" ]; then
echo "Coverage directory exists:"
ls -la coverage/
else
echo "No coverage directory found"
fi
echo "Checking for jest-html-reporters files:"
if [ -f "jest_html_reporters.html" ]; then
echo "Jest HTML reporters main file exists"
ls -la jest_html_reporters.html
else
echo "No jest_html_reporters.html found"
fi
if [ -d "jest-html-reporters-attach" ]; then
echo "Jest HTML reporters attach directory exists:"
ls -la jest-html-reporters-attach/
else
echo "No jest-html-reporters-attach directory found"
fi
- name: Copy reports to correct structure
run: |
echo "Copying reports to public/weekly-reports/..."
if [ -d "coverage" ] && [ "$(ls -A coverage)" ]; then
echo "Copying coverage files..."
cp -r coverage/* public/weekly-reports/coverage/ 2>/dev/null || echo "Failed to copy coverage files"
if [ -f "coverage/coverage-summary.json" ]; then
cp coverage/coverage-summary.json public/
cp coverage/coverage-summary.json public/weekly-reports/
echo "Coverage summary copied"
fi
else
echo "No coverage data found, creating empty reports..."
echo '<html><body><h1>No Coverage Data</h1><p>Tests did not generate coverage reports. Check Jest configuration.</p></body></html>' > public/weekly-reports/coverage/index.html
echo '{"total":{"lines":{"pct":0},"functions":{"pct":0},"branches":{"pct":0},"statements":{"pct":0}}}' > public/coverage-summary.json
echo '{"total":{"lines":{"pct":0},"functions":{"pct":0},"branches":{"pct":0},"statements":{"pct":0}}}' > public/weekly-reports/coverage-summary.json
fi
if [ -f "jest_html_reporters.html" ]; then
echo "Copying jest-html-reporters file..."
cp jest_html_reporters.html public/weekly-reports/tests/test-report.html
echo "Jest HTML reporters file copied as test-report.html"
else
echo "Creating placeholder test report..."
echo '<!DOCTYPE html>
<html>
<head><title>Test Results</title></head>
<body>
<h1>No Test Results Available</h1>
<p>Tests may have failed to run or generate reports.</p>
<p>Check the workflow logs for more information.</p>
</body>
</html>' > public/weekly-reports/tests/test-report.html
fi
if [ -d "jest-html-reporters-attach" ] && [ "$(ls -A jest-html-reporters-attach)" ]; then
echo "Copying jest-html-reporters attach files..."
cp -r jest-html-reporters-attach public/weekly-reports/tests/
echo "Jest HTML reporters attach files copied"
else
echo "No jest-html-reporters-attach directory found or it's empty"
fi
- name: Debug - List generated files
run: |
echo "=== Final public directory structure ==="
find public -type f -exec ls -la {} \;
echo ""
echo "=== Content samples ==="
echo "Coverage summary content:"
cat public/coverage-summary.json 2>/dev/null || echo "No coverage summary"
echo ""
echo "Previous coverage content:"
cat previous-coverage.json 2>/dev/null || echo "No previous coverage"
- name: Generate coverage trend analysis
run: |
node -e "
const fs = require('fs');
console.log('Generating trend analysis...');
let currentCoverage = {};
try {
const currentData = fs.readFileSync('public/coverage-summary.json', 'utf8');
currentCoverage = JSON.parse(currentData);
console.log('Current coverage loaded');
} catch (e) {
console.log('Failed to load current coverage, using defaults');
currentCoverage = { total: { lines: { pct: 0 }, functions: { pct: 0 }, branches: { pct: 0 }, statements: { pct: 0 } } };
}
let previousCoverage = {};
try {
const previousData = fs.readFileSync('previous-coverage.json', 'utf8');
previousCoverage = JSON.parse(previousData);
console.log('Previous coverage loaded');
} catch (e) {
console.log('Failed to load previous coverage, using defaults');
previousCoverage = { total: { lines: { pct: 0 }, functions: { pct: 0 }, branches: { pct: 0 }, statements: { pct: 0 } } };
}
function getCoveragePercent(coverage, type) {
try {
return coverage?.total?.[type]?.pct || 0;
} catch (e) {
return 0;
}
}
const current = {
lines: getCoveragePercent(currentCoverage, 'lines'),
functions: getCoveragePercent(currentCoverage, 'functions'),
branches: getCoveragePercent(currentCoverage, 'branches'),
statements: getCoveragePercent(currentCoverage, 'statements')
};
const previous = {
lines: getCoveragePercent(previousCoverage, 'lines'),
functions: getCoveragePercent(previousCoverage, 'functions'),
branches: getCoveragePercent(previousCoverage, 'branches'),
statements: getCoveragePercent(previousCoverage, 'statements')
};
const trends = {
lines: current.lines - previous.lines,
functions: current.functions - previous.functions,
branches: current.branches - previous.branches,
statements: current.statements - previous.statements
};
console.log('Current:', current);
console.log('Previous:', previous);
console.log('Trends:', trends);
// HTML Trend Generation
const trendHtml = \`<!DOCTYPE html>
<html lang=\"uk\">
<head>
<meta charset=\"UTF-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
<title>Test Coverage Trend Report</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
margin: 0;
padding: 20px;
background-color: #f8f9fa;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #e9ecef;
}
.header h1 {
color: #212529;
margin: 0 0 10px 0;
font-size: 2.5em;
}
.date {
font-size: 1.1em;
color: #6c757d;
margin: 0;
}
.trend-positive { color: #28a745; font-weight: bold; }
.trend-negative { color: #dc3545; font-weight: bold; }
.trend-neutral { color: #6c757d; }
.coverage-table {
border-collapse: collapse;
width: 100%;
margin: 30px 0;
font-size: 1.1em;
}
.coverage-table th, .coverage-table td {
border: 1px solid #dee2e6;
padding: 15px;
text-align: left;
}
.coverage-table th {
background-color: #495057;
color: white;
font-weight: 600;
text-align: center;
}
.coverage-table td {
text-align: center;
}
.coverage-table tbody tr:nth-child(even) {
background-color: #f8f9fa;
}
.coverage-table tbody tr:hover {
background-color: #e9ecef;
}
.links {
margin-top: 40px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
}
.links h2 {
margin-top: 0;
color: #495057;
}
.links ul {
list-style-type: none;
padding: 0;
}
.links li {
margin: 15px 0;
}
.links a {
color: #007bff;
text-decoration: none;
padding: 12px 20px;
background: white;
border-radius: 6px;
display: inline-block;
border: 1px solid #dee2e6;
transition: all 0.2s;
font-weight: 500;
}
.links a:hover {
background: #007bff;
color: white;
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,123,255,0.3);
}
.back-link {
margin-bottom: 20px;
}
.back-link a {
color: #6c757d;
text-decoration: none;
font-weight: 500;
}
.back-link a:hover {
color: #007bff;
}
.alert {
padding: 20px;
border-radius: 8px;
margin: 20px 0;
border-left: 4px solid;
}
.alert.info {
background: #e3f2fd;
border-left-color: #2196f3;
color: #0d47a1;
}
.alert h3 {
margin-top: 0;
color: inherit;
}
.troubleshooting ul {
margin: 15px 0;
padding-left: 25px;
}
.troubleshooting li {
margin: 8px 0;
}
</style>
</head>
<body>
<div class=\"container\">
<div class=\"back-link\">
<a href=\"../\">← Back to Main Page</a>
</div>
<div class=\"header\">
<h1>🧪 Test Coverage Trend Report</h1>
<p class=\"date\">📅 Generated: \${new Date().toLocaleString('en-GB', {
timeZone: 'Europe/Kiev',
dateStyle: 'full',
timeStyle: 'medium'
})}</p>
</div>
<div class=\"alert info\">
<h3>📊 About This Report</h3>
<p>This report shows test coverage trends over time. Coverage data is collected automatically and compared with previous runs to show improvement or regression trends.</p>
</div>
<table class=\"coverage-table\">
<thead>
<tr>
<th>📈 Metric</th>
<th>Current</th>
<th>Previous</th>
<th>Trend</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>📄 Lines</strong></td>
<td>\${current.lines.toFixed(2)}%</td>
<td>\${previous.lines.toFixed(2)}%</td>
<td class=\"\${trends.lines > 0 ? 'trend-positive' : trends.lines < 0 ? 'trend-negative' : 'trend-neutral'}\">
\${trends.lines > 0 ? '+' : ''}\${trends.lines.toFixed(2)}%
\${trends.lines > 0 ? ' 📈' : trends.lines < 0 ? ' 📉' : ' ➡️'}
</td>
</tr>
<tr>
<td><strong>⚙️ Functions</strong></td>
<td>\${current.functions.toFixed(2)}%</td>
<td>\${previous.functions.toFixed(2)}%</td>
<td class=\"\${trends.functions > 0 ? 'trend-positive' : trends.functions < 0 ? 'trend-negative' : 'trend-neutral'}\">
\${trends.functions > 0 ? '+' : ''}\${trends.functions.toFixed(2)}%
\${trends.functions > 0 ? ' 📈' : trends.functions < 0 ? ' 📉' : ' ➡️'}
</td>
</tr>
<tr>
<td><strong>🌿 Branches</strong></td>
<td>\${current.branches.toFixed(2)}%</td>
<td>\${previous.branches.toFixed(2)}%</td>
<td class=\"\${trends.branches > 0 ? 'trend-positive' : trends.branches < 0 ? 'trend-negative' : 'trend-neutral'}\">
\${trends.branches > 0 ? '+' : ''}\${trends.branches.toFixed(2)}%
\${trends.branches > 0 ? ' 📈' : trends.branches < 0 ? ' 📉' : ' ➡️'}
</td>
</tr>
<tr>
<td><strong>📝 Statements</strong></td>
<td>\${current.statements.toFixed(2)}%</td>
<td>\${previous.statements.toFixed(2)}%</td>
<td class=\"\${trends.statements > 0 ? 'trend-positive' : trends.statements < 0 ? 'trend-negative' : 'trend-neutral'}\">
\${trends.statements > 0 ? '+' : ''}\${trends.statements.toFixed(2)}%
\${trends.statements > 0 ? ' 📈' : trends.statements < 0 ? ' 📉' : ' ➡️'}
</td>
</tr>
</tbody>
</table>
<div class=\"links\">
<h2>📋 Available Reports</h2>
<ul>
<li><a href=\"./coverage/index.html\">📊 Detailed Coverage Report</a></li>
<li><a href=\"./tests/test-report.html\">🧪 Jest HTML Reporters</a></li>
</ul>
</div>
<div class=\"alert info troubleshooting\">
<h3>🔧 Troubleshooting</h3>
<p>If you see 0% coverage everywhere, here are common issues:</p>
<ul>
<li><strong>Jest Configuration:</strong> Make sure collectCoverage is true and coverageDirectory is set</li>
<li><strong>Test Files:</strong> Ensure your test files match the testMatch pattern</li>
<li><strong>Source Files:</strong> Check that source files are being instrumented properly</li>
<li><strong>Dependencies:</strong> Verify all testing dependencies are installed</li>
<li><strong>Jest HTML Reporters:</strong> Check that jest-html-reporters is properly configured</li>
</ul>
<p><strong>Next Steps:</strong> Check the Actions logs for specific error messages.</p>
</div>
</div>
</body>
</html>\`;
fs.writeFileSync('public/weekly-reports/index.html', trendHtml);
console.log('✅ Trend report generated successfully');
"
- name: Ensure main page exists
run: |
if [ ! -f "public/index.html" ] || [ ! -s "public/index.html" ]; then
echo "Creating fallback main page..."
cat > public/index.html << 'EOF'
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reports Hub</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: white;
text-align: center;
}
.container {
max-width: 800px;
margin: 50px auto;
background: rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
padding: 40px;
border-radius: 20px;
}
h1 { font-size: 3em; margin-bottom: 20px; }
.report-link {
display: inline-block;
background: rgba(255,255,255,0.2);
color: white;
padding: 15px 30px;
margin: 10px;
border-radius: 10px;
text-decoration: none;
transition: all 0.3s;
}
.report-link:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-2px);
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 App Menu</h1>
<p>Test Management and Reporting Center</p>
<div style="margin-top: 40px;">
<a href="./weekly-reports/" class="report-link">
📊 Test Coverage Reports
</a>
</div>
</div>
</body>
</html>
EOF
fi
- name: Final directory check
run: |
echo "=== Final public directory structure ==="
find public -type f | sort
echo ""
echo "=== Verifying key files exist ==="
echo "Main page: $([ -f public/index.html ] && echo "✅" || echo "❌")"
echo "Weekly reports index: $([ -f public/weekly-reports/index.html ] && echo "✅" || echo "❌")"
echo "Coverage summary: $([ -f public/coverage-summary.json ] && echo "✅" || echo "❌")"
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './public'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4