feat: 创建Core Web Vitals性能测试
- 添加首页性能测试(加载时间、DOM内容、FCP、LCP、TTI、FID、CLS) - 添加联系页面性能测试(加载时间、表单提交性能) - 添加网络时序测试(DNS、TCP、SSL、请求、响应时间) - 添加资源加载测试(关键资源、加载时间、失败资源) - 添加滚动性能测试(平滑滚动、快速滚动) - 添加交互性能测试(导航点击、联系按钮点击) - 添加性能预算测试(总页面大小、图片、脚本、样式表)
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user