feat: 完善HomePage页面对象
- 添加公司信息获取方法 - 添加统计数据获取方法 - 添加服务列表获取方法 - 添加产品列表获取方法 - 添加新闻列表获取方法 - 添加页面加载性能测量方法 - 添加响应式布局验证方法 - 添加可访问性验证方法 - 添加平滑滚动验证方法 - 添加粘性页头验证方法 - 添加移动端菜单验证方法 - 添加颜色对比度验证方法
This commit is contained in:
@@ -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<Array<{ label: string; value: string }>> {
|
||||
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<Array<{ title: string; description: string }>> {
|
||||
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<Array<{ title: string; description: string }>> {
|
||||
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<Array<{ title: string; date: string; summary: string }>> {
|
||||
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<boolean> {
|
||||
const scrollBehavior = await this.page.evaluate(() => {
|
||||
return window.getComputedStyle(document.documentElement).scrollBehavior;
|
||||
});
|
||||
return scrollBehavior === 'smooth';
|
||||
}
|
||||
|
||||
async verifyStickyHeader(): Promise<boolean> {
|
||||
await this.scrollToBottom();
|
||||
const isSticky = await this.header.evaluate((el) => {
|
||||
return window.getComputedStyle(el).position === 'fixed';
|
||||
});
|
||||
return isSticky;
|
||||
}
|
||||
|
||||
async verifyMobileMenu(): Promise<boolean> {
|
||||
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<boolean> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user