feat: complete system test fixes - 100% pass rate (85/85)

- Fixed all form tests (20/20 passing)
- Fixed all performance tests (35/35 passing)
- Fixed all SEO and accessibility tests (30/30 passing)
- Enhanced test framework with custom reporting
- Added performance baseline tracking
- Improved test reliability and error handling
This commit is contained in:
张翔
2026-03-06 19:37:02 +08:00
parent e6524044ef
commit 4c8714c12d
27 changed files with 5072 additions and 264 deletions
@@ -0,0 +1,35 @@
import * as fs from 'fs';
import * as path from 'path';
import { TestDataFactory } from './TestDataFactory';
export class TestDataCleaner {
static async cleanupDatabase(): Promise<void> {
console.log('清理测试数据库...');
}
static async cleanupFiles(): Promise<void> {
const testResultsDir = path.join(process.cwd(), 'test-results');
if (fs.existsSync(testResultsDir)) {
const files = fs.readdirSync(testResultsDir);
for (const file of files) {
const filePath = path.join(testResultsDir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
fs.rmSync(filePath, { recursive: true, force: true });
} else {
fs.unlinkSync(filePath);
}
}
}
}
static async cleanupCache(): Promise<void> {
TestDataFactory.clearCache();
}
static async cleanupAll(): Promise<void> {
await this.cleanupDatabase();
await this.cleanupFiles();
await this.cleanupCache();
}
}
@@ -0,0 +1,68 @@
import { formData, performanceThresholds } from '../../config/test-data';
export interface ContactFormData {
name: string;
email: string;
phone: string;
message: string;
subject?: string;
}
export interface PerformanceData {
url: string;
thresholds: typeof performanceThresholds;
}
export interface SEOData {
url: string;
expectedTitle: string;
expectedDescription: string;
}
export class TestDataFactory {
private static cache: Map<string, any> = new Map();
static createContactForm(overrides?: Partial<ContactFormData>): ContactFormData {
const cacheKey = 'contact-form';
if (!this.cache.has(cacheKey)) {
this.cache.set(cacheKey, {
name: '测试用户',
email: 'test@example.com',
phone: '13800138000',
message: '这是一条测试消息,用于测试表单提交功能',
subject: '测试主题'
});
}
return { ...this.cache.get(cacheKey), ...overrides };
}
static createPerformanceData(overrides?: Partial<PerformanceData>): PerformanceData {
const cacheKey = 'performance-data';
if (!this.cache.has(cacheKey)) {
this.cache.set(cacheKey, {
url: 'http://localhost:3000',
thresholds: performanceThresholds
});
}
return { ...this.cache.get(cacheKey), ...overrides };
}
static createSEOData(overrides?: Partial<SEOData>): SEOData {
const cacheKey = 'seo-data';
if (!this.cache.has(cacheKey)) {
this.cache.set(cacheKey, {
url: 'http://localhost:3000',
expectedTitle: 'Novalon - 创新科技解决方案',
expectedDescription: 'Novalon提供专业的科技解决方案'
});
}
return { ...this.cache.get(cacheKey), ...overrides };
}
static clearCache(): void {
this.cache.clear();
}
}
@@ -0,0 +1,37 @@
export class TestDataManager {
private data: Map<string, any> = new Map();
private version: string = '1.0.0';
setData(key: string, value: any): void {
this.data.set(key, value);
}
getData(key: string): any {
return this.data.get(key);
}
getVersion(): string {
return this.version;
}
setVersion(version: string): void {
this.version = version;
}
export(): string {
return JSON.stringify({
version: this.version,
data: Object.fromEntries(this.data)
}, null, 2);
}
import(json: string): void {
const imported = JSON.parse(json);
this.version = imported.version;
this.data = new Map(Object.entries(imported.data));
}
clear(): void {
this.data.clear();
}
}
@@ -0,0 +1,37 @@
export class TestDataVersion {
private versions: Map<string, string> = new Map();
private currentVersion: string = '1.0.0';
setCurrentVersion(version: string): void {
this.currentVersion = version;
}
getCurrentVersion(): string {
return this.currentVersion;
}
saveVersion(key: string, data: string): void {
this.versions.set(`${this.currentVersion}-${key}`, data);
}
getVersion(key: string): string | undefined {
return this.versions.get(`${this.currentVersion}-${key}`);
}
listVersions(): string[] {
return Array.from(new Set(Array.from(this.versions.keys()).map(k => k.split('-')[0])));
}
export(): string {
return JSON.stringify({
currentVersion: this.currentVersion,
versions: Object.fromEntries(this.versions)
}, null, 2);
}
import(json: string): void {
const imported = JSON.parse(json);
this.currentVersion = imported.currentVersion;
this.versions = new Map(Object.entries(imported.versions));
}
}
@@ -0,0 +1,15 @@
import { Page } from '@playwright/test';
export class TestWarmup {
static async warmupBrowser(page: Page): Promise<void> {
await page.goto('about:blank');
await page.waitForTimeout(100);
}
static async warmupServer(baseUrl: string): Promise<void> {
const response = await fetch(baseUrl);
if (!response.ok) {
throw new Error(`Server warmup failed: ${response.status}`);
}
}
}