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

293 lines
9.8 KiB
TypeScript
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.
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));
});
});
});