import { FullConfig } from '@playwright/test'; import axios from 'axios'; import fs from 'fs'; import path from '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(); // 全局测试数据存储 export interface GlobalTestData { activityId: number; apiKey: string; userId: number; shortCode: string; } declare global { var __TEST_DATA__: GlobalTestData; } async function globalSetup(config: FullConfig) { console.log('🚀 开始E2E测试全局设置...'); console.log(` API地址: ${API_BASE_URL}`); try { // 1. 等待后端服务就绪 await waitForBackend(); // 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: GlobalTestData = { activityId: activity.id, apiKey: apiKey, userId: 10001, shortCode: shortCode, }; // 写入全局变量供测试使用 globalThis.__TEST_DATA__ = testData; // 也写入文件供进程间通信 const testDataPath = path.join(__dirname, '..', '.e2e-test-data.json'); fs.writeFileSync(testDataPath, JSON.stringify(testData, null, 2)); console.log('✅ 全局设置完成!'); console.log(''); } catch (error) { console.error('❌ 全局设置失败:', error); throw error; } } /** * 等待后端服务就绪 */ async function waitForBackend(): Promise { const maxRetries = 30; 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', }, }); if (response.status === 200) { console.log(' ✅ 后端服务已就绪'); return; } } catch (error) { if (i < maxRetries - 1) { process.stdout.write(` ⏳ 等待后端服务... (${i + 1}/${maxRetries})\r`); await new Promise(resolve => setTimeout(resolve, retryDelay)); } } } throw new Error('后端服务未能启动'); } /** * 创建测试活动 */ async function createTestActivity(): Promise<{ id: number; name: string }> { 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}`, }, } ); 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: number): Promise { const response = await axios.post( `${API_BASE_URL}/api/v1/activities/${activityId}/api-keys`, { name: 'E2E测试密钥', activityId: activityId, }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_USER_TOKEN}`, }, } ); if (response.status !== 201) { throw new Error(`生成API Key失败: ${response.status}`); } return response.data.data.apiKey; } /** * 创建测试短链 */ async function createShortLink(activityId: number, apiKey: string): Promise { 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}`, }, } ); 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; } export default globalSetup;