test(cache): 修复CacheConfigTest边界值测试
- 修改 shouldVerifyCacheManager_withMaximumIntegerTtl 为 shouldVerifyCacheManager_withMaximumAllowedTtl - 使用正确的最大TTL值(10080分钟,7天)而不是 Integer.MAX_VALUE - 新增 shouldThrowException_whenTtlExceedsMaximum 测试验证边界检查 - 所有1266个测试用例通过 - 覆盖率: 指令81.89%, 行88.48%, 分支51.55% docs: 添加项目状态报告 - 生成 PROJECT_STATUS_REPORT.md 详细记录项目当前状态 - 包含质量指标、已完成功能、待办事项和技术债务
This commit is contained in:
212
frontend/e2e/fixtures/test-data.ts
Normal file
212
frontend/e2e/fixtures/test-data.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { test as baseTest, expect, Page, APIRequestContext } from '@playwright/test';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
/**
|
||||
* E2E测试夹具(Fixtures)
|
||||
* 提供测试数据、API客户端、认证信息等
|
||||
*/
|
||||
|
||||
// 测试数据接口
|
||||
export interface TestData {
|
||||
activityId: number;
|
||||
apiKey: string;
|
||||
userId: number;
|
||||
shortCode: string;
|
||||
baseUrl: string;
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
// API响应类型
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
// API客户端类
|
||||
export class ApiClient {
|
||||
constructor(
|
||||
private request: APIRequestContext,
|
||||
private apiKey: string,
|
||||
private userToken: string,
|
||||
private baseURL: string
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 发送认证请求
|
||||
*/
|
||||
async get<T>(endpoint: string, headers?: Record<string, string>): Promise<ApiResponse<T>> {
|
||||
const response = await this.request.get(`${this.baseURL}${endpoint}`, {
|
||||
headers: {
|
||||
'X-API-Key': this.apiKey,
|
||||
'Authorization': `Bearer ${this.userToken}`,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送POST请求
|
||||
*/
|
||||
async post<T>(endpoint: string, data: any, headers?: Record<string, string>): Promise<ApiResponse<T>> {
|
||||
const response = await this.request.post(`${this.baseURL}${endpoint}`, {
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': this.apiKey,
|
||||
'Authorization': `Bearer ${this.userToken}`,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证API Key
|
||||
*/
|
||||
async validateApiKey(apiKey: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await this.request.post(`${this.baseURL}/api/v1/api-keys/validate`, {
|
||||
data: { apiKey },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.userToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
return response.status() === 200;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动列表
|
||||
*/
|
||||
async getActivities(): Promise<ApiResponse<any[]>> {
|
||||
return this.get('/api/v1/activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动详情
|
||||
*/
|
||||
async getActivity(activityId: number): Promise<ApiResponse<any>> {
|
||||
return this.get(`/api/v1/activities/${activityId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动统计
|
||||
*/
|
||||
async getActivityStats(activityId: number): Promise<ApiResponse<any>> {
|
||||
return this.get(`/api/v1/activities/${activityId}/stats`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排行榜
|
||||
*/
|
||||
async getLeaderboard(activityId: number, page: number = 0, size: number = 10): Promise<ApiResponse<any>> {
|
||||
return this.get(`/api/v1/activities/${activityId}/leaderboard?page=${page}&size=${size}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建短链
|
||||
*/
|
||||
async createShortLink(originalUrl: string, activityId: number): Promise<ApiResponse<any>> {
|
||||
return this.post('/api/v1/internal/shorten', {
|
||||
originalUrl,
|
||||
activityId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分享指标
|
||||
*/
|
||||
async getShareMetrics(activityId: number): Promise<ApiResponse<any>> {
|
||||
return this.get(`/api/v1/share/metrics?activityId=${activityId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载测试数据
|
||||
*/
|
||||
function loadTestData(): TestData {
|
||||
// ES模块中获取当前文件目录
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const testDataPath = path.join(__dirname, '..', '.e2e-test-data.json');
|
||||
|
||||
// 默认测试数据
|
||||
const defaultData: TestData = {
|
||||
activityId: 1,
|
||||
apiKey: 'test-api-key',
|
||||
userId: 10001,
|
||||
shortCode: 'test123',
|
||||
baseUrl: process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173',
|
||||
apiBaseUrl: process.env.API_BASE_URL || 'http://localhost:8080',
|
||||
};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(testDataPath)) {
|
||||
const data = JSON.parse(fs.readFileSync(testDataPath, 'utf-8'));
|
||||
return {
|
||||
...defaultData,
|
||||
...data,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('无法加载测试数据,使用默认值');
|
||||
}
|
||||
|
||||
return defaultData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展的测试夹具类型
|
||||
*/
|
||||
export interface TestFixtures {
|
||||
testData: TestData;
|
||||
apiClient: ApiClient;
|
||||
authenticatedPage: Page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建扩展的test对象
|
||||
*/
|
||||
export const test = baseTest.extend<TestFixtures>({
|
||||
// 测试数据
|
||||
testData: async ({}, use) => {
|
||||
const data = loadTestData();
|
||||
await use(data);
|
||||
},
|
||||
|
||||
// API客户端
|
||||
apiClient: async ({ request, testData }, use) => {
|
||||
const client = new ApiClient(
|
||||
request,
|
||||
testData.apiKey,
|
||||
'test-e2e-token',
|
||||
testData.apiBaseUrl
|
||||
);
|
||||
await use(client);
|
||||
},
|
||||
|
||||
// 已认证的页面
|
||||
authenticatedPage: async ({ page, testData }, use) => {
|
||||
// 设置localStorage模拟登录状态
|
||||
await page.addInitScript((data) => {
|
||||
localStorage.setItem('token', 'test-e2e-token');
|
||||
localStorage.setItem('userId', data.userId.toString());
|
||||
localStorage.setItem('apiKey', data.apiKey);
|
||||
localStorage.setItem('activityId', data.activityId.toString());
|
||||
}, testData);
|
||||
|
||||
await use(page);
|
||||
},
|
||||
});
|
||||
|
||||
export { expect };
|
||||
Reference in New Issue
Block a user