Files
wenzi/frontend/e2e/tests/h5-user-operations.spec.ts

293 lines
9.8 KiB
TypeScript
Raw Permalink Normal View History

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:5176';
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));
});
});
});