08ea5fbe98
添加用户管理视图、API和状态管理文件
131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import { FullConfig, Suite, TestCase, TestResult, Reporter } from '@playwright/test/reporter';
|
|
import colors from 'ansi-colors';
|
|
|
|
interface TestProgress {
|
|
total: number;
|
|
passed: number;
|
|
failed: number;
|
|
skipped: number;
|
|
current: string;
|
|
startTime: number;
|
|
}
|
|
|
|
class TestProgressBar {
|
|
private progress: TestProgress;
|
|
private barWidth: number = 40;
|
|
private lastUpdate: number = 0;
|
|
|
|
constructor(total: number) {
|
|
this.progress = {
|
|
total,
|
|
passed: 0,
|
|
failed: 0,
|
|
skipped: 0,
|
|
current: '',
|
|
startTime: Date.now()
|
|
};
|
|
}
|
|
|
|
update(testName: string, result?: TestResult) {
|
|
if (result) {
|
|
if (result.status === 'passed') this.progress.passed++;
|
|
else if (result.status === 'failed') this.progress.failed++;
|
|
else if (result.status === 'skipped') this.progress.skipped++;
|
|
}
|
|
this.progress.current = testName;
|
|
this.render();
|
|
}
|
|
|
|
private render() {
|
|
const now = Date.now();
|
|
if (now - this.lastUpdate < 100) return;
|
|
this.lastUpdate = now;
|
|
|
|
const completed = this.progress.passed + this.progress.failed + this.progress.skipped;
|
|
const percentage = Math.min(100, Math.round((completed / this.progress.total) * 100));
|
|
const filled = Math.round((this.barWidth * percentage) / 100);
|
|
const empty = this.barWidth - filled;
|
|
|
|
const elapsed = Date.now() - this.progress.startTime;
|
|
const elapsedSeconds = Math.floor(elapsed / 1000);
|
|
const avgTime = completed > 0 ? elapsed / completed : 0;
|
|
const remaining = (this.progress.total - completed) * avgTime;
|
|
const remainingSeconds = Math.floor(remaining / 1000);
|
|
|
|
const bar = colors.cyan('█').repeat(filled) + colors.gray('░').repeat(empty);
|
|
const statusColor = this.progress.failed > 0 ? colors.red : colors.green;
|
|
const statusText = statusColor(`✓ ${this.progress.passed} | ✗ ${this.progress.failed} | ⊘ ${this.progress.skipped}`);
|
|
|
|
const timeText = colors.gray(`⏱ ${elapsedSeconds}s | ⏳ ~${remainingSeconds}s`);
|
|
const currentText = colors.yellow(this.progress.current.substring(0, 50));
|
|
|
|
process.stdout.write('\r' + ' '.repeat(200));
|
|
process.stdout.write(`\r[${bar}] ${percentage}% | ${statusText} | ${timeText}`);
|
|
process.stdout.write(`\n ${colors.blue('▶')} ${currentText}`);
|
|
}
|
|
|
|
finalize() {
|
|
const elapsed = Date.now() - this.progress.startTime;
|
|
const elapsedSeconds = (elapsed / 1000).toFixed(2);
|
|
|
|
process.stdout.write('\r' + ' '.repeat(200));
|
|
process.stdout.write('\n');
|
|
|
|
const statusColor = this.progress.failed > 0 ? colors.red : colors.green;
|
|
const statusText = statusColor(
|
|
`测试完成: ${this.progress.passed} 通过, ${this.progress.failed} 失败, ${this.progress.skipped} 跳过`
|
|
);
|
|
|
|
console.log(colors.bold('\n' + '═'.repeat(60)));
|
|
console.log(colors.bold(' 测试执行完成'));
|
|
console.log('═'.repeat(60));
|
|
console.log(` ${statusText}`);
|
|
console.log(` ${colors.gray(`总用时: ${elapsedSeconds}秒`)}`);
|
|
console.log(` ${colors.gray(`总测试数: ${this.progress.total}`)}`);
|
|
console.log('═'.repeat(60) + '\n');
|
|
}
|
|
}
|
|
|
|
class ProgressReporter implements Reporter {
|
|
private progressBar: TestProgressBar | null = null;
|
|
private totalTests: number = 0;
|
|
|
|
onBegin(config: FullConfig, suite: Suite) {
|
|
this.totalTests = this.countTests(suite);
|
|
console.log(colors.bold('\n' + '═'.repeat(60)));
|
|
console.log(colors.bold(' 开始执行测试'));
|
|
console.log('═'.repeat(60));
|
|
console.log(` ${colors.blue(`总测试数: ${this.totalTests}`)}`);
|
|
console.log(` ${colors.gray(`测试套件: ${suite.allTests().length}`)}`);
|
|
console.log('═'.repeat(60) + '\n');
|
|
|
|
this.progressBar = new TestProgressBar(this.totalTests);
|
|
}
|
|
|
|
onTestBegin(test: TestCase) {
|
|
if (this.progressBar) {
|
|
this.progressBar.update(test.title);
|
|
}
|
|
}
|
|
|
|
onTestEnd(test: TestCase, result: TestResult) {
|
|
if (this.progressBar) {
|
|
this.progressBar.update(test.title, result);
|
|
}
|
|
}
|
|
|
|
onEnd() {
|
|
if (this.progressBar) {
|
|
this.progressBar.finalize();
|
|
}
|
|
}
|
|
|
|
private countTests(suite: Suite): number {
|
|
let count = 0;
|
|
suite.allTests().forEach(() => count++);
|
|
return count;
|
|
}
|
|
}
|
|
|
|
export default ProgressReporter;
|