feat(e2e): 添加完整的E2E测试框架和测试用例

添加Playwright测试框架配置和基础页面对象
实现冒烟测试用例覆盖首页和联系页面核心功能
更新导航组件以支持滚动高亮功能
添加BackButton组件统一返回按钮行为
配置Woodpecker CI集成和测试报告生成
This commit is contained in:
张翔
2026-02-27 10:30:33 +08:00
parent 4a616fe96e
commit 5d5b7feb0a
50 changed files with 6765 additions and 46 deletions
@@ -0,0 +1,56 @@
import { test, expect } from '@playwright/test';
test('检查联系页面所有元素', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const badges = await page.locator('[class*="badge"]').all();
console.log('找到的badge数量:', badges.length);
for (let i = 0; i < badges.length; i++) {
const badge = badges[i];
const className = await badge.evaluate(el => el.className);
const text = await badge.textContent();
console.log(`Badge ${i}: ${className} - ${text}`);
}
const contactCard = page.locator('[class*="card"]').filter({ hasText: '联系方式' }).first();
const contactCardText = await contactCard.textContent();
console.log('联系卡片文本:', contactCardText?.substring(0, 100));
const workHoursCard = page.locator('[class*="card"]').filter({ hasText: '工作时间' }).first();
const workHoursCardText = await workHoursCard.textContent();
console.log('工作时间卡片文本:', workHoursCardText?.substring(0, 100));
const addressH3 = contactCard.locator('h3:has-text("公司地址")');
const addressParent = addressH3.locator('..');
const addressGrandParent = addressParent.locator('..');
const addressP = addressGrandParent.locator('p');
const addressText = await addressP.textContent();
console.log('地址文本:', addressText);
const phoneH3 = contactCard.locator('h3:has-text("联系电话")');
const phoneParent = phoneH3.locator('..');
const phoneGrandParent = phoneParent.locator('..');
const phoneP = phoneGrandParent.locator('p');
const phoneText = await phoneP.textContent();
console.log('电话文本:', phoneText);
const emailH3 = contactCard.locator('h3:has-text("电子邮箱")');
const emailParent = emailH3.locator('..');
const emailGrandParent = emailParent.locator('..');
const emailP = emailGrandParent.locator('p');
const emailText = await emailP.textContent();
console.log('邮箱文本:', emailText);
const workHoursRows = workHoursCard.locator('.space-y-2 > div');
const workHoursCount = await workHoursRows.count();
console.log('工作时间行数:', workHoursCount);
for (let i = 0; i < workHoursCount; i++) {
const row = workHoursRows.nth(i);
const day = await row.locator('span').first().textContent();
const hours = await row.locator('span').nth(1).textContent();
console.log(`工作时间 ${i}: ${day} - ${hours}`);
}
});
@@ -0,0 +1,21 @@
import { test, expect } from '@playwright/test';
test('检查联系卡片详细结构', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const contactCard = page.locator('[data-slot="card"]').filter({ hasText: '联系方式' }).first();
const contactCardChildren = await contactCard.locator('div').all();
console.log('联系卡片子元素数量:', contactCardChildren.length);
for (let i = 0; i < contactCardChildren.length; i++) {
const child = contactCardChildren[i];
const className = await child.evaluate(el => el.className);
const text = await child.textContent();
console.log(`子元素 ${i}: ${className.substring(0, 80)} - ${text?.substring(0, 50)}`);
}
const allDivs = await contactCard.locator('div').all();
console.log('所有div数量:', allDivs.length);
});
@@ -0,0 +1,25 @@
import { test, expect } from '@playwright/test';
test('检查联系页面Card标题', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const cardTitles = await page.locator('CardTitle').all();
console.log('找到的CardTitle数量:', cardTitles.length);
for (let i = 0; i < cardTitles.length; i++) {
const title = cardTitles[i];
const text = await title.textContent();
console.log(`CardTitle ${i}: ${text}`);
}
const allCards = await page.locator('[class*="card"]').all();
console.log('找到的所有card元素数量:', allCards.length);
for (let i = 0; i < allCards.length; i++) {
const card = allCards[i];
const className = await card.evaluate(el => el.className);
const text = await card.textContent();
console.log(`Card ${i}: ${className.substring(0, 50)} - ${text?.substring(0, 50)}`);
}
});
+23
View File
@@ -0,0 +1,23 @@
import { test, expect } from '@playwright/test';
test('检查联系卡片详细信息', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const contactCard = page.locator('.card').filter({ hasText: '联系方式' });
const contactText = await contactCard.textContent();
console.log('联系方式卡片内容:', contactText);
const workHoursCard = page.locator('.card').filter({ hasText: '工作时间' });
const workHoursText = await workHoursCard.textContent();
console.log('工作时间卡片内容:', workHoursText);
const allCards = await page.locator('.card').all();
console.log('所有卡片数量:', allCards.length);
for (let i = 0; i < allCards.length; i++) {
const card = allCards[i];
const text = await card.textContent();
console.log(`卡片 ${i}:`, text?.substring(0, 100));
}
});
@@ -0,0 +1,41 @@
import { test, expect } from '@playwright/test';
test('检查联系页面详细元素', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const pageHeader = page.locator('h1:has-text("与我们取得联系")');
const pageHeaderParent = pageHeader.locator('..');
const pageHeaderGrandParent = pageHeaderParent.locator('..');
console.log('Page Header parent:', await pageHeaderParent.evaluate(el => el.className));
console.log('Page Header grand parent:', await pageHeaderGrandParent.evaluate(el => el.className));
const badges = await pageHeaderGrandParent.locator('.badge').all();
console.log('找到的badge数量:', badges.length);
for (let i = 0; i < badges.length; i++) {
const badge = badges[i];
const text = await badge.textContent();
console.log(`Badge ${i}: ${text}`);
}
const contactCard = page.locator('h3:has-text("联系方式")');
const contactCardParent = contactCard.locator('..');
const contactCardGrandParent = contactCardParent.locator('..');
const contactCardGreatGrandParent = contactCardGrandParent.locator('..');
console.log('Contact card great grand parent:', await contactCardGreatGrandParent.evaluate(el => el.className));
const addressElement = contactCard.locator('text=公司地址').locator('..').locator('p');
const addressText = await addressElement.textContent();
console.log('地址:', addressText);
const phoneElement = contactCard.locator('text=联系电话').locator('..').locator('p');
const phoneText = await phoneElement.textContent();
console.log('电话:', phoneText);
const emailElement = contactCard.locator('text=电子邮箱').locator('..').locator('p');
const emailText = await emailElement.textContent();
console.log('邮箱:', emailText);
});
+21
View File
@@ -0,0 +1,21 @@
import { test, expect } from '@playwright/test';
test('检查联系页面完整DOM', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const contactCard = page.locator('[class*="card"]').filter({ hasText: '联系方式' }).first();
const contactCardHTML = await contactCard.innerHTML();
console.log('联系卡片HTML:', contactCardHTML.substring(0, 500));
const contactCardChildren = await contactCard.locator('div').all();
console.log('联系卡片子元素数量:', contactCardChildren.length);
for (let i = 0; i < contactCardChildren.length; i++) {
const child = contactCardChildren[i];
const className = await child.evaluate(el => el.className);
const text = await child.textContent();
console.log(`子元素 ${i}: ${className.substring(0, 50)} - ${text?.substring(0, 50)}`);
}
});
@@ -0,0 +1,30 @@
import { test, expect } from '@playwright/test';
test('检查联系页面完整结构', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const allH3 = await page.locator('h3').all();
console.log('找到的h3元素数量:', allH3.length);
for (let i = 0; i < allH3.length; i++) {
const h3 = allH3[i];
const text = await h3.textContent();
console.log(`H3 ${i}: ${text}`);
const parent = h3.locator('..');
const grandParent = parent.locator('..');
const greatGrandParent = grandParent.locator('..');
try {
const parentClass = await parent.evaluate(el => el.className);
const grandParentClass = await grandParent.evaluate(el => el.className);
const greatGrandParentClass = await greatGrandParent.evaluate(el => el.className);
console.log(` Parent: ${parentClass}`);
console.log(` Grand Parent: ${grandParentClass}`);
console.log(` Great Grand Parent: ${greatGrandParentClass}`);
} catch (e) {
console.log(` Error getting parent info: ${e}`);
}
}
});
+34
View File
@@ -0,0 +1,34 @@
import { test, expect } from '@playwright/test';
test('检查联系页面元素', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const pageHeaders = await page.locator('.page-header').all();
console.log('找到的page-header数量:', pageHeaders.length);
const forms = await page.locator('form').all();
console.log('找到的form数量:', forms.length);
const cards = await page.locator('.card').all();
console.log('找到的card数量:', cards.length);
for (let i = 0; i < cards.length; i++) {
const card = cards[i];
const text = await card.textContent();
console.log(`Card ${i}: ${text?.substring(0, 50)}`);
}
const inputs = await page.locator('input').all();
console.log('找到的input数量:', inputs.length);
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
const name = await input.getAttribute('name');
const type = await input.getAttribute('type');
console.log(`Input ${i}: name="${name}", type="${type}"`);
}
const textareas = await page.locator('textarea').all();
console.log('找到的textarea数量:', textareas.length);
});
@@ -0,0 +1,28 @@
import { test, expect } from '@playwright/test';
test('检查联系页面结构', async ({ page }) => {
await page.goto('/contact');
await page.waitForLoadState('networkidle');
const allElements = await page.evaluate(() => {
const result: any = {};
const h1s = document.querySelectorAll('h1');
result.h1Count = h1s.length;
result.h1Text = Array.from(h1s).map(h => h.textContent?.substring(0, 50));
const cards = document.querySelectorAll('[class*="card"]');
result.cardCount = cards.length;
result.cardText = Array.from(cards).map(c => c.textContent?.substring(0, 50));
const pageHeaders = document.querySelectorAll('[class*="page-header"]');
result.pageHeaderCount = pageHeaders.length;
const contactInfoCards = document.querySelectorAll('[class*="contact"]');
result.contactInfoCount = contactInfoCards.length;
return result;
});
console.log('联系页面结构:', JSON.stringify(allElements, null, 2));
});
+37
View File
@@ -0,0 +1,37 @@
import { test, expect } from '@playwright/test';
test('测试页面加载', async ({ page }) => {
await page.goto('/');
await page.waitForLoadState('networkidle');
const title = await page.title();
console.log('页面标题:', title);
const body = await page.locator('body').textContent();
console.log('页面内容长度:', body?.length);
const headers = await page.locator('header').all();
console.log('找到的header元素数量:', headers.length);
const navs = await page.locator('nav').all();
console.log('找到的nav元素数量:', navs.length);
const sections = await page.locator('section').all();
console.log('找到的section元素数量:', sections.length);
const allElements = await page.evaluate(() => {
const headers = document.querySelectorAll('header');
const navs = document.querySelectorAll('nav');
const sections = document.querySelectorAll('section');
return {
headers: headers.length,
navs: navs.length,
sections: sections.length,
bodyText: document.body.textContent?.substring(0, 200)
};
});
console.log('页面元素信息:', allElements);
expect(title).toBeTruthy();
});
+36
View File
@@ -0,0 +1,36 @@
import { test, expect } from '@playwright/test';
test('检查页面元素选择器', async ({ page }) => {
await page.goto('/');
await page.waitForLoadState('networkidle');
const logoImages = await page.locator('header img').all();
console.log('找到的logo图片数量:', logoImages.length);
for (let i = 0; i < logoImages.length; i++) {
const img = logoImages[i];
const alt = await img.getAttribute('alt');
const src = await img.getAttribute('src');
console.log(`Logo ${i}: alt="${alt}", src="${src}"`);
}
const contactButtons = await page.locator('a:has-text("立即咨询")').all();
console.log('找到的立即咨询按钮数量:', contactButtons.length);
for (let i = 0; i < contactButtons.length; i++) {
const btn = contactButtons[i];
const href = await btn.getAttribute('href');
const text = await btn.textContent();
console.log(`立即咨询按钮 ${i}: text="${text}", href="${href}"`);
}
const mobileMenuButtons = await page.locator('button').all();
console.log('找到的按钮数量:', mobileMenuButtons.length);
for (let i = 0; i < mobileMenuButtons.length; i++) {
const btn = mobileMenuButtons[i];
const ariaLabel = await btn.getAttribute('aria-label');
const text = await btn.textContent();
console.log(`按钮 ${i}: aria-label="${ariaLabel}", text="${text}"`);
}
});
@@ -0,0 +1,376 @@
import { test, expect } from '../../fixtures/base.fixture';
import { PerformanceMonitor } from '../../utils/PerformanceMonitor';
test.describe('交互性能测试 @performance', () => {
test('点击导航项应该快速响应', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 0) {
await homePage.clickNavigationItem(labels[0]);
}
await homePage.page.waitForTimeout(100);
const endTime = Date.now();
const clickDuration = endTime - startTime;
console.log('导航项点击响应时间:', clickDuration, 'ms');
expect(clickDuration).toBeLessThan(500);
});
test('滚动应该流畅', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
for (let i = 0; i < 20; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 100));
await homePage.page.waitForTimeout(30);
}
const endTime = Date.now();
const scrollDuration = endTime - startTime;
console.log('滚动持续时间:', scrollDuration, 'ms');
expect(scrollDuration).toBeLessThan(1500);
});
test('表单输入应该快速响应', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await contactPage.nameInput.fill('测试用户');
await contactPage.emailInput.fill('test@example.com');
await contactPage.subjectInput.fill('测试主题');
await contactPage.messageInput.fill('这是一条测试消息');
const endTime = Date.now();
const inputDuration = endTime - startTime;
console.log('表单输入持续时间:', inputDuration, 'ms');
expect(inputDuration).toBeLessThan(1000);
});
test('按钮点击应该快速响应', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.clickContactButton();
await homePage.page.waitForTimeout(100);
const endTime = Date.now();
const clickDuration = endTime - startTime;
console.log('按钮点击响应时间:', clickDuration, 'ms');
expect(clickDuration).toBeLessThan(500);
});
test('移动端菜单打开应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.openMobileMenu();
const endTime = Date.now();
const menuOpenDuration = endTime - startTime;
console.log('移动端菜单打开时间:', menuOpenDuration, 'ms');
expect(menuOpenDuration).toBeLessThan(500);
});
test('移动端菜单关闭应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.closeMobileMenu();
const endTime = Date.now();
const menuCloseDuration = endTime - startTime;
console.log('移动端菜单关闭时间:', menuCloseDuration, 'ms');
expect(menuCloseDuration).toBeLessThan(500);
});
test('页面跳转应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.clickContactButton();
await homePage.page.waitForLoadState('networkidle');
const endTime = Date.now();
const navigationDuration = endTime - startTime;
console.log('页面跳转持续时间:', navigationDuration, 'ms');
expect(navigationDuration).toBeLessThan(2000);
});
test('表单提交应该快速', async ({ contactPage, page, testDataGenerator }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await contactPage.fillContactForm(formData);
await contactPage.submitForm();
await contactPage.waitForFormSubmission();
const endTime = Date.now();
const submissionDuration = endTime - startTime;
console.log('表单提交持续时间:', submissionDuration, 'ms');
expect(submissionDuration).toBeLessThan(3000);
});
test('悬停效果应该流畅', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 0) {
const firstNavItem = homePage.navigation.locator('a').first();
await firstNavItem.hover();
await homePage.page.waitForTimeout(100);
}
const endTime = Date.now();
const hoverDuration = endTime - startTime;
console.log('悬停效果持续时间:', hoverDuration, 'ms');
expect(hoverDuration).toBeLessThan(300);
});
test('快速连续点击应该正常响应', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
const labels = await homePage.getAllNavigationLabels();
for (let i = 0; i < Math.min(labels.length, 3); i++) {
await homePage.clickNavigationItem(labels[i]);
await homePage.page.waitForTimeout(200);
}
const endTime = Date.now();
const rapidClickDuration = endTime - startTime;
console.log('快速连续点击持续时间:', rapidClickDuration, 'ms');
expect(rapidClickDuration).toBeLessThan(2000);
});
test('快速滚动应该流畅', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
for (let i = 0; i < 10; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 500));
await homePage.page.waitForTimeout(50);
}
const endTime = Date.now();
const rapidScrollDuration = endTime - startTime;
console.log('快速滚动持续时间:', rapidScrollDuration, 'ms');
expect(rapidScrollDuration).toBeLessThan(1500);
});
test('表单验证应该快速', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await contactPage.emailInput.fill('invalid-email');
await contactPage.page.waitForTimeout(100);
const isValid = await contactPage.isEmailValid();
const endTime = Date.now();
const validationDuration = endTime - startTime;
console.log('表单验证持续时间:', validationDuration, 'ms');
expect(validationDuration).toBeLessThan(300);
expect(isValid).toBe(false);
});
test('键盘导航应该流畅', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
for (let i = 0; i < 10; i++) {
await homePage.page.keyboard.press('Tab');
await homePage.page.waitForTimeout(50);
}
const endTime = Date.now();
const keyboardNavDuration = endTime - startTime;
console.log('键盘导航持续时间:', keyboardNavDuration, 'ms');
expect(keyboardNavDuration).toBeLessThan(1000);
});
test('页面重新加载应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.reload();
await homePage.waitForPageLoad();
const endTime = Date.now();
const reloadDuration = endTime - startTime;
console.log('页面重新加载持续时间:', reloadDuration, 'ms');
expect(reloadDuration).toBeLessThan(2000);
});
test('返回上一页应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.clickContactButton();
await homePage.page.waitForLoadState('networkidle');
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.goBack();
await homePage.page.waitForLoadState('networkidle');
const endTime = Date.now();
const backDuration = endTime - startTime;
console.log('返回上一页持续时间:', backDuration, 'ms');
expect(backDuration).toBeLessThan(1500);
});
test('前进到下一页应该快速', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.clickContactButton();
await homePage.page.waitForLoadState('networkidle');
await homePage.goBack();
await homePage.page.waitForLoadState('networkidle');
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.goForward();
await homePage.page.waitForLoadState('networkidle');
const endTime = Date.now();
const forwardDuration = endTime - startTime;
console.log('前进到下一页持续时间:', forwardDuration, 'ms');
expect(forwardDuration).toBeLessThan(1500);
});
test('窗口大小调整应该流畅', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const startTime = Date.now();
await homePage.page.setViewportSize({ width: 768, height: 1024 });
await homePage.page.waitForTimeout(100);
await homePage.page.setViewportSize({ width: 1280, height: 720 });
await homePage.page.waitForTimeout(100);
const endTime = Date.now();
const resizeDuration = endTime - startTime;
console.log('窗口大小调整持续时间:', resizeDuration, 'ms');
expect(resizeDuration).toBeLessThan(500);
});
test('所有交互应该在合理时间内完成', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
const interactions: { name: string; duration: number }[] = [];
const startClick = Date.now();
await homePage.clickContactButton();
await homePage.page.waitForLoadState('networkidle');
interactions.push({ name: '点击按钮', duration: Date.now() - startClick });
await homePage.goBack();
const startScroll = Date.now();
await homePage.scrollToSection('services');
interactions.push({ name: '滚动到区块', duration: Date.now() - startScroll });
const startNav = Date.now();
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 0) {
await homePage.clickNavigationItem(labels[0]);
}
interactions.push({ name: '导航点击', duration: Date.now() - startNav });
console.log('交互性能汇总:');
interactions.forEach(interaction => {
console.log(`- ${interaction.name}: ${interaction.duration}ms`);
});
interactions.forEach(interaction => {
expect(interaction.duration).toBeLessThan(2000);
});
});
});
@@ -0,0 +1,271 @@
import { test, expect } from '../../fixtures/base.fixture';
import { PerformanceMonitor } from '../../utils/PerformanceMonitor';
import { PerformanceThresholds } from '../../types';
const performanceThresholds: PerformanceThresholds = {
loadTime: 3000,
firstContentfulPaint: 1800,
largestContentfulPaint: 2500,
timeToInteractive: 3500,
cumulativeLayoutShift: 0.1,
firstInputDelay: 100,
};
test.describe('性能测试 @performance', () => {
test('首页加载时间应该在阈值范围内', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const metrics = await monitor.collectMetrics();
const validation = monitor.validateMetrics(performanceThresholds);
console.log('首页性能指标:', metrics);
console.log('验证结果:', validation);
expect(validation.passed).toBe(true);
expect(metrics.loadTime).toBeLessThan(performanceThresholds.loadTime);
});
test('联系页面加载时间应该在阈值范围内', async ({ contactPage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await contactPage.goto();
await contactPage.waitForPageLoad();
const metrics = await monitor.collectMetrics();
const validation = monitor.validateMetrics(performanceThresholds);
console.log('联系页面性能指标:', metrics);
console.log('验证结果:', validation);
expect(validation.passed).toBe(true);
expect(metrics.loadTime).toBeLessThan(performanceThresholds.loadTime);
});
test('首次内容绘制应该在1.8秒内完成', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const fcp = await monitor.measureFirstContentfulPaint();
console.log('首次内容绘制时间:', fcp, 'ms');
expect(fcp).toBeLessThan(performanceThresholds.firstContentfulPaint);
expect(fcp).toBeGreaterThan(0);
});
test('最大内容绘制应该在2.5秒内完成', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const lcp = await monitor.measureLargestContentfulPaint();
console.log('最大内容绘制时间:', lcp, 'ms');
expect(lcp).toBeLessThan(performanceThresholds.largestContentfulPaint);
expect(lcp).toBeGreaterThan(0);
});
test('累积布局偏移应该小于0.1', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.scrollToSection('products');
await homePage.scrollToSection('cases');
const cls = await monitor.measureCumulativeLayoutShift();
console.log('累积布局偏移:', cls);
expect(cls).toBeLessThan(performanceThresholds.cumulativeLayoutShift);
expect(cls).toBeGreaterThanOrEqual(0);
});
test('首次输入延迟应该小于100ms', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.logo.click();
const fid = await monitor.measureFirstInputDelay();
console.log('首次输入延迟:', fid, 'ms');
expect(fid).toBeLessThan(performanceThresholds.firstInputDelay);
expect(fid).toBeGreaterThanOrEqual(0);
});
test('可交互时间应该在3.5秒内完成', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const tti = await monitor.measureTimeToInteractive();
console.log('可交互时间:', tti, 'ms');
expect(tti).toBeLessThan(performanceThresholds.timeToInteractive);
expect(tti).toBeGreaterThan(0);
});
test('页面应该有良好的帧率', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const monitor = new PerformanceMonitor(page);
const frameRate = await monitor.measureFrameRate();
console.log('帧率:', frameRate, 'FPS');
expect(frameRate).toBeGreaterThan(30);
});
test('资源加载应该高效', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const resources = await monitor.measureResourceTiming();
const totalSize = resources.reduce((sum, r) => sum + (r.size || 0), 0);
const totalSizeKB = totalSize / 1024;
console.log('总资源大小:', totalSizeKB.toFixed(2), 'KB');
console.log('资源数量:', resources.length);
expect(totalSizeKB).toBeLessThan(3000);
expect(resources.length).toBeGreaterThan(0);
});
test('DOM内容加载应该快速', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
const dcl = await monitor.measureDomContentLoaded();
console.log('DOM内容加载时间:', dcl, 'ms');
expect(dcl).toBeLessThan(2000);
expect(dcl).toBeGreaterThan(0);
});
test('应该生成性能报告', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const report = await monitor.generateReport();
console.log('性能报告:');
console.log(report);
expect(report).toContain('页面加载时间');
expect(report).toContain('首次内容绘制');
expect(report).toContain('最大内容绘制');
expect(report).toContain('累积布局偏移');
expect(report).toContain('资源加载');
});
test('滚动性能应该良好', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const startTime = Date.now();
for (let i = 0; i < 10; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 200));
await homePage.page.waitForTimeout(50);
}
const endTime = Date.now();
const scrollDuration = endTime - startTime;
console.log('滚动持续时间:', scrollDuration, 'ms');
expect(scrollDuration).toBeLessThan(2000);
});
test('导航性能应该良好', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const startTime = Date.now();
await homePage.clickContactButton();
await homePage.page.waitForLoadState('networkidle');
const endTime = Date.now();
const navigationDuration = endTime - startTime;
console.log('导航持续时间:', navigationDuration, 'ms');
expect(navigationDuration).toBeLessThan(2000);
});
test('表单提交性能应该良好', async ({ contactPage, page, testDataGenerator }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
const startTime = Date.now();
await contactPage.fillContactForm(formData);
await contactPage.submitForm();
await contactPage.waitForFormSubmission();
const endTime = Date.now();
const submissionDuration = endTime - startTime;
console.log('表单提交持续时间:', submissionDuration, 'ms');
expect(submissionDuration).toBeLessThan(3000);
});
test('所有核心性能指标应该符合标准', async ({ homePage, page }) => {
const monitor = new PerformanceMonitor(page);
await monitor.startMonitoring();
await homePage.goto();
await homePage.waitForPageLoad();
const metrics = await monitor.collectMetrics();
const validation = monitor.validateMetrics(performanceThresholds);
console.log('完整性能指标:', metrics);
console.log('验证结果:', validation);
if (!validation.passed) {
console.error('性能违规:', validation.violations);
}
expect(metrics.loadTime).toBeLessThan(performanceThresholds.loadTime);
expect(metrics.firstContentfulPaint).toBeLessThan(performanceThresholds.firstContentfulPaint);
expect(metrics.largestContentfulPaint).toBeLessThan(performanceThresholds.largestContentfulPaint);
expect(metrics.timeToInteractive).toBeLessThan(performanceThresholds.timeToInteractive);
expect(metrics.cumulativeLayoutShift).toBeLessThan(performanceThresholds.cumulativeLayoutShift);
expect(metrics.firstInputDelay).toBeLessThan(performanceThresholds.firstInputDelay);
});
});
@@ -0,0 +1,239 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('联系表单回归测试 @regression', () => {
test.beforeEach(async ({ contactPage }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
});
test('应该能够提交完整的表单', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
const isSubmitted = await contactPage.isFormSubmitted();
expect(isSubmitted).toBe(true);
});
test('应该验证必填字段', async ({ contactPage }) => {
await contactPage.submitForm();
await contactPage.waitForFormSubmission();
const isSubmitted = await contactPage.isFormSubmitted();
expect(isSubmitted).toBe(false);
});
test('应该验证邮箱格式', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.email = testDataGenerator.generateInvalidEmail();
await contactPage.fillContactForm(formData);
const isValid = await contactPage.isEmailValid();
expect(isValid).toBe(false);
});
test('应该能够清空表单', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
await contactPage.clearForm();
const nameValue = await contactPage.getNameInputValue();
const emailValue = await contactPage.getEmailInputValue();
const subjectValue = await contactPage.getSubjectInputValue();
const messageValue = await contactPage.getMessageInputValue();
expect(nameValue).toBe('');
expect(emailValue).toBe('');
expect(subjectValue).toBe('');
expect(messageValue).toBe('');
});
test('应该能够输入长消息', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = testDataGenerator.generateMessage(200, 500);
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(formData.message);
});
test('应该能够输入特殊字符', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = testDataGenerator.generateSpecialCharacters();
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(formData.message);
});
test('应该能够输入中文字符', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = testDataGenerator.generateChineseCharacters();
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(formData.message);
});
test('应该能够输入混合内容', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = testDataGenerator.generateMixedContent();
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(formData.message);
});
test('应该能够聚焦和失焦字段', async ({ contactPage }) => {
await contactPage.focusOnField('name');
const isNameFocused = await contactPage.nameInput.evaluate(el => document.activeElement === el);
expect(isNameFocused).toBe(true);
await contactPage.blurField('name');
const isNameBlurred = await contactPage.nameInput.evaluate(el => document.activeElement !== el);
expect(isNameBlurred).toBe(true);
});
test('应该能够使用键盘导航表单', async ({ contactPage }) => {
await contactPage.nameInput.focus();
await contactPage.page.keyboard.press('Tab');
await contactPage.page.waitForTimeout(100);
const focusedElement = await contactPage.page.evaluate(() => document.activeElement?.tagName);
expect(focusedElement).toBe('INPUT');
});
test('应该能够使用回车键提交表单', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
await contactPage.messageInput.press('Enter');
await contactPage.waitForFormSubmission();
const isSubmitted = await contactPage.isFormSubmitted();
expect(isSubmitted).toBe(true);
});
test('应该显示提交按钮的加载状态', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
await contactPage.submitButton.click();
await contactPage.page.waitForTimeout(500);
const isLoading = await contactPage.isSubmitButtonLoading();
expect(isLoading).toBe(true);
});
test('应该显示成功消息', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
expect(isSuccessVisible).toBe(true);
});
test('应该显示正确的成功消息文本', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
const successText = await contactPage.getSuccessMessageText();
expect(successText).toContain('消息已发送');
});
test('应该能够重新提交表单', async ({ contactPage, testDataGenerator }) => {
const formData1 = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData1);
await contactPage.waitForFormSubmission();
await contactPage.page.reload();
await contactPage.waitForPageLoad();
const formData2 = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData2);
await contactPage.waitForFormSubmission();
const isSubmitted = await contactPage.isFormSubmitted();
expect(isSubmitted).toBe(true);
});
test('应该能够输入空格', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = ' 测试消息 ';
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(' 测试消息 ');
});
test('应该能够输入换行符', async ({ contactPage }) => {
const message = '第一行\n第二行\n第三行';
await contactPage.messageInput.fill(message);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toBe(message);
});
test('应该能够输入URL', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.message = `请查看我的网站:${testDataGenerator.generateUrl()}`;
await contactPage.fillContactForm(formData);
const messageValue = await contactPage.getMessageInputValue();
expect(messageValue).toContain('http');
});
test('应该能够输入数字', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
formData.phone = testDataGenerator.generatePhone();
await contactPage.fillContactForm(formData);
const phoneValue = await contactPage.getPhoneInputValue();
expect(phoneValue).toBe(formData.phone);
});
test('应该能够输入电子邮件地址', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
const emailValue = await contactPage.getEmailInputValue();
expect(emailValue).toContain('@');
expect(emailValue).toContain('.');
});
test('应该能够截取表单截图', async ({ contactPage }) => {
await contactPage.scrollToForm();
const isVisible = await contactPage.contactForm.isVisible();
expect(isVisible).toBe(true);
});
test('应该能够截取成功消息截图', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
expect(isSuccessVisible).toBe(true);
});
test('应该正确处理表单重置', async ({ contactPage, testDataGenerator }) => {
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
await contactPage.page.reload();
await contactPage.waitForPageLoad();
const nameValue = await contactPage.getNameInputValue();
const emailValue = await contactPage.getEmailInputValue();
const subjectValue = await contactPage.getSubjectInputValue();
const messageValue = await contactPage.getMessageInputValue();
expect(nameValue).toBe('');
expect(emailValue).toBe('');
expect(subjectValue).toBe('');
expect(messageValue).toBe('');
});
test('应该没有JavaScript错误', async ({ contactPage, page }) => {
const errors: string[] = [];
page.on('pageerror', error => {
errors.push(error.toString());
});
await contactPage.waitForPageLoad();
const formData = { name: '测试', email: 'test@example.com', subject: '测试', message: '测试消息' };
await contactPage.fillContactForm(formData);
await contactPage.submitForm();
await contactPage.waitForFormSubmission();
expect(errors.length).toBe(0);
});
test('应该正确处理网络请求', async ({ contactPage, page }) => {
const failedRequests: string[] = [];
page.on('requestfailed', request => {
failedRequests.push(request.url());
});
await contactPage.waitForPageLoad();
await contactPage.page.waitForTimeout(2000);
expect(failedRequests.length).toBe(0);
});
});
@@ -0,0 +1,213 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('首页回归测试 @regression', () => {
test.beforeEach(async ({ homePage }) => {
await homePage.goto();
await homePage.waitForPageLoad();
});
test('应该正确响应滚动事件', async ({ homePage }) => {
const initialBg = await homePage.getHeaderBackgroundColor();
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
const scrolledBg = await homePage.getHeaderBackgroundColor();
expect(scrolledBg).not.toBe(initialBg);
});
test('应该显示粘性头部', async ({ homePage }) => {
const isSticky = await homePage.isHeaderSticky();
expect(isSticky).toBe(true);
});
test('滚动后应该显示头部阴影', async ({ homePage }) => {
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
const hasShadow = await homePage.isHeaderScrolled();
expect(hasShadow).toBe(true);
});
test('应该能够通过导航跳转到各个区块', async ({ homePage }) => {
const labels = await homePage.getAllNavigationLabels();
for (let i = 0; i < Math.min(labels.length, 3); i++) {
await homePage.clickNavigationItem(labels[i]);
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('#');
}
});
test('应该正确高亮当前区块的导航项', async ({ homePage }) => {
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
const activeItem = await homePage.getActiveNavigationItem();
expect(activeItem).toBeTruthy();
});
test('应该能够点击Logo返回首页', async ({ homePage }) => {
await homePage.scrollToSection('services');
await homePage.logo.click();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toMatch(/\/$/);
});
test('应该能够通过立即咨询按钮跳转到联系页面', async ({ homePage }) => {
await homePage.clickContactButton();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('/contact');
});
test('应该能够打开和关闭移动端菜单', async ({ homePage }) => {
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
await homePage.closeMobileMenu();
await expect(homePage.mobileMenu).not.toBeVisible();
});
test('移动端菜单应该包含所有导航项', async ({ homePage }) => {
await homePage.openMobileMenu();
const desktopNavItems = await homePage.getAllNavigationLabels();
const mobileNavItems = homePage.mobileMenu.locator('a');
const mobileCount = await mobileNavItems.count();
expect(mobileCount).toBeGreaterThan(0);
expect(mobileCount).toBe(desktopNavItems.length);
});
test('应该能够通过移动端菜单导航', async ({ homePage }) => {
await homePage.openMobileMenu();
const firstLink = homePage.mobileMenu.locator('a').first();
await firstLink.click();
await homePage.page.waitForTimeout(1000);
const isMenuVisible = await homePage.mobileMenu.isVisible();
expect(isMenuVisible).toBe(false);
});
test('应该能够平滑滚动到各个区块', async ({ homePage }) => {
const sections = ['services', 'products', 'cases'];
for (const sectionId of sections) {
await homePage.scrollToSection(sectionId);
const isVisible = await homePage.isSectionVisible(sectionId);
expect(isVisible).toBe(true);
}
});
test('应该正确显示所有区块标题', async ({ homePage }) => {
const titles = [
await homePage.getHeroSectionTitle(),
await homePage.getServicesSectionTitle(),
await homePage.getProductsSectionTitle(),
await homePage.getCasesSectionTitle(),
await homePage.getAboutSectionTitle(),
await homePage.getNewsSectionTitle(),
await homePage.getContactSectionTitle(),
];
titles.forEach(title => {
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
});
test('应该能够滚动到页面底部并返回顶部', async ({ homePage }) => {
await homePage.scrollToBottom();
const bottomScroll = await homePage.page.evaluate(() => window.scrollY);
expect(bottomScroll).toBeGreaterThan(0);
await homePage.scrollToTop();
const topScroll = await homePage.page.evaluate(() => window.scrollY);
expect(topScroll).toBe(0);
});
test('应该正确处理快速滚动', async ({ homePage }) => {
for (let i = 0; i < 5; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 500));
await homePage.page.waitForTimeout(100);
}
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBeGreaterThan(0);
});
test('应该能够截取各个区块的截图', async ({ homePage }) => {
const sections = ['home', 'services'];
for (const sectionId of sections) {
await homePage.scrollToSection(sectionId);
await homePage.page.waitForTimeout(500);
const isVisible = await homePage.isSectionVisible(sectionId);
expect(isVisible).toBe(true);
}
});
test('应该正确响应窗口大小变化', async ({ homePage }) => {
await homePage.page.setViewportSize({ width: 768, height: 1024 });
await homePage.page.waitForTimeout(500);
await expect(homePage.header).toBeVisible();
await homePage.page.setViewportSize({ width: 1280, height: 720 });
await homePage.page.waitForTimeout(500);
await expect(homePage.header).toBeVisible();
});
test('应该能够通过键盘导航', async ({ homePage }) => {
await homePage.page.keyboard.press('Tab');
await homePage.page.waitForTimeout(100);
const focusedElement = await homePage.page.evaluate(() => document.activeElement?.tagName);
expect(focusedElement).toBeTruthy();
});
test('应该正确显示页脚内容', async ({ homePage }) => {
await homePage.scrollToBottom();
const footerText = await homePage.getFooterText();
expect(footerText).toBeTruthy();
expect(footerText.length).toBeGreaterThan(0);
});
test('应该能够重新加载页面', async ({ homePage }) => {
await homePage.reload();
await homePage.waitForPageLoad();
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
});
test('应该能够使用浏览器后退按钮', async ({ homePage }) => {
await homePage.clickContactButton();
await homePage.page.waitForTimeout(1000);
await homePage.goBack();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toMatch(/\/$/);
});
test('应该能够使用浏览器前进按钮', async ({ homePage }) => {
await homePage.clickContactButton();
await homePage.page.waitForTimeout(1000);
await homePage.goBack();
await homePage.page.waitForTimeout(1000);
await homePage.goForward();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('/contact');
});
test('应该没有JavaScript错误', async ({ homePage, page }) => {
const errors: string[] = [];
page.on('pageerror', error => {
errors.push(error.toString());
});
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.scrollToSection('products');
await homePage.scrollToSection('cases');
expect(errors.length).toBe(0);
});
test('应该正确处理网络请求', async ({ homePage, page }) => {
const failedRequests: string[] = [];
page.on('requestfailed', request => {
failedRequests.push(request.url());
});
await homePage.waitForPageLoad();
await homePage.page.waitForTimeout(2000);
expect(failedRequests.length).toBe(0);
});
});
@@ -0,0 +1,356 @@
import { test, expect } from '../../fixtures/base.fixture';
import { devices, getMobileDevices } from '../../utils/devices';
test.describe('移动端交互测试 @responsive', () => {
for (const device of getMobileDevices()) {
test(`移动端 ${device.name} - 应该能够打开和关闭菜单`, async ({ homePage, page }) => {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.mobileMenuButton).toBeVisible();
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
await homePage.closeMobileMenu();
await expect(homePage.mobileMenu).not.toBeVisible();
});
}
test('移动端 - 应该能够通过菜单导航', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
const firstLink = homePage.mobileMenu.locator('a').first();
await firstLink.click();
await homePage.page.waitForTimeout(1000);
const isMenuVisible = await homePage.mobileMenu.isVisible();
expect(isMenuVisible).toBe(false);
});
test('移动端 - 应该能够滚动页面', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const initialScroll = await homePage.page.evaluate(() => window.scrollY);
expect(initialScroll).toBe(0);
await homePage.scrollToSection('services');
const afterScroll = await homePage.page.evaluate(() => window.scrollY);
expect(afterScroll).toBeGreaterThan(0);
});
test('移动端 - 应该能够点击Logo', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.logo.click();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toMatch(/\/$/);
});
test('移动端 - 应该能够点击联系按钮', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
const contactButton = homePage.mobileMenu.locator('a:has-text("联系我们")').first();
await contactButton.click();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('/contact');
});
test('移动端 - 应该能够快速滚动', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const startTime = Date.now();
for (let i = 0; i < 10; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 200));
await homePage.page.waitForTimeout(50);
}
const endTime = Date.now();
const scrollDuration = endTime - startTime;
expect(scrollDuration).toBeLessThan(1500);
});
test('移动端 - 应该能够触摸交互', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const heroSection = homePage.heroSection;
await heroSection.tap();
await homePage.page.waitForTimeout(500);
const isVisible = await heroSection.isVisible();
expect(isVisible).toBe(true);
});
test('移动端 - 应该能够滑动页面', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const heroSection = homePage.heroSection;
await heroSection.tap();
const startX = await homePage.page.evaluate(() => window.scrollX);
const startY = await homePage.page.evaluate(() => window.scrollY);
await homePage.page.touchscreen.tap(200, 500);
await homePage.page.waitForTimeout(500);
const endX = await homePage.page.evaluate(() => window.scrollX);
const endY = await homePage.page.evaluate(() => window.scrollY);
expect(endY).toBeGreaterThan(startY);
});
test('移动端 - 应该能够双击缩放', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const heroSection = homePage.heroSection;
await heroSection.tap();
await homePage.page.waitForTimeout(200);
await heroSection.tap();
await homePage.page.waitForTimeout(500);
const isVisible = await heroSection.isVisible();
expect(isVisible).toBe(true);
});
test('移动端 - 应该能够长按', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const heroSection = homePage.heroSection;
await heroSection.tap();
await homePage.page.waitForTimeout(1000);
const isVisible = await heroSection.isVisible();
expect(isVisible).toBe(true);
});
test('移动端 - 应该能够使用键盘导航', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.page.keyboard.press('Tab');
await homePage.page.waitForTimeout(100);
const focusedElement = await homePage.page.evaluate(() => document.activeElement?.tagName);
expect(focusedElement).toBeTruthy();
});
test('移动端 - 应该能够输入表单', async ({ contactPage, page, testDataGenerator }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
const nameValue = await contactPage.getNameInputValue();
const emailValue = await contactPage.getEmailInputValue();
expect(nameValue).toBe(formData.name);
expect(emailValue).toBe(formData.email);
});
test('移动端 - 应该能够提交表单', async ({ contactPage, page, testDataGenerator }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
const isSubmitted = await contactPage.isFormSubmitted();
expect(isSubmitted).toBe(true);
});
test('移动端 - 应该能够滚动到表单', async ({ contactPage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.scrollToForm();
const isVisible = await contactPage.contactForm.isVisible();
expect(isVisible).toBe(true);
});
test('移动端 - 应该能够点击表单字段', async ({ contactPage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.nameInput.tap();
await homePage.page.waitForTimeout(100);
const isFocused = await contactPage.nameInput.evaluate(el => document.activeElement === el);
expect(isFocused).toBe(true);
});
test('移动端 - 应该能够使用返回按钮', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.clickContactButton();
await homePage.page.waitForTimeout(1000);
await homePage.goBack();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toMatch(/\/$/);
});
test('移动端 - 应该能够使用前进按钮', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.clickContactButton();
await homePage.page.waitForTimeout(1000);
await homePage.goBack();
await homePage.page.waitForTimeout(1000);
await homePage.goForward();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('/contact');
});
test('移动端 - 应该能够刷新页面', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.reload();
await homePage.waitForPageLoad();
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
});
test('移动端 - 应该没有JavaScript错误', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
const errors: string[] = [];
page.on('pageerror', error => {
errors.push(error.toString());
});
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.scrollToSection('products');
expect(errors.length).toBe(0);
});
test('移动端 - 应该能够处理快速连续点击', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
const startTime = Date.now();
const links = homePage.mobileMenu.locator('a');
const count = await links.count();
for (let i = 0; i < Math.min(count, 3); i++) {
await links.nth(i).tap();
await homePage.page.waitForTimeout(200);
}
const endTime = Date.now();
const rapidClickDuration = endTime - startTime;
expect(rapidClickDuration).toBeLessThan(2000);
});
test('移动端 - 应该能够处理快速滚动', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const startTime = Date.now();
for (let i = 0; i < 20; i++) {
await homePage.page.evaluate(() => window.scrollBy(0, 100));
await homePage.page.waitForTimeout(30);
}
const endTime = Date.now();
const rapidScrollDuration = endTime - startTime;
expect(rapidScrollDuration).toBeLessThan(1500);
});
test('移动端 - 应该能够处理方向变化', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await page.setViewportSize({ width: 667, height: 375 });
await homePage.page.waitForTimeout(500);
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
});
test('移动端 - 应该能够处理键盘弹出', async ({ contactPage, page, testDataGenerator }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
await contactPage.nameInput.tap();
await contactPage.nameInput.fill(formData.name);
await homePage.page.waitForTimeout(500);
const nameValue = await contactPage.getNameInputValue();
expect(nameValue).toBe(formData.name);
});
});
+339
View File
@@ -0,0 +1,339 @@
import { test, expect } from '../../fixtures/base.fixture';
import { devices, getDesktopDevices, getMobileDevices, getTabletDevices } from '../../utils/devices';
test.describe('响应式测试 @responsive', () => {
for (const device of getDesktopDevices()) {
test(`桌面端 ${device.name} - 首页应该正常显示`, async ({ homePage, page }) => {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
await expect(homePage.footer).toBeVisible();
await expect(homePage.navigation).toBeVisible();
await expect(homePage.mobileMenuButton).not.toBeVisible();
});
}
for (const device of getMobileDevices()) {
test(`移动端 ${device.name} - 首页应该正常显示`, async ({ homePage, page }) => {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
await expect(homePage.footer).toBeVisible();
await expect(homePage.mobileMenuButton).toBeVisible();
});
}
for (const device of getTabletDevices()) {
test(`平板端 ${device.name} - 首页应该正常显示`, async ({ homePage, page }) => {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
await expect(homePage.footer).toBeVisible();
await expect(homePage.mobileMenuButton).toBeVisible();
});
}
test('桌面端 - 导航应该水平显示', async ({ homePage, page }) => {
const device = devices['desktop-1280x720'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.navigation).toBeVisible();
await expect(homePage.mobileMenuButton).not.toBeVisible();
const navItems = await homePage.getNavigationItemCount();
expect(navItems).toBeGreaterThan(0);
});
test('移动端 - 导航应该隐藏在汉堡菜单中', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.mobileMenuButton).toBeVisible();
await expect(homePage.navigation).not.toBeVisible();
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
});
test('平板端 - 导航应该隐藏在汉堡菜单中', async ({ homePage, page }) => {
const device = devices['tablet-768x1024'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.mobileMenuButton).toBeVisible();
await expect(homePage.navigation).not.toBeVisible();
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
});
test('所有设备 - 页面应该能够滚动', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBeGreaterThan(0);
await homePage.scrollToTop();
const topPosition = await homePage.page.evaluate(() => window.scrollY);
expect(topPosition).toBe(0);
}
});
test('所有设备 - 所有区块应该可见', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
const sections = ['services', 'products', 'cases', 'about', 'news', 'contact'];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
for (const sectionId of sections) {
await homePage.scrollToSection(sectionId);
const isVisible = await homePage.isSectionVisible(sectionId);
expect(isVisible).toBe(true);
}
}
});
test('移动端 - 移动菜单应该能够打开和关闭', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
await homePage.closeMobileMenu();
await expect(homePage.mobileMenu).not.toBeVisible();
});
test('桌面端 - Logo应该可见', async ({ homePage, page }) => {
const device = devices['desktop-1280x720'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.logo).toBeVisible();
const altText = await homePage.getLogoAltText();
expect(altText).toBeTruthy();
});
test('移动端 - Logo应该可见', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.logo).toBeVisible();
const altText = await homePage.getLogoAltText();
expect(altText).toBeTruthy();
});
test('所有设备 - 页脚应该可见', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToBottom();
await expect(homePage.footer).toBeVisible();
}
});
test('桌面端 - 立即咨询按钮应该可见', async ({ homePage, page }) => {
const device = devices['desktop-1280x720'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const contactButton = homePage.page.locator('a:has-text("立即咨询")').first();
await expect(contactButton).toBeVisible();
});
test('移动端 - 立即咨询按钮应该可见', async ({ homePage, page }) => {
const device = devices['mobile-375x667'];
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
const contactButton = homePage.mobileMenu.locator('a:has-text("联系我们")').first();
await expect(contactButton).toBeVisible();
});
test('所有设备 - 应该能够点击导航项', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
if (device.isMobile) {
await homePage.openMobileMenu();
}
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 0) {
await homePage.clickNavigationItem(labels[0]);
await homePage.page.waitForTimeout(1000);
}
}
});
test('所有设备 - 应该能够点击Logo返回首页', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.logo.click();
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toMatch(/\/$/);
}
});
test('所有设备 - 应该没有水平滚动条', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const hasHorizontalScroll = await homePage.page.evaluate(() => {
return document.body.scrollWidth > document.body.clientWidth;
});
expect(hasHorizontalScroll).toBe(false);
}
});
test('所有设备 - 文字应该可读', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
const heroTitle = await homePage.getHeroSectionTitle();
expect(heroTitle).toBeTruthy();
expect(heroTitle.length).toBeGreaterThan(0);
}
});
test('所有设备 - 应该能够滚动到页面底部', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToBottom();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBeGreaterThan(0);
}
});
test('所有设备 - 应该能够滚动到页面顶部', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToBottom();
await homePage.scrollToTop();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBe(0);
}
});
test('所有设备 - 页面应该没有JavaScript错误', async ({ homePage, page }) => {
const testDevices = [
devices['desktop-1280x720'],
devices['mobile-375x667'],
devices['tablet-768x1024'],
];
for (const device of testDevices) {
const errors: string[] = [];
page.on('pageerror', error => {
errors.push(error.toString());
});
await page.setViewportSize(device.viewport);
await homePage.goto();
await homePage.waitForPageLoad();
expect(errors.length).toBe(0);
}
});
});
@@ -0,0 +1,173 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('联系页面冒烟测试 @smoke', () => {
test.beforeEach(async ({ contactPage }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
});
test('应该成功加载联系页面', async ({ contactPage }) => {
await expect(contactPage.page).toHaveURL(/\/contact/);
await expect(contactPage.pageHeader).toBeVisible();
await expect(contactPage.contactForm).toBeVisible();
});
test('应该显示正确的页面标题', async ({ contactPage }) => {
const title = await contactPage.getPageTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
expect(title).toContain('联系');
});
test('应该显示页面描述', async ({ contactPage }) => {
const description = await contactPage.getPageDescription();
expect(description).toBeTruthy();
expect(description.length).toBeGreaterThan(0);
});
test('应该显示页面徽章', async ({ contactPage }) => {
const badge = await contactPage.getBadgeText();
expect(badge).toBeTruthy();
expect(badge).toBe('联系我们');
});
test('应该显示联系表单', async ({ contactPage }) => {
await expect(contactPage.contactForm).toBeVisible();
await expect(contactPage.nameInput).toBeVisible();
await expect(contactPage.emailInput).toBeVisible();
await expect(contactPage.subjectInput).toBeVisible();
await expect(contactPage.messageInput).toBeVisible();
await expect(contactPage.submitButton).toBeVisible();
});
test('应该显示所有表单字段', async ({ contactPage }) => {
await expect(contactPage.nameInput).toBeVisible();
await expect(contactPage.phoneInput).toBeVisible();
await expect(contactPage.emailInput).toBeVisible();
await expect(contactPage.subjectInput).toBeVisible();
await expect(contactPage.messageInput).toBeVisible();
});
test('应该显示联系信息卡片', async ({ contactPage }) => {
await expect(contactPage.contactInfoCard).toBeVisible();
await expect(contactPage.addressInfo).toBeVisible();
await expect(contactPage.phoneInfo).toBeVisible();
await expect(contactPage.emailInfo).toBeVisible();
});
test('应该显示工作时间卡片', async ({ contactPage }) => {
await expect(contactPage.workHoursCard).toBeVisible();
const workHours = await contactPage.getWorkHours();
expect(workHours.length).toBeGreaterThan(0);
});
test('应该显示公司地址', async ({ contactPage }) => {
const address = await contactPage.getAddress();
expect(address).toBeTruthy();
expect(address.length).toBeGreaterThan(0);
});
test('应该显示联系电话', async ({ contactPage }) => {
const phone = await contactPage.getPhone();
expect(phone).toBeTruthy();
expect(phone.length).toBeGreaterThan(0);
});
test('应该显示电子邮箱', async ({ contactPage }) => {
const email = await contactPage.getEmail();
expect(email).toBeTruthy();
expect(email.length).toBeGreaterThan(0);
expect(email).toContain('@');
});
test('应该显示提交按钮', async ({ contactPage }) => {
await expect(contactPage.submitButton).toBeVisible();
const buttonText = await contactPage.getSubmitButtonText();
expect(buttonText).toContain('发送');
});
test('应该能够输入姓名', async ({ contactPage }) => {
const testName = '测试用户';
await contactPage.nameInput.fill(testName);
const value = await contactPage.getNameInputValue();
expect(value).toBe(testName);
});
test('应该能够输入电话', async ({ contactPage }) => {
const testPhone = '13800138000';
await contactPage.phoneInput.fill(testPhone);
const value = await contactPage.getPhoneInputValue();
expect(value).toBe(testPhone);
});
test('应该能够输入邮箱', async ({ contactPage }) => {
const testEmail = 'test@example.com';
await contactPage.emailInput.fill(testEmail);
const value = await contactPage.getEmailInputValue();
expect(value).toBe(testEmail);
});
test('应该能够输入主题', async ({ contactPage }) => {
const testSubject = '测试主题';
await contactPage.subjectInput.fill(testSubject);
const value = await contactPage.getSubjectInputValue();
expect(value).toBe(testSubject);
});
test('应该能够输入消息内容', async ({ contactPage }) => {
const testMessage = '这是一条测试消息';
await contactPage.messageInput.fill(testMessage);
const value = await contactPage.getMessageInputValue();
expect(value).toBe(testMessage);
});
test('应该显示必填字段标记', async ({ contactPage }) => {
const isNameRequired = await contactPage.isFieldRequired('name');
const isEmailRequired = await contactPage.isFieldRequired('email');
const isSubjectRequired = await contactPage.isFieldRequired('subject');
const isMessageRequired = await contactPage.isFieldRequired('message');
expect(isNameRequired).toBe(true);
expect(isEmailRequired).toBe(true);
expect(isSubjectRequired).toBe(true);
expect(isMessageRequired).toBe(true);
});
test('应该显示字段占位符', async ({ contactPage }) => {
const namePlaceholder = await contactPage.getFieldPlaceholder('name');
const emailPlaceholder = await contactPage.getFieldPlaceholder('email');
const subjectPlaceholder = await contactPage.getFieldPlaceholder('subject');
const messagePlaceholder = await contactPage.getFieldPlaceholder('message');
expect(namePlaceholder).toBeTruthy();
expect(emailPlaceholder).toBeTruthy();
expect(subjectPlaceholder).toBeTruthy();
expect(messagePlaceholder).toBeTruthy();
});
test('应该有正确的工作时间信息', async ({ contactPage }) => {
const workHours = await contactPage.getWorkHours();
expect(workHours.length).toBeGreaterThan(0);
workHours.forEach(item => {
expect(item.day).toBeTruthy();
expect(item.hours).toBeTruthy();
});
});
test('应该没有控制台错误', async ({ contactPage, page }) => {
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
await contactPage.waitForPageLoad();
expect(errors.length).toBe(0);
});
test('应该能够滚动到表单', async ({ contactPage }) => {
await contactPage.scrollToForm();
const isVisible = await contactPage.contactForm.isVisible();
expect(isVisible).toBe(true);
});
});
+137
View File
@@ -0,0 +1,137 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('首页冒烟测试 @smoke', () => {
test.beforeEach(async ({ homePage }) => {
await homePage.goto();
await homePage.waitForPageLoad();
});
test('应该成功加载首页', async ({ homePage }) => {
await expect(homePage.page).toHaveURL(/\/$/);
await expect(homePage.header).toBeVisible();
await expect(homePage.heroSection).toBeVisible();
await expect(homePage.footer).toBeVisible();
});
test('应该显示正确的页面标题', async ({ homePage }) => {
const title = await homePage.getTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示Logo', async ({ homePage }) => {
await expect(homePage.logo).toBeVisible();
const altText = await homePage.getLogoAltText();
expect(altText).toBeTruthy();
});
test('应该显示主导航菜单', async ({ homePage }) => {
await expect(homePage.navigation).toBeVisible();
const navItems = await homePage.getNavigationItemCount();
expect(navItems).toBeGreaterThan(0);
});
test('应该显示所有主要区块', async ({ homePage }) => {
await expect(homePage.heroSection).toBeVisible();
await homePage.scrollToSection('services');
await expect(homePage.servicesSection).toBeVisible();
await homePage.scrollToSection('products');
await expect(homePage.productsSection).toBeVisible();
await homePage.scrollToSection('cases');
await expect(homePage.casesSection).toBeVisible();
await homePage.scrollToSection('about');
await expect(homePage.aboutSection).toBeVisible();
await homePage.scrollToSection('news');
await expect(homePage.newsSection).toBeVisible();
await homePage.scrollToSection('contact');
await expect(homePage.contactSection).toBeVisible();
});
test('应该显示页脚', async ({ homePage }) => {
await homePage.scrollToBottom();
await expect(homePage.footer).toBeVisible();
const footerText = await homePage.getFooterText();
expect(footerText.length).toBeGreaterThan(0);
});
test('应该能够滚动到页面底部', async ({ homePage }) => {
await homePage.scrollToBottom();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBeGreaterThan(0);
});
test('应该能够滚动到页面顶部', async ({ homePage }) => {
await homePage.scrollToBottom();
await homePage.scrollToTop();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBe(0);
});
test('应该显示Hero区块标题', async ({ homePage }) => {
const title = await homePage.getHeroSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示Services区块标题', async ({ homePage }) => {
await homePage.waitForServicesSection();
const title = await homePage.getServicesSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示Products区块标题', async ({ homePage }) => {
await homePage.waitForProductsSection();
const title = await homePage.getProductsSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示Cases区块标题', async ({ homePage }) => {
await homePage.waitForCasesSection();
const title = await homePage.getCasesSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示About区块标题', async ({ homePage }) => {
await homePage.waitForAboutSection();
const title = await homePage.getAboutSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示News区块标题', async ({ homePage }) => {
await homePage.waitForNewsSection();
const title = await homePage.getNewsSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该显示Contact区块标题', async ({ homePage }) => {
await homePage.waitForContactSection();
const title = await homePage.getContactSectionTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该有正确的导航标签', async ({ homePage }) => {
const labels = await homePage.getAllNavigationLabels();
expect(labels.length).toBeGreaterThan(0);
labels.forEach(label => {
expect(label).toBeTruthy();
expect(label.length).toBeGreaterThan(0);
});
});
test('应该没有控制台错误', async ({ homePage, page }) => {
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
await homePage.waitForPageLoad();
expect(errors.length).toBe(0);
});
});
@@ -0,0 +1,131 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('导航冒烟测试 @smoke', () => {
test.beforeEach(async ({ homePage }) => {
await homePage.goto();
await homePage.waitForPageLoad();
});
test('应该显示主导航菜单', async ({ homePage }) => {
await expect(homePage.navigation).toBeVisible();
});
test('应该显示Logo链接', async ({ homePage }) => {
await expect(homePage.logo).toBeVisible();
const altText = await homePage.getLogoAltText();
expect(altText).toBeTruthy();
});
test('应该有导航项', async ({ homePage }) => {
const navItems = await homePage.getNavigationItemCount();
expect(navItems).toBeGreaterThan(0);
});
test('应该能够点击导航项', async ({ homePage }) => {
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 0) {
await homePage.clickNavigationItem(labels[0]);
await homePage.page.waitForTimeout(1000);
}
});
test('应该显示立即咨询按钮', async ({ homePage }) => {
const contactButton = homePage.page.locator('a:has-text("立即咨询")').first();
await expect(contactButton).toBeVisible();
});
test('应该能够点击立即咨询按钮', async ({ homePage }) => {
const contactButton = homePage.page.locator('a:has-text("立即咨询")').first();
await contactButton.click();
await homePage.page.waitForTimeout(2000);
const url = homePage.page.url();
console.log('点击立即咨询后的URL:', url);
expect(url).toContain('/contact');
});
test('应该显示移动端菜单按钮', async ({ homePage }) => {
await expect(homePage.mobileMenuButton).toBeVisible();
});
test('应该能够打开移动端菜单', async ({ homePage }) => {
await homePage.openMobileMenu();
await expect(homePage.mobileMenu).toBeVisible();
});
test('应该能够关闭移动端菜单', async ({ homePage }) => {
await homePage.openMobileMenu();
await homePage.closeMobileMenu();
await expect(homePage.mobileMenu).not.toBeVisible();
});
test('应该有正确的导航标签', async ({ homePage }) => {
const labels = await homePage.getAllNavigationLabels();
expect(labels.length).toBeGreaterThan(0);
labels.forEach(label => {
expect(label).toBeTruthy();
expect(label.length).toBeGreaterThan(0);
});
});
test('应该能够滚动到各个区块', async ({ homePage }) => {
const sections = ['services', 'products', 'cases', 'about', 'news', 'contact'];
for (const sectionId of sections) {
await homePage.scrollToSection(sectionId);
const isVisible = await homePage.isSectionVisible(sectionId);
expect(isVisible).toBe(true);
}
});
test('应该能够滚动到页面顶部', async ({ homePage }) => {
await homePage.scrollToBottom();
await homePage.scrollToTop();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBe(0);
});
test('应该能够滚动到页面底部', async ({ homePage }) => {
await homePage.scrollToBottom();
const scrollPosition = await homePage.page.evaluate(() => window.scrollY);
expect(scrollPosition).toBeGreaterThan(0);
});
test('应该显示所有区块', async ({ homePage }) => {
const sectionIds = await homePage.getAllSectionIds();
expect(sectionIds.length).toBeGreaterThan(0);
sectionIds.forEach(sectionId => {
expect(sectionId).toBeTruthy();
});
});
test('应该能够通过导航跳转到区块', async ({ homePage }) => {
const labels = await homePage.getAllNavigationLabels();
if (labels.length > 1) {
await homePage.clickNavigationItem(labels[1]);
await homePage.page.waitForTimeout(1000);
const url = homePage.page.url();
expect(url).toContain('#');
}
});
test('应该显示页脚', async ({ homePage }) => {
await homePage.scrollToBottom();
await expect(homePage.footer).toBeVisible();
});
test('应该有正确的页面标题', async ({ homePage }) => {
const title = await homePage.getTitle();
expect(title).toBeTruthy();
expect(title.length).toBeGreaterThan(0);
});
test('应该没有控制台错误', async ({ homePage, page }) => {
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
await homePage.waitForPageLoad();
expect(errors.length).toBe(0);
});
});
@@ -0,0 +1,298 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('联系页面视觉回归测试 @visual', () => {
test('联系页面 - 页面头部应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.pageHeader).toHaveScreenshot('contact-page-header.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 联系表单应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.contactForm).toHaveScreenshot('contact-form.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 联系信息卡片应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.contactInfoCard).toHaveScreenshot('contact-info-card.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 工作时间卡片应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.workHoursCard).toHaveScreenshot('work-hours-card.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 表单字段应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.nameInput).toHaveScreenshot('name-input.png', {
maxDiffPixels: 20,
threshold: 0.1,
});
});
test('联系页面 - 邮箱字段应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.emailInput).toHaveScreenshot('email-input.png', {
maxDiffPixels: 20,
threshold: 0.1,
});
});
test('联系页面 - 主题字段应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.subjectInput).toHaveScreenshot('subject-input.png', {
maxDiffPixels: 20,
threshold: 0.1,
});
});
test('联系页面 - 消息字段应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.messageInput).toHaveScreenshot('message-input.png', {
maxDiffPixels: 50,
threshold: 0.15,
});
});
test('联系页面 - 提交按钮应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.submitButton).toHaveScreenshot('submit-button.png', {
maxDiffPixels: 30,
threshold: 0.15,
});
});
test('联系页面 - 完整页面应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(page).toHaveScreenshot('contact-full-page.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 滚动后页面应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.scrollToForm();
await contactPage.page.waitForTimeout(500);
await expect(page).toHaveScreenshot('contact-scrolled-page.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 移动端视图应该与基线匹配', async ({ contactPage, page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(page).toHaveScreenshot('contact-mobile-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 平板端视图应该与基线匹配', async ({ contactPage, page }) => {
await page.setViewportSize({ width: 768, height: 1024 });
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(page).toHaveScreenshot('contact-tablet-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 桌面端视图应该与基线匹配', async ({ contactPage, page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(page).toHaveScreenshot('contact-desktop-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 填写表单后应该与基线匹配', async ({ contactPage, page, testDataGenerator }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillContactForm(formData);
await contactPage.page.waitForTimeout(500);
await expect(contactPage.contactForm).toHaveScreenshot('contact-form-filled.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 提交成功后应该与基线匹配', async ({ contactPage, page, testDataGenerator }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const formData = testDataGenerator.generateContactFormData();
await contactPage.fillAndSubmitForm(formData);
await contactPage.waitForFormSubmission();
await expect(contactPage.successMessage).toHaveScreenshot('contact-success.png', {
maxDiffPixels: 50,
threshold: 0.15,
});
});
test('联系页面 - 应该能够捕获视觉差异', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const screenshot = await page.screenshot({
fullPage: true,
path: 'test-results/screenshots/contact-page-visual.png',
});
expect(screenshot).toBeTruthy();
});
test('联系页面 - 应该能够比较视觉差异', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.contactForm).toHaveScreenshot('contact-comparison.png', {
maxDiffPixels: 100,
threshold: 0.2,
animations: 'disabled',
});
});
test('联系页面 - 应该能够禁用动画进行截图', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(page).toHaveScreenshot('contact-no-animations.png', {
fullPage: true,
animations: 'disabled',
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('联系页面 - 应该能够捕获高DPI截图', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
const screenshot = await page.screenshot({
fullPage: true,
scale: 'device',
path: 'test-results/screenshots/contact-high-dpi.png',
});
expect(screenshot).toBeTruthy();
});
test('联系页面 - 表单字段焦点状态应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.nameInput.focus();
await contactPage.page.waitForTimeout(300);
await expect(contactPage.nameInput).toHaveScreenshot('name-input-focused.png', {
maxDiffPixels: 30,
threshold: 0.15,
});
});
test('联系页面 - 表单字段悬停状态应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.nameInput.hover();
await contactPage.page.waitForTimeout(300);
await expect(contactPage.nameInput).toHaveScreenshot('name-input-hover.png', {
maxDiffPixels: 30,
threshold: 0.15,
});
});
test('联系页面 - 提交按钮悬停状态应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await contactPage.submitButton.hover();
await contactPage.page.waitForTimeout(300);
await expect(contactPage.submitButton).toHaveScreenshot('submit-button-hover.png', {
maxDiffPixels: 30,
threshold: 0.15,
});
});
test('联系页面 - 所有表单字段应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.contactForm).toHaveScreenshot('all-form-fields.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 联系信息应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.contactInfoCard).toHaveScreenshot('contact-info.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('联系页面 - 工作时间应该与基线匹配', async ({ contactPage, page }) => {
await contactPage.goto();
await contactPage.waitForPageLoad();
await expect(contactPage.workHoursCard).toHaveScreenshot('work-hours.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
});
@@ -0,0 +1,298 @@
import { test, expect } from '../../fixtures/base.fixture';
test.describe('首页视觉回归测试 @visual', () => {
test('首页 - Hero区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.heroSection).toHaveScreenshot('hero-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Services区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
await expect(homePage.servicesSection).toHaveScreenshot('services-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Products区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('products');
await homePage.page.waitForTimeout(500);
await expect(homePage.productsSection).toHaveScreenshot('products-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Cases区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('cases');
await homePage.page.waitForTimeout(500);
await expect(homePage.casesSection).toHaveScreenshot('cases-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - About区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('about');
await homePage.page.waitForTimeout(500);
await expect(homePage.aboutSection).toHaveScreenshot('about-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - News区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('news');
await homePage.page.waitForTimeout(500);
await expect(homePage.newsSection).toHaveScreenshot('news-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Contact区块应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('contact');
await homePage.page.waitForTimeout(500);
await expect(homePage.contactSection).toHaveScreenshot('contact-section.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Header应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.header).toHaveScreenshot('header.png', {
maxDiffPixels: 50,
threshold: 0.1,
});
});
test('首页 - Footer应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToBottom();
await homePage.page.waitForTimeout(500);
await expect(homePage.footer).toHaveScreenshot('footer.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - Logo应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.logo).toHaveScreenshot('logo.png', {
maxDiffPixels: 10,
threshold: 0.05,
});
});
test('首页 - 导航应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.navigation).toHaveScreenshot('navigation.png', {
maxDiffPixels: 50,
threshold: 0.1,
});
});
test('首页 - 完整页面应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(page).toHaveScreenshot('full-page.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - 滚动后页面应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
await expect(page).toHaveScreenshot('scrolled-page.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - Hero区块标题应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const title = homePage.heroSection.locator('h1, h2').first();
await expect(title).toHaveScreenshot('hero-title.png', {
maxDiffPixels: 20,
threshold: 0.1,
});
});
test('首页 - 悬停状态应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const firstNavItem = homePage.navigation.locator('a').first();
await firstNavItem.hover();
await homePage.page.waitForTimeout(300);
await expect(homePage.navigation).toHaveScreenshot('nav-hover.png', {
maxDiffPixels: 50,
threshold: 0.1,
});
});
test('首页 - 移动端视图应该与基线匹配', async ({ homePage, page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await homePage.goto();
await homePage.waitForPageLoad();
await expect(page).toHaveScreenshot('mobile-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - 平板端视图应该与基线匹配', async ({ homePage, page }) => {
await page.setViewportSize({ width: 768, height: 1024 });
await homePage.goto();
await homePage.waitForPageLoad();
await expect(page).toHaveScreenshot('tablet-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - 桌面端视图应该与基线匹配', async ({ homePage, page }) => {
await page.setViewportSize({ width: 1280, height: 720 });
await homePage.goto();
await homePage.waitForPageLoad();
await expect(page).toHaveScreenshot('desktop-view.png', {
fullPage: true,
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - 移动端菜单应该与基线匹配', async ({ homePage, page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.openMobileMenu();
await homePage.page.waitForTimeout(300);
await expect(homePage.mobileMenu).toHaveScreenshot('mobile-menu.png', {
maxDiffPixels: 100,
threshold: 0.2,
});
});
test('首页 - 滚动后Header应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToSection('services');
await homePage.page.waitForTimeout(500);
await expect(homePage.header).toHaveScreenshot('header-scrolled.png', {
maxDiffPixels: 50,
threshold: 0.1,
});
});
test('首页 - 所有区块组合应该与基线匹配', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await homePage.scrollToBottom();
await homePage.page.waitForTimeout(500);
await expect(page).toHaveScreenshot('all-sections.png', {
fullPage: true,
maxDiffPixels: 300,
threshold: 0.4,
});
});
test('首页 - 应该能够捕获视觉差异', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const screenshot = await page.screenshot({
fullPage: true,
path: 'test-results/screenshots/homepage-visual.png',
});
expect(screenshot).toBeTruthy();
});
test('首页 - 应该能够比较视觉差异', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(homePage.heroSection).toHaveScreenshot('hero-comparison.png', {
maxDiffPixels: 100,
threshold: 0.2,
animations: 'disabled',
});
});
test('首页 - 应该能够禁用动画进行截图', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
await expect(page).toHaveScreenshot('no-animations.png', {
fullPage: true,
animations: 'disabled',
maxDiffPixels: 200,
threshold: 0.3,
});
});
test('首页 - 应该能够捕获高DPI截图', async ({ homePage, page }) => {
await homePage.goto();
await homePage.waitForPageLoad();
const screenshot = await page.screenshot({
fullPage: true,
scale: 'device',
path: 'test-results/screenshots/homepage-high-dpi.png',
});
expect(screenshot).toBeTruthy();
});
});