import { test, expect } from '@playwright/test'; /** * 🖱️ 蚊子项目H5前端 - 用户操作测试 * 模拟真实用户在H5界面的查看和操作 * * 注意:H5_BASE_URL必须通过环境变量配置,默认值仅供参考 * 使用方式: H5_BASE_URL=http://localhost:5173 npx playwright test * * 注意:H5与Admin共享同一前端服务(5173),H5路由(/share等)由Admin前端提供 */ test.describe('👤 用户H5前端操作测试', () => { const FRONTEND_URL = process.env.H5_BASE_URL || 'http://localhost:5173'; const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080'; /** * 验证当前页面是否为H5应用(而非管理后台) * 通过检查页面特征来识别 */ const verifyH5Page = async (page: any, expectedPath?: string) => { const currentUrl = page.url(); // 如果指定了期望路径,验证路径 if (expectedPath && !currentUrl.includes(expectedPath)) { throw new Error(`页面路径不正确: ${currentUrl},期望包含: ${expectedPath}`); } // H5页面特征:路径是 / 或 /share 或 /rank 或 /profile const isH5Path = currentUrl === '/' || currentUrl.includes('/share') || currentUrl.includes('/rank') || currentUrl.includes('/profile'); // 如果不是H5路径,抛出错误 if (!isH5Path && !currentUrl.includes('localhost')) { throw new Error(`E2E目标偏离:当前页面 ${currentUrl} 不是H5应用,可能跑到了管理前端或其他应用`); } console.log(` ✅ H5页面验证通过: ${currentUrl}`); return true; }; test('📱 查看首页和底部导航', async ({ page }) => { await test.step('访问H5首页', async () => { // 访问首页 const response = await page.goto(FRONTEND_URL); // 验证页面可访问 expect(response).not.toBeNull(); console.log(' ✅ 首页响应状态:', response?.status()); // 等待页面加载完成 await page.waitForLoadState('networkidle'); // 验证是H5页面而非管理后台 await verifyH5Page(page, '/'); // 截图记录首页 await page.screenshot({ path: 'test-results/h5-user-homepage.png', fullPage: true }); console.log(' 📸 首页截图已保存'); }); await test.step('检查底部导航栏', async () => { // 查找导航栏 const nav = page.locator('nav'); const navExists = await nav.count() > 0; if (navExists) { console.log(' ✅ 底部导航栏已找到'); // 查找导航链接 const homeLink = page.locator('text=首页').first(); const shareLink = page.locator('text=推广').first(); const rankLink = page.locator('text=排行').first(); // 验证导航项存在 const hasHome = await homeLink.count() > 0; const hasShare = await shareLink.count() > 0; const hasRank = await rankLink.count() > 0; console.log(` 📊 导航项: 首页(${hasHome ? '✓' : '✗'}), 推广(${hasShare ? '✓' : '✗'}), 排行(${hasRank ? '✓' : '✗'})`); } else { console.log(' ⚠️ 未找到底部导航栏'); } }); }); test('🖱️ 用户点击导航菜单', async ({ page }) => { await test.step('点击推广页面', async () => { await page.goto(FRONTEND_URL); await page.waitForLoadState('networkidle'); // 验证是H5页面 await verifyH5Page(page); // 查找并点击推广链接 const shareLink = page.locator('text=推广').first(); if (await shareLink.count() > 0) { console.log(' 🖱️ 点击推广导航项'); await shareLink.click(); // 等待页面切换 await page.waitForTimeout(1000); // 截图记录推广页面 await page.screenshot({ path: 'test-results/h5-user-share-page.png', fullPage: true }); console.log(' ✅ 推广页面截图已保存'); // 验证URL变化 const currentUrl = page.url(); console.log(' 🔗 当前URL:', currentUrl); } else { console.log(' ⚠️ 未找到推广导航项'); } }); await test.step('点击排行榜页面', async () => { // 查找并点击排行链接 const rankLink = page.locator('text=排行').first(); if (await rankLink.count() > 0) { console.log(' 🖱️ 点击排行导航项'); await rankLink.click(); // 等待页面切换 await page.waitForTimeout(1000); // 截图记录排行榜页面 await page.screenshot({ path: 'test-results/h5-user-rank-page.png', fullPage: true }); console.log(' ✅ 排行榜页面截图已保存'); // 验证URL变化 const currentUrl = page.url(); console.log(' 🔗 当前URL:', currentUrl); } else { console.log(' ⚠️ 未找到排行导航项'); } }); await test.step('返回首页', async () => { // 查找并点击首页链接 const homeLink = page.locator('text=首页').first(); if (await homeLink.count() > 0) { console.log(' 🖱️ 点击首页导航项'); await homeLink.click(); // 等待页面切换 await page.waitForTimeout(1000); // 验证返回首页 const currentUrl = page.url(); console.log(' 🔗 返回首页URL:', currentUrl); } }); }); test('📱 移动端响应式布局测试', async ({ page }) => { const viewports = [ { width: 375, height: 667, name: 'iPhone-SE' }, { width: 414, height: 896, name: 'iPhone-12-Pro' }, { width: 768, height: 1024, name: 'iPad' } ]; for (const viewport of viewports) { await test.step(`${viewport.name}设备布局检查`, async () => { // 设置设备尺寸 await page.setViewportSize({ width: viewport.width, height: viewport.height }); await page.goto(FRONTEND_URL); await page.waitForLoadState('networkidle'); // 验证是H5页面 await verifyH5Page(page); // 截图记录不同设备效果 await page.screenshot({ path: `test-results/h5-responsive-${viewport.name}.png`, fullPage: true }); console.log(` 📱 ${viewport.name} (${viewport.width}x${viewport.height}) 截图完成`); // 验证底部导航在移动端可见 const nav = page.locator('nav'); const isNavVisible = await nav.isVisible().catch(() => false); console.log(` ${isNavVisible ? '✅' : '⚠️'} 底部导航栏可见性: ${isNavVisible}`); }); } }); test('🔍 页面元素检查和交互', async ({ page }) => { await test.step('检查页面元素', async () => { await page.goto(FRONTEND_URL); await page.waitForLoadState('networkidle'); // 验证是H5页面 await verifyH5Page(page); // 统计页面元素 const buttons = page.locator('button'); const links = page.locator('a'); const images = page.locator('img'); const inputs = page.locator('input'); const buttonCount = await buttons.count(); const linkCount = await links.count(); const imageCount = await images.count(); const inputCount = await inputs.count(); console.log(' 📊 页面元素统计:'); console.log(` - 按钮: ${buttonCount} 个`); console.log(` - 链接: ${linkCount} 个`); console.log(` - 图片: ${imageCount} 个`); console.log(` - 输入框: ${inputCount} 个`); // 如果存在按钮,测试点击第一个 if (buttonCount > 0) { const firstButton = buttons.first(); const buttonText = await firstButton.textContent(); console.log(` 🖱️ 第一个按钮: "${buttonText}"`); } // 获取页面完整文本内容预览 const pageText = await page.textContent('body'); if (pageText) { const preview = pageText.replace(/\s+/g, ' ').substring(0, 200); console.log(` 📝 页面内容: ${preview}...`); } }); }); test('⏱️ 页面性能测试', async ({ page }) => { await test.step('测量页面加载性能', async () => { const startTime = Date.now(); await page.goto(FRONTEND_URL); await page.waitForLoadState('networkidle'); // 验证是H5页面 await verifyH5Page(page); const loadTime = Date.now() - startTime; console.log(` ⏱️ 页面加载时间: ${loadTime}ms`); // 验证加载时间 expect(loadTime).toBeLessThan(10000); // 10秒内加载完成 // 获取性能指标 const performanceMetrics = await page.evaluate(() => { const timing = performance.timing; return { domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart, loadComplete: timing.loadEventEnd - timing.navigationStart, }; }); console.log(' 📊 性能指标:'); console.log(` - DOM内容加载: ${performanceMetrics.domContentLoaded}ms`); console.log(` - 页面完全加载: ${performanceMetrics.loadComplete}ms`); }); }); test('🔗 前后端连通性测试', async ({ request }) => { await test.step('验证后端API可用', async () => { const response = await request.get(`${API_BASE_URL}/actuator/health`); expect(response.status()).toBe(200); const body = await response.json(); expect(body.status).toBe('UP'); console.log(' ✅ 后端API连通性正常'); console.log(' 📊 后端状态:', JSON.stringify(body, null, 2)); }); }); });