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:
118
frontend/e2e/utils/auth-helper.ts
Normal file
118
frontend/e2e/utils/auth-helper.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* 认证辅助工具
|
||||
* 帮助测试进行用户认证和状态管理
|
||||
*/
|
||||
|
||||
export interface UserSession {
|
||||
token: string;
|
||||
userId: number;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户登录状态
|
||||
*/
|
||||
export async function setAuthenticated(page: Page, userId: number = 10001): Promise<void> {
|
||||
await page.addInitScript((uid: number) => {
|
||||
// 设置localStorage模拟登录
|
||||
localStorage.setItem('token', `test-token-${Date.now()}`);
|
||||
localStorage.setItem('userId', uid.toString());
|
||||
localStorage.setItem('authTime', Date.now().toString());
|
||||
}, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置API Key
|
||||
*/
|
||||
export async function setApiKey(page: Page, apiKey: string): Promise<void> {
|
||||
await page.addInitScript((key: string) => {
|
||||
localStorage.setItem('apiKey', key);
|
||||
}, apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置活动上下文
|
||||
*/
|
||||
export async function setActivityContext(page: Page, activityId: number): Promise<void> {
|
||||
await page.addInitScript((aid: number) => {
|
||||
localStorage.setItem('activityId', aid.toString());
|
||||
localStorage.setItem('currentActivity', JSON.stringify({ id: aid }));
|
||||
}, activityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有认证状态
|
||||
*/
|
||||
export async function clearAuthentication(page: Page): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('userId');
|
||||
localStorage.removeItem('apiKey');
|
||||
localStorage.removeItem('activityId');
|
||||
localStorage.removeItem('authTime');
|
||||
localStorage.removeItem('currentActivity');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已登录
|
||||
*/
|
||||
export async function isAuthenticated(page: Page): Promise<boolean> {
|
||||
return await page.evaluate(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
return !!token;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待登录状态
|
||||
*/
|
||||
export async function waitForAuthentication(page: Page, timeout: number = 5000): Promise<void> {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
if (await isAuthenticated(page)) {
|
||||
return;
|
||||
}
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
throw new Error('等待登录状态超时');
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟OAuth登录流程
|
||||
*/
|
||||
export async function simulateOAuthLogin(
|
||||
page: Page,
|
||||
provider: string = 'wechat'
|
||||
): Promise<void> {
|
||||
// 点击登录按钮
|
||||
const loginButton = page.locator('[data-testid="login-button"], .login-btn, text=登录').first();
|
||||
|
||||
if (await loginButton.isVisible().catch(() => false)) {
|
||||
await loginButton.click();
|
||||
}
|
||||
|
||||
// 等待登录弹窗或跳转
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 设置模拟的登录状态
|
||||
await setAuthenticated(page);
|
||||
|
||||
console.log(` 模拟${provider}登录完成`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*/
|
||||
export async function getCurrentUser(page: Page): Promise<{ userId: number | null; token: string | null }> {
|
||||
return await page.evaluate(() => {
|
||||
return {
|
||||
userId: localStorage.getItem('userId') ? parseInt(localStorage.getItem('userId')!) : null,
|
||||
token: localStorage.getItem('token'),
|
||||
};
|
||||
});
|
||||
}
|
||||
94
frontend/e2e/utils/wait-helper.ts
Normal file
94
frontend/e2e/utils/wait-helper.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* 等待辅助工具
|
||||
* 提供各种等待条件的辅助函数
|
||||
*/
|
||||
|
||||
import { Page, Locator } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* 等待API响应
|
||||
*/
|
||||
export async function waitForApiResponse(
|
||||
page: Page,
|
||||
urlPattern: string | RegExp,
|
||||
timeout: number = 10000
|
||||
): Promise<any> {
|
||||
return await page.waitForResponse(
|
||||
response => {
|
||||
const matches = typeof urlPattern === 'string'
|
||||
? response.url().includes(urlPattern)
|
||||
: urlPattern.test(response.url());
|
||||
return matches && response.status() === 200;
|
||||
},
|
||||
{ timeout }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待页面加载完成
|
||||
*/
|
||||
export async function waitForPageLoad(page: Page, timeout: number = 10000): Promise<void> {
|
||||
await page.waitForLoadState('networkidle', { timeout });
|
||||
await page.waitForLoadState('domcontentloaded', { timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待元素可见并稳定
|
||||
*/
|
||||
export async function waitForStableElement(
|
||||
locator: Locator,
|
||||
timeout: number = 5000
|
||||
): Promise<void> {
|
||||
await locator.waitFor({ state: 'visible', timeout });
|
||||
await locator.waitFor({ state: 'stable', timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待指定时间
|
||||
*/
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待条件满足
|
||||
*/
|
||||
export async function waitForCondition(
|
||||
condition: () => Promise<boolean> | boolean,
|
||||
timeout: number = 5000,
|
||||
interval: number = 100
|
||||
): Promise<void> {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const result = await condition();
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
await sleep(interval);
|
||||
}
|
||||
|
||||
throw new Error('等待条件超时');
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待元素包含特定文本
|
||||
*/
|
||||
export async function waitForText(
|
||||
locator: Locator,
|
||||
text: string,
|
||||
timeout: number = 5000
|
||||
): Promise<void> {
|
||||
await locator.waitFor({ timeout });
|
||||
|
||||
const startTime = Date.now();
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const elementText = await locator.textContent();
|
||||
if (elementText?.includes(text)) {
|
||||
return;
|
||||
}
|
||||
await sleep(100);
|
||||
}
|
||||
|
||||
throw new Error(`等待文本"${text}"超时`);
|
||||
}
|
||||
Reference in New Issue
Block a user