Files
wenzi/frontend/e2e/global-setup.cjs
Your Name 5f5597ef0f
Some checks failed
CI / build_test_package (push) Has been cancelled
CI / auto_merge (push) Has been cancelled
chore: sync project snapshot for gitea/github upload
2026-03-26 15:59:53 +08:00

255 lines
7.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const axios = require('axios');
const fs = require('fs');
const path = require('path');
/**
* Playwright E2E全局设置
* 在测试开始前执行:
* 1. 创建测试活动
* 2. 生成API Key
* 3. 准备测试数据
* 4. 验证服务可用性
*
* 凭证配置:
* - E2E_USER_TOKEN: 真实用户令牌(可选)
* * 如果设置:使用真实凭证创建测试数据,严格模式
* * 如果未设置使用假token降级模式smoke测试
* - E2E_STRICT=true: 严格模式,无真实凭证时测试会失败并明确提示
*
* 如果无法创建真实数据,将使用默认占位数据
*/
// 测试配置
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080';
// E2E_USER_TOKEN 环境变量有真实凭证时直接使用无则生成假token用于服务就绪检测
const E2E_USER_TOKEN = process.env.E2E_USER_TOKEN;
const TEST_USER_TOKEN = E2E_USER_TOKEN || 'test-e2e-token-' + Date.now();
const USE_REAL_CREDENTIALS = Boolean(E2E_USER_TOKEN);
// 默认测试数据
const DEFAULT_TEST_DATA = {
activityId: 1,
apiKey: 'test-api-key-000000000000',
userToken: 'test-e2e-token',
userId: 10001,
shortCode: 'test123',
baseUrl: process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173',
apiBaseUrl: API_BASE_URL,
};
async function globalSetup(config) {
console.log('🚀 开始E2E测试全局设置...');
console.log(` API地址: ${API_BASE_URL}`);
const testDataPath = path.join(__dirname, '..', '.e2e-test-data.json');
try {
// 1. 等待后端服务就绪
const backendReady = await waitForBackend();
if (!backendReady) {
throw new Error('后端服务未能启动');
}
// 2. 尝试创建测试活动
const activity = await createTestActivity();
console.log(` ✅ 创建测试活动: ID=${activity.id}`);
// 3. 生成API Key
const apiKey = await generateApiKey(activity.id);
console.log(` ✅ 生成API Key: ${apiKey.substring(0, 20)}...`);
// 4. 创建短链
const shortCode = await createShortLink(activity.id, apiKey);
console.log(` ✅ 创建短链: ${shortCode}`);
// 5. 保存全局测试数据
const testData = {
activityId: activity.id,
apiKey: apiKey,
userToken: TEST_USER_TOKEN,
userId: 10001,
shortCode: shortCode,
baseUrl: DEFAULT_TEST_DATA.baseUrl,
apiBaseUrl: API_BASE_URL,
};
// 写入文件供进程间通信
fs.writeFileSync(testDataPath, JSON.stringify(testData, null, 2));
console.log('✅ 全局设置完成!');
console.log('');
} catch (error) {
// E2E_STRICT模式下不允许降级
if (process.env.E2E_STRICT === 'true') {
console.error('❌ E2E严格模式无法创建真实测试数据');
console.error(` 原因: ${error instanceof Error ? error.message : String(error)}`);
console.error(' 请配置有效的后端凭证后重试');
process.exit(1);
}
console.warn('⚠️ 无法创建真实测试数据,使用默认占位数据');
console.warn(` 原因: ${error instanceof Error ? error.message : String(error)}`);
console.warn(' 需要完整测试请配置有效的后端凭证');
// 使用默认数据
fs.writeFileSync(testDataPath, JSON.stringify(DEFAULT_TEST_DATA, null, 2));
console.log('✅ 全局设置完成(降级模式)');
console.log('');
}
}
/**
* 等待后端服务就绪
*/
async function waitForBackend() {
const maxRetries = 15;
const retryDelay = 2000;
for (let i = 0; i < maxRetries; i++) {
try {
const response = await axios.get(`${API_BASE_URL}/api/v1/activities`, {
timeout: 5000,
headers: {
'X-API-Key': 'test',
'Authorization': 'Bearer test',
},
maxRedirects: 0, // 不自动重定向
validateStatus: (status) => status < 500, // 接受4xx状态码
});
// 只要能连接上就算成功不管返回401还是200
console.log(' ✅ 后端服务已就绪');
return true;
} catch (error) {
if (i < maxRetries - 1) {
process.stdout.write(` ⏳ 等待后端服务... (${i + 1}/${maxRetries})\r`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
}
return false;
}
/**
* 创建测试活动
*/
async function createTestActivity() {
const now = new Date();
const startTime = new Date(now.getTime() + 60 * 60 * 1000); // 1小时后
const endTime = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 7天后
const response = await axios.post(
`${API_BASE_URL}/api/v1/activities`,
{
name: `E2E测试活动-${Date.now()}`,
startTime: startTime.toISOString(),
endTime: endTime.toISOString(),
rewardCalculationMode: 'delta',
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'test-setup-key',
'Authorization': `Bearer ${TEST_USER_TOKEN}`,
},
maxRedirects: 0,
validateStatus: (status) => status === 201 || status === 401 || status === 403,
}
);
if (response.status === 401 || response.status === 403) {
if (USE_REAL_CREDENTIALS) {
throw new Error(`认证失败: ${response.status} - 提供的 E2E_USER_TOKEN 无效,请检查凭证是否过期`);
}
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌(请设置 E2E_USER_TOKEN 环境变量)`);
}
if (response.status !== 201) {
throw new Error(`创建活动失败: ${response.status}`);
}
return {
id: response.data.data.id,
name: response.data.data.name,
};
}
/**
* 生成API Key
*/
async function generateApiKey(activityId) {
const response = await axios.post(
`${API_BASE_URL}/api/v1/keys`,
{
name: 'E2E测试密钥',
activityId: activityId,
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${TEST_USER_TOKEN}`,
},
maxRedirects: 0,
validateStatus: (status) => status === 201 || status === 401 || status === 403,
}
);
if (response.status === 401 || response.status === 403) {
if (USE_REAL_CREDENTIALS) {
throw new Error(`认证失败: ${response.status} - 提供的 E2E_USER_TOKEN 无效,请检查凭证是否过期`);
}
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌(请设置 E2E_USER_TOKEN 环境变量)`);
}
if (response.status !== 201) {
throw new Error(`生成API Key失败: ${response.status}`);
}
return response.data.data.apiKey;
}
/**
* 创建测试短链
*/
async function createShortLink(activityId, apiKey) {
const originalUrl = `https://example.com/landing?activityId=${activityId}&inviter=10001`;
const response = await axios.post(
`${API_BASE_URL}/api/v1/internal/shorten`,
{
originalUrl: originalUrl,
activityId: activityId,
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey,
'Authorization': `Bearer ${TEST_USER_TOKEN}`,
},
maxRedirects: 0,
validateStatus: (status) => status === 201 || status === 401 || status === 403,
}
);
if (response.status === 401 || response.status === 403) {
if (USE_REAL_CREDENTIALS) {
throw new Error(`认证失败: ${response.status} - 提供的 E2E_USER_TOKEN 无效,请检查凭证是否过期`);
}
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌(请设置 E2E_USER_TOKEN 环境变量)`);
}
if (response.status !== 201) {
throw new Error(`创建短链失败: ${response.status}`);
}
// 从响应中提取code
const shortUrl = response.data.data.shortUrl || response.data.data.url;
const code = shortUrl.split('/').pop();
return code || 'test123';
}
module.exports = globalSetup;