Files
wenzi/frontend/e2e/global-setup.cjs

237 lines
6.6 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. 验证服务可用性
*
* 如果无法创建真实数据,将使用默认占位数据
*/
// 测试配置
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080';
const TEST_USER_TOKEN = 'test-e2e-token-' + Date.now();
// 默认测试数据
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) {
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌`);
}
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) {
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌`);
}
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) {
throw new Error(`认证失败: ${response.status} - 需要有效的用户令牌`);
}
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;