import { test, expect } from '@playwright/test' import path from 'path' import { fileURLToPath } from 'url' import fs from 'fs' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) // 测试配置 const TENANT_CODE = 'super' const USERNAME = 'admin' const PASSWORD = 'admin123' // 确保测试图片存在 const FIXTURES_DIR = path.join(__dirname, 'fixtures') const TEST_IMAGE_PATH = path.join(FIXTURES_DIR, 'test-upload.png') if (!fs.existsSync(FIXTURES_DIR)) { fs.mkdirSync(FIXTURES_DIR, { recursive: true }) } if (!fs.existsSync(TEST_IMAGE_PATH)) { const pngData = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==', 'base64' ) fs.writeFileSync(TEST_IMAGE_PATH, pngData) } test.describe('OSS 直传上传', () => { // 单独给这个测试更长的超时 test.setTimeout(60000) test('登录 -> 赛事创建页 -> 上传封面图片到 OSS', async ({ page }) => { // 监听网络请求,捕获 OSS 相关请求 const ossTokenRequests: string[] = [] const ossUploadRequests: string[] = [] page.on('request', (req) => { const url = req.url() if (url.includes('/upload/oss/token')) { ossTokenRequests.push(url) } if (url.includes('aliyuncs.com')) { ossUploadRequests.push(url) } }) // ========== 1. 登录 ========== await page.goto(`/${TENANT_CODE}/login`) await page.waitForLoadState('domcontentloaded') // 等待登录表单可见 await page.locator('input[placeholder="请输入用户名"]').waitFor({ state: 'visible', timeout: 10000 }) // 填写 Ant Design 表单 await page.locator('input[placeholder="请输入用户名"]').click() await page.locator('input[placeholder="请输入用户名"]').fill(USERNAME) await page.locator('input[placeholder="请输入密码"]').click() await page.locator('input[placeholder="请输入密码"]').fill(PASSWORD) // 点击登录按钮 const loginBtn = page.locator('button[type="submit"]').first() await loginBtn.click() // 等待登录成功(URL 不再包含 /login) await page.waitForFunction(() => !window.location.pathname.includes('/login'), { timeout: 15000 }) console.log('[1] 登录成功, 当前页面:', page.url()) // ========== 2. 进入赛事创建页 ========== await page.goto(`/${TENANT_CODE}/contests/create`) await page.waitForLoadState('domcontentloaded') // 等待表单页面加载 await page.locator('input[placeholder*="活动名称"], input[placeholder*="名称"]').first().waitFor({ timeout: 10000 }) console.log('[2] 赛事创建页加载成功') // ========== 3. 上传封面图片 ========== // 直接用全局的 file input(Ant Design Upload 的隐藏 input) const fileInputs = page.locator('input[type="file"]') const fileCount = await fileInputs.count() console.log('[3] 发现 file input 数量:', fileCount) // 第一个 file input 对应封面上传 await fileInputs.first().setInputFiles(TEST_IMAGE_PATH) console.log('[3] 已选择封面文件,等待 OSS 上传...') // 等待网络请求完成 await page.waitForTimeout(5000) // ========== 4. 验证 ========== console.log('[4] OSS Token 请求数:', ossTokenRequests.length) console.log('[4] OSS 上传请求数:', ossUploadRequests.length) // 验证:发出了 OSS Token 请求 if (ossTokenRequests.length > 0) { console.log('[4] Token 请求 URL:', ossTokenRequests[0]) } // 验证:发出了 OSS 上传请求 if (ossUploadRequests.length > 0) { console.log('[4] 上传目标 URL:', ossUploadRequests[0]) expect(ossUploadRequests[0]).toContain('aliyuncs.com') } // 验证:检查页面上是否有上传成功的 UI 指示 const successItems = page.locator('.ant-upload-list-item-done') const errorItems = page.locator('.ant-upload-list-item-error') const successCount = await successItems.count() const errorCount = await errorItems.count() console.log('[4] 上传成功项:', successCount, '上传失败项:', errorCount) // 检查是否有错误提示消息 const errorMsg = await page.locator('.ant-message-error').textContent().catch(() => '') if (errorMsg) { console.log('[4] 错误消息:', errorMsg) } // 核心断言 expect(ossTokenRequests.length).toBeGreaterThanOrEqual(1) expect(ossUploadRequests.length).toBeGreaterThanOrEqual(1) expect(errorCount).toBe(0) console.log('\n===== OSS 直传上传测试通过 =====') console.log('OSS Token 请求:', ossTokenRequests.length) console.log('OSS 上传请求:', ossUploadRequests.length) console.log('上传目标:', ossUploadRequests[0] || 'N/A') }) })