feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* 测试日志记录器
|
||||
* 提供结构化的测试日志记录
|
||||
*/
|
||||
|
||||
export interface LogEntry {
|
||||
timestamp: string;
|
||||
level: 'debug' | 'info' | 'warn' | 'error';
|
||||
message: string;
|
||||
context?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface TestStep {
|
||||
name: string;
|
||||
status: 'pending' | 'running' | 'passed' | 'failed' | 'skipped';
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
duration?: number;
|
||||
logs: LogEntry[];
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
export interface TestResult {
|
||||
testName: string;
|
||||
status: 'passed' | 'failed' | 'skipped';
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
duration: number;
|
||||
steps: TestStep[];
|
||||
logs: LogEntry[];
|
||||
screenshots: string[];
|
||||
error?: Error;
|
||||
retryCount?: number;
|
||||
}
|
||||
|
||||
class TestLogger {
|
||||
private logs: LogEntry[] = [];
|
||||
private steps: TestStep[] = [];
|
||||
private currentStep: TestStep | null = null;
|
||||
private currentTest: TestResult | null = null;
|
||||
|
||||
private getTimestamp(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
private addLog(level: LogEntry['level'], message: string, context?: Record<string, unknown>): void {
|
||||
const entry: LogEntry = {
|
||||
timestamp: this.getTimestamp(),
|
||||
level,
|
||||
message,
|
||||
context,
|
||||
};
|
||||
|
||||
this.logs.push(entry);
|
||||
|
||||
if (this.currentStep) {
|
||||
this.currentStep.logs.push(entry);
|
||||
}
|
||||
|
||||
// 控制台输出
|
||||
const consoleMessage = `[${entry.timestamp}] [${level.toUpperCase()}] ${message}`;
|
||||
switch (level) {
|
||||
case 'debug':
|
||||
console.debug(consoleMessage);
|
||||
break;
|
||||
case 'info':
|
||||
console.info(consoleMessage);
|
||||
break;
|
||||
case 'warn':
|
||||
console.warn(consoleMessage);
|
||||
break;
|
||||
case 'error':
|
||||
console.error(consoleMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug(message: string, context?: Record<string, unknown>): void {
|
||||
this.addLog('debug', message, context);
|
||||
}
|
||||
|
||||
info(message: string, context?: Record<string, unknown>): void {
|
||||
this.addLog('info', message, context);
|
||||
}
|
||||
|
||||
warn(message: string, context?: Record<string, unknown>): void {
|
||||
this.addLog('warn', message, context);
|
||||
}
|
||||
|
||||
error(message: string, error?: Error, context?: Record<string, unknown>): void {
|
||||
this.addLog('error', message, {
|
||||
...context,
|
||||
error: error?.message,
|
||||
stack: error?.stack,
|
||||
});
|
||||
}
|
||||
|
||||
startTest(testName: string): void {
|
||||
this.currentTest = {
|
||||
testName,
|
||||
status: 'passed',
|
||||
startTime: this.getTimestamp(),
|
||||
endTime: '',
|
||||
duration: 0,
|
||||
steps: [],
|
||||
logs: [],
|
||||
screenshots: [],
|
||||
};
|
||||
this.logs = [];
|
||||
this.steps = [];
|
||||
this.info(`开始测试: ${testName}`);
|
||||
}
|
||||
|
||||
endTest(testName: string, status: 'passed' | 'failed' | 'skipped', error?: Error): void {
|
||||
if (this.currentTest) {
|
||||
this.currentTest.status = status;
|
||||
this.currentTest.endTime = this.getTimestamp();
|
||||
this.currentTest.duration = new Date(this.currentTest.endTime).getTime() -
|
||||
new Date(this.currentTest.startTime).getTime();
|
||||
this.currentTest.steps = this.steps;
|
||||
this.currentTest.logs = this.logs;
|
||||
|
||||
if (error) {
|
||||
this.currentTest.error = error;
|
||||
}
|
||||
|
||||
this.info(`测试结束: ${testName} - ${status}`, {
|
||||
duration: this.currentTest.duration,
|
||||
stepsCount: this.steps.length,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
startStep(stepName: string): void {
|
||||
if (this.currentStep) {
|
||||
this.endStep(this.currentStep.name, 'failed');
|
||||
}
|
||||
|
||||
this.currentStep = {
|
||||
name: stepName,
|
||||
status: 'running',
|
||||
startTime: this.getTimestamp(),
|
||||
logs: [],
|
||||
};
|
||||
|
||||
this.info(`开始步骤: ${stepName}`);
|
||||
}
|
||||
|
||||
endStep(stepName: string, status: TestStep['status'], error?: Error): void {
|
||||
if (this.currentStep && this.currentStep.name === stepName) {
|
||||
this.currentStep.status = status;
|
||||
this.currentStep.endTime = this.getTimestamp();
|
||||
|
||||
if (this.currentStep.startTime) {
|
||||
this.currentStep.duration = new Date(this.currentStep.endTime).getTime() -
|
||||
new Date(this.currentStep.startTime).getTime();
|
||||
}
|
||||
|
||||
if (error) {
|
||||
this.currentStep.error = error;
|
||||
}
|
||||
|
||||
this.steps.push(this.currentStep);
|
||||
this.info(`步骤结束: ${stepName} - ${status}`, {
|
||||
duration: this.currentStep.duration,
|
||||
});
|
||||
|
||||
this.currentStep = null;
|
||||
}
|
||||
}
|
||||
|
||||
addScreenshot(path: string): void {
|
||||
if (this.currentTest) {
|
||||
this.currentTest.screenshots.push(path);
|
||||
}
|
||||
this.info(`截图已保存: ${path}`);
|
||||
}
|
||||
|
||||
getCurrentTest(): TestResult | null {
|
||||
return this.currentTest;
|
||||
}
|
||||
|
||||
getLogs(): LogEntry[] {
|
||||
return this.logs;
|
||||
}
|
||||
|
||||
getSteps(): TestStep[] {
|
||||
return this.steps;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.logs = [];
|
||||
this.steps = [];
|
||||
this.currentStep = null;
|
||||
this.currentTest = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成测试执行摘要
|
||||
*/
|
||||
generateSummary(): Record<string, unknown> {
|
||||
const passed = this.steps.filter(s => s.status === 'passed').length;
|
||||
const failed = this.steps.filter(s => s.status === 'failed').length;
|
||||
const skipped = this.steps.filter(s => s.status === 'skipped').length;
|
||||
|
||||
return {
|
||||
totalSteps: this.steps.length,
|
||||
passed,
|
||||
failed,
|
||||
skipped,
|
||||
totalLogs: this.logs.length,
|
||||
errors: this.logs.filter(l => l.level === 'error').length,
|
||||
warnings: this.logs.filter(l => l.level === 'warn').length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const testLogger = new TestLogger();
|
||||
Reference in New Issue
Block a user