feat: 创建Core Web Vitals性能测试

- 添加首页性能测试(加载时间、DOM内容、FCP、LCP、TTI、FID、CLS)
- 添加联系页面性能测试(加载时间、表单提交性能)
- 添加网络时序测试(DNS、TCP、SSL、请求、响应时间)
- 添加资源加载测试(关键资源、加载时间、失败资源)
- 添加滚动性能测试(平滑滚动、快速滚动)
- 添加交互性能测试(导航点击、联系按钮点击)
- 添加性能预算测试(总页面大小、图片、脚本、样式表)
This commit is contained in:
张翔
2026-02-28 16:03:46 +08:00
parent a7fa9af853
commit 5131ba8880
@@ -0,0 +1,288 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../../pages/HomePage';
import { ContactPage } from '../../pages/ContactPage';
import { PERFORMANCE_THRESHOLDS } from '../../data/test-data';
test.describe('Core Web Vitals性能测试', () => {
test.describe('首页性能测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该满足页面加载时间阈值', async () => {
await homePage.goto();
const performance = await homePage.measurePageLoadPerformance();
expect(performance.loadTime).toBeLessThan(PERFORMANCE_THRESHOLDS.loadTime);
});
test('应该满足DOM内容加载时间阈值', async () => {
await homePage.goto();
const performance = await homePage.measurePageLoadPerformance();
expect(performance.domContentLoaded).toBeLessThan(PERFORMANCE_THRESHOLDS.firstContentfulPaint);
});
test('应该满足首次内容绘制阈值', async () => {
await homePage.goto();
const performance = await homePage.measurePageLoadPerformance();
expect(performance.firstContentfulPaint).toBeLessThan(PERFORMANCE_THRESHOLDS.firstContentfulPaint);
});
test('应该满足最大内容绘制阈值', async () => {
await homePage.goto();
const vitals = await homePage.getCoreWebVitals();
expect(vitals.largestContentfulPaint).toBeLessThan(PERFORMANCE_THRESHOLDS.largestContentfulPaint);
});
test('应该满足可交互时间阈值', async () => {
await homePage.goto();
const vitals = await homePage.getCoreWebVitals();
expect(vitals.largestContentfulPaint).toBeLessThan(PERFORMANCE_THRESHOLDS.timeToInteractive);
});
test('应该满足首次输入延迟阈值', async () => {
await homePage.goto();
const vitals = await homePage.getCoreWebVitals();
expect(vitals.firstInputDelay).toBeLessThan(PERFORMANCE_THRESHOLDS.firstInputDelay);
});
test('应该满足累积布局偏移阈值', async () => {
await homePage.goto();
const vitals = await homePage.getCoreWebVitals();
expect(vitals.cumulativeLayoutShift).toBeLessThan(PERFORMANCE_THRESHOLDS.cumulativeLayoutShift);
});
});
test.describe('联系页面性能测试', () => {
let contactPage: ContactPage;
test.beforeEach(async ({ page }) => {
contactPage = new ContactPage(page);
});
test('应该满足页面加载时间阈值', async () => {
await contactPage.goto();
const performance = await contactPage.measurePerformance();
expect(performance.loadTime).toBeLessThan(PERFORMANCE_THRESHOLDS.loadTime);
});
test('应该满足表单提交性能阈值', async () => {
await contactPage.goto();
const performance = await contactPage.measureFormSubmissionPerformance();
expect(performance.fillTime).toBeLessThan(1000);
expect(performance.submitTime).toBeLessThan(2000);
expect(performance.totalTime).toBeLessThan(3000);
});
});
test.describe('网络时序测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该满足DNS查询时间阈值', async () => {
await homePage.goto();
const timing = await homePage.getNetworkTiming();
expect(timing.dns).toBeLessThan(500);
});
test('应该满足TCP连接时间阈值', async () => {
await homePage.goto();
const timing = await homePage.getNetworkTiming();
expect(timing.tcp).toBeLessThan(500);
});
test('应该满足SSL握手时间阈值', async () => {
await homePage.goto();
const timing = await homePage.getNetworkTiming();
expect(timing.ssl).toBeLessThan(500);
});
test('应该满足请求时间阈值', async () => {
await homePage.goto();
const timing = await homePage.getNetworkTiming();
expect(timing.request).toBeLessThan(1000);
});
test('应该满足响应时间阈值', async () => {
await homePage.goto();
const timing = await homePage.getNetworkTiming();
expect(timing.response).toBeLessThan(1000);
});
});
test.describe('资源加载测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该加载所有关键资源', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const images = resources.filter(r => r.initiatorType === 'img');
const scripts = resources.filter(r => r.initiatorType === 'script');
const stylesheets = resources.filter(r => r.initiatorType === 'link');
expect(images.length).toBeGreaterThan(0);
expect(scripts.length).toBeGreaterThan(0);
expect(stylesheets.length).toBeGreaterThan(0);
});
test('应该满足资源加载时间阈值', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
resources.forEach(resource => {
const loadTime = resource.responseEnd - resource.fetchStart;
expect(loadTime).toBeLessThan(5000);
});
});
test('应该没有加载失败的资源', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const failedResources = resources.filter(r => r.transferSize === 0);
expect(failedResources.length).toBe(0);
});
});
test.describe('滚动性能测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该能够平滑滚动到各个区域', async () => {
await homePage.goto();
const scrollTimes: number[] = [];
const sections = ['services', 'products', 'cases', 'news', 'contact'];
for (const section of sections) {
const startTime = Date.now();
await homePage.scrollToSection(section);
const scrollTime = Date.now() - startTime;
scrollTimes.push(scrollTime);
}
const avgScrollTime = scrollTimes.reduce((a, b) => a + b, 0) / scrollTimes.length;
expect(avgScrollTime).toBeLessThan(500);
});
test('应该能够快速滚动到页面底部', async () => {
await homePage.goto();
const startTime = Date.now();
await homePage.scrollToBottom();
const scrollTime = Date.now() - startTime;
expect(scrollTime).toBeLessThan(1000);
});
test('应该能够快速滚动到页面顶部', async () => {
await homePage.goto();
await homePage.scrollToBottom();
const startTime = Date.now();
await homePage.scrollToTop();
const scrollTime = Date.now() - startTime;
expect(scrollTime).toBeLessThan(1000);
});
});
test.describe('交互性能测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该能够快速点击导航链接', async () => {
await homePage.goto();
const startTime = Date.now();
await homePage.clickNavigationItem('服务');
await homePage.waitForTimeout(500);
const clickTime = Date.now() - startTime;
expect(clickTime).toBeLessThan(500);
});
test('应该能够快速点击联系按钮', async () => {
await homePage.goto();
const startTime = Date.now();
await homePage.clickContactButton();
await homePage.waitForLoadState('networkidle');
const clickTime = Date.now() - startTime;
expect(clickTime).toBeLessThan(1000);
});
});
test.describe('性能预算测试', () => {
let homePage: HomePage;
test.beforeEach(async ({ page }) => {
homePage = new HomePage(page);
});
test('应该满足总页面大小预算', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const totalSize = resources.reduce((sum, r) => sum + r.transferSize, 0);
expect(totalSize).toBeLessThan(1600000);
});
test('应该满足图片大小预算', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const images = resources.filter(r => r.initiatorType === 'img');
const imageSize = images.reduce((sum, r) => sum + r.transferSize, 0);
expect(imageSize).toBeLessThan(500000);
});
test('应该满足脚本大小预算', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const scripts = resources.filter(r => r.initiatorType === 'script');
const scriptSize = scripts.reduce((sum, r) => sum + r.transferSize, 0);
expect(scriptSize).toBeLessThan(300000);
});
test('应该满足样式表大小预算', async () => {
await homePage.goto();
const resources = await homePage.getResourceTiming();
const stylesheets = resources.filter(r => r.initiatorType === 'link');
const stylesheetSize = stylesheets.reduce((sum, r) => sum + r.transferSize, 0);
expect(stylesheetSize).toBeLessThan(100000);
});
});
});