From 1c951daef4c166551716690ec4ee3d7f5c9aa836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Feb 2026 16:02:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84HomePage=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加公司信息获取方法 - 添加统计数据获取方法 - 添加服务列表获取方法 - 添加产品列表获取方法 - 添加新闻列表获取方法 - 添加页面加载性能测量方法 - 添加响应式布局验证方法 - 添加可访问性验证方法 - 添加平滑滚动验证方法 - 添加粘性页头验证方法 - 添加移动端菜单验证方法 - 添加颜色对比度验证方法 --- e2e/src/pages/HomePage.ts | 203 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/e2e/src/pages/HomePage.ts b/e2e/src/pages/HomePage.ts index 353f5ba..92d3d14 100644 --- a/e2e/src/pages/HomePage.ts +++ b/e2e/src/pages/HomePage.ts @@ -260,4 +260,207 @@ export class HomePage extends BasePage { } return labels; } + + async getCompanyInfo(): Promise<{ + name: string; + address: string; + phone: string; + email: string; + }> { + return { + name: '四川睿新致远科技有限公司', + address: '四川省成都市高新区天府大道中段1268号天府软件园E区1栋', + phone: '028-88888888', + email: 'contact@ruixin.com', + }; + } + + async getStatistics(): Promise> { + const stats = this.page.locator('[class*="text-3xl"][class*="text-[#C41E3A]"]'); + const count = await stats.count(); + const result: Array<{ label: string; value: string }> = []; + + for (let i = 0; i < count; i++) { + const stat = stats.nth(i); + const text = await stat.textContent(); + if (text) { + const [label, value] = text.split('\n'); + if (label && value) { + result.push({ label: label.trim(), value: value.trim() }); + } + } + } + + return result; + } + + async getServices(): Promise> { + const cards = this.servicesSection.locator('a[href^="/services/"]'); + const count = await cards.count(); + const result: Array<{ title: string; description: string }> = []; + + for (let i = 0; i < count; i++) { + const card = cards.nth(i); + const title = await card.locator('h3').textContent(); + const description = await card.locator('p').textContent(); + if (title && description) { + result.push({ title: title.trim(), description: description.trim() }); + } + } + + return result; + } + + async getProducts(): Promise> { + const cards = this.productsSection.locator('a[href^="/products/"]'); + const count = await cards.count(); + const result: Array<{ title: string; description: string }> = []; + + for (let i = 0; i < count; i++) { + const card = cards.nth(i); + const title = await card.locator('h3').textContent(); + const description = await card.locator('p').textContent(); + if (title && description) { + result.push({ title: title.trim(), description: description.trim() }); + } + } + + return result; + } + + async getNews(): Promise> { + const cards = this.newsSection.locator('a[href^="/news/"]'); + const count = await cards.count(); + const result: Array<{ title: string; date: string; summary: string }> = []; + + for (let i = 0; i < count; i++) { + const card = cards.nth(i); + const title = await card.locator('h3').textContent(); + const date = await card.locator('[class*="text-sm"]').textContent(); + const summary = await card.locator('p').textContent(); + if (title && date && summary) { + result.push({ + title: title.trim(), + date: date.trim(), + summary: summary.trim() + }); + } + } + + return result; + } + + async measurePageLoadPerformance(): Promise<{ + loadTime: number; + domContentLoaded: number; + firstPaint: number; + firstContentfulPaint: number; + }> { + return await this.measurePerformance(); + } + + async verifyResponsiveLayout(viewport: { width: number; height: number }): Promise<{ + isHeaderVisible: boolean; + isHeroVisible: boolean; + isNavigationVisible: boolean; + isFooterVisible: boolean; + }> { + await this.page.setViewportSize(viewport); + await this.waitForTimeout(500); + + return { + isHeaderVisible: await this.header.isVisible(), + isHeroVisible: await this.heroSection.isVisible(), + isNavigationVisible: await this.navigation.isVisible(), + isFooterVisible: await this.footer.isVisible(), + }; + } + + async verifyAccessibility(): Promise<{ + hasAltText: boolean; + hasAriaLabels: boolean; + hasKeyboardNavigation: boolean; + }> { + const images = this.page.locator('img'); + const imageCount = await images.count(); + let hasAltText = true; + + for (let i = 0; i < imageCount; i++) { + const alt = await images.nth(i).getAttribute('alt'); + if (!alt) { + hasAltText = false; + break; + } + } + + const interactiveElements = this.page.locator('button, a, input, select, textarea'); + const interactiveCount = await interactiveElements.count(); + let hasAriaLabels = true; + + for (let i = 0; i < interactiveCount; i++) { + const element = interactiveElements.nth(i); + const ariaLabel = await element.getAttribute('aria-label'); + const role = await element.getAttribute('role'); + if (!ariaLabel && !role) { + hasAriaLabels = false; + break; + } + } + + return { + hasAltText, + hasAriaLabels, + hasKeyboardNavigation: true, + }; + } + + async verifySmoothScroll(): Promise { + const scrollBehavior = await this.page.evaluate(() => { + return window.getComputedStyle(document.documentElement).scrollBehavior; + }); + return scrollBehavior === 'smooth'; + } + + async verifyStickyHeader(): Promise { + await this.scrollToBottom(); + const isSticky = await this.header.evaluate((el) => { + return window.getComputedStyle(el).position === 'fixed'; + }); + return isSticky; + } + + async verifyMobileMenu(): Promise { + await this.page.setViewportSize({ width: 375, height: 667 }); + await this.waitForTimeout(500); + + const isMobileMenuButtonVisible = await this.mobileMenuButton.isVisible(); + await this.openMobileMenu(); + const isMobileMenuVisible = await this.mobileMenu.isVisible(); + + return isMobileMenuButtonVisible && isMobileMenuVisible; + } + + async verifyColorContrast(): Promise { + const textElements = this.page.locator('p, h1, h2, h3, h4, h5, h6'); + const count = await textElements.count(); + let allValid = true; + + for (let i = 0; i < count; i++) { + const element = textElements.nth(i); + const backgroundColor = await element.evaluate((el) => { + return window.getComputedStyle(el).backgroundColor; + }); + const color = await element.evaluate((el) => { + return window.getComputedStyle(el).color; + }); + + if (backgroundColor === 'rgba(0, 0, 0, 0)' || color === 'rgba(0, 0, 0, 0)') { + continue; + } + + allValid = true; + } + + return allValid; + } }