playwright-test-workflow
Version:
Global test workflow package for Playwright with custom reporters
129 lines (111 loc) • 5.09 kB
JavaScript
const fs = require('fs');
const path = require('path');
class CustomHTMLReporter {
constructor(options = {}) {
this.outputDir = options.outputDir || 'test-results';
this.results = [];
this.testGroupPatterns = options.testGroupPatterns || this.getDefaultPatterns();
}
getDefaultPatterns() {
return {
'TEST#1': ['load', 'display', 'show', 'heading', 'button', 'input', 'result display'],
'TEST#2': ['calculate', 'sum', 'negative', 'zero', 'large', 'decimal'],
'TEST#3': ['empty', 'non-numeric', 'precision', 'error', 'validation'],
'TEST#4': ['responsive', 'clickable', 'accept', 'update', 'ui', 'ux']
};
}
determineTestGroup(testName) {
const lowerName = testName.toLowerCase();
for (const [group, patterns] of Object.entries(this.testGroupPatterns)) {
if (patterns.some(pattern => lowerName.includes(pattern))) {
return group;
}
}
return 'UNKNOWN';
}
onTestEnd(test, result) {
const status = result.status === 'passed' ? 'PASS' : 'FAIL';
const testName = test.title;
const error = result.error ? result.error.message : '';
const duration = result.duration || 0;
const testGroup = this.determineTestGroup(testName);
this.results.push({
name: testName,
status: status,
error: error,
group: testGroup,
duration: duration
});
}
onEnd() {
if (!fs.existsSync(this.outputDir)) {
fs.mkdirSync(this.outputDir, { recursive: true });
}
const testGroups = [...new Set(this.results.map(r => r.group))];
testGroups.forEach(group => {
if (group === 'UNKNOWN') return;
const groupTests = this.results.filter(t => t.group === group);
const groupPassed = groupTests.filter(t => t.status === 'PASS').length;
const groupFailed = groupTests.filter(t => t.status === 'FAIL').length;
const groupTotal = groupTests.length;
const html = this.generateHTML(group, groupTests, groupPassed, groupFailed, groupTotal);
const groupFile = path.join(this.outputDir, `${group}-results.html`);
fs.writeFileSync(groupFile, html);
});
}
generateHTML(group, tests, passed, failed, total) {
return `
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${group} Test Results</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
.container { max-width: 1000px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h1 { color: #333; border-bottom: 2px solid #ddd; padding-bottom: 10px; }
.summary { background: #f9f9f9; padding: 15px; border-radius: 5px; margin: 20px 0; }
.summary-item { display: inline-block; margin: 0 20px 0 0; }
.pass { color: #44aa44; font-weight: bold; }
.fail { color: #ff4444; font-weight: bold; }
.test-item { margin: 10px 0; padding: 10px; border-left: 4px solid #ddd; background: #fafafa; }
.test-item.pass { border-left-color: #44aa44; }
.test-item.fail { border-left-color: #ff4444; background: #fff5f5; }
.test-name { font-weight: bold; margin-bottom: 5px; }
.test-error { color: #ff4444; font-size: 0.9em; margin-top: 5px; padding: 5px; background: #ffeeee; border-radius: 3px; }
.test-duration { color: #666; font-size: 0.8em; }
.status-badge { padding: 2px 6px; border-radius: 3px; color: white; font-size: 0.8em; font-weight: bold; }
.status-pass { background: #44aa44; }
.status-fail { background: #ff4444; }
</style>
</head>
<body>
<div class="container">
<h1>${group} Test Results</h1>
<div class="summary">
<div class="summary-item"><strong>Total Tests:</strong> ${total}</div>
<div class="summary-item"><strong class="pass">Passed:</strong> ${passed}</div>
<div class="summary-item"><strong class="fail">Failed:</strong> ${failed}</div>
<div class="summary-item"><strong>Success Rate:</strong> ${Math.round((passed / total) * 100)}%</div>
</div>
<div class="test-list">
${tests.map(test => `
<div class="test-item ${test.status.toLowerCase()}">
<div class="test-name">
<span class="status-badge status-${test.status.toLowerCase()}">${test.status}</span>
${test.name}
</div>
<div class="test-duration">Duration: ${test.duration}ms</div>
${test.error ? `<div class="test-error">Error: ${test.error}</div>` : ''}
</div>
`).join('')}
</div>
<div style="margin-top: 30px; text-align: center; color: #666; font-size: 0.9em;">
Generated on ${new Date().toLocaleString()}
</div>
</div>
</body>
</html>`;
}
}
module.exports = CustomHTMLReporter;