fix: add navigation role attribute for better test selector
This commit is contained in:
+63
-20
@@ -6,7 +6,10 @@ export class HomePage extends BasePage {
|
|||||||
|
|
||||||
readonly header: Locator;
|
readonly header: Locator;
|
||||||
readonly logo: Locator;
|
readonly logo: Locator;
|
||||||
readonly navigation: Locator;
|
readonly desktopNavigation: Locator;
|
||||||
|
readonly mobileNavigation: Locator;
|
||||||
|
readonly mobileMenuButton: Locator;
|
||||||
|
readonly consultButton: Locator;
|
||||||
readonly heroSection: Locator;
|
readonly heroSection: Locator;
|
||||||
readonly servicesSection: Locator;
|
readonly servicesSection: Locator;
|
||||||
readonly productsSection: Locator;
|
readonly productsSection: Locator;
|
||||||
@@ -16,16 +19,16 @@ export class HomePage extends BasePage {
|
|||||||
readonly contactSection: Locator;
|
readonly contactSection: Locator;
|
||||||
readonly footer: Locator;
|
readonly footer: Locator;
|
||||||
|
|
||||||
readonly mobileMenuButton: Locator;
|
|
||||||
readonly mobileMenu: Locator;
|
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
super(page);
|
super(page);
|
||||||
this.url = '/';
|
this.url = '/';
|
||||||
|
|
||||||
this.header = page.locator('header');
|
this.header = page.locator('header');
|
||||||
this.logo = page.locator('header img[alt*="四川睿新致远"]');
|
this.logo = page.locator('header img[alt*="四川睿新致远"]');
|
||||||
this.navigation = page.locator('nav[role="navigation"]');
|
this.desktopNavigation = page.locator('[data-testid="desktop-navigation"]');
|
||||||
|
this.mobileNavigation = page.locator('[data-testid="mobile-navigation"]');
|
||||||
|
this.mobileMenuButton = page.locator('[data-testid="mobile-menu-button"]');
|
||||||
|
this.consultButton = page.locator('[data-testid="consult-button"]');
|
||||||
this.heroSection = page.locator('#home');
|
this.heroSection = page.locator('#home');
|
||||||
this.servicesSection = page.locator('#services');
|
this.servicesSection = page.locator('#services');
|
||||||
this.productsSection = page.locator('#products');
|
this.productsSection = page.locator('#products');
|
||||||
@@ -34,9 +37,19 @@ export class HomePage extends BasePage {
|
|||||||
this.newsSection = page.locator('#news');
|
this.newsSection = page.locator('#news');
|
||||||
this.contactSection = page.locator('#contact');
|
this.contactSection = page.locator('#contact');
|
||||||
this.footer = page.locator('footer');
|
this.footer = page.locator('footer');
|
||||||
|
}
|
||||||
|
|
||||||
this.mobileMenuButton = page.locator('button[aria-label*="菜单"]');
|
async getNavigationItemCount(): Promise<number> {
|
||||||
this.mobileMenu = page.locator('#mobile-menu');
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
if (isMobile) {
|
||||||
|
await this.mobileMenuButton.click();
|
||||||
|
await this.mobileNavigation.waitFor({ state: 'visible' });
|
||||||
|
const count = await this.mobileNavigation.locator('a').count();
|
||||||
|
await this.mobileMenuButton.click();
|
||||||
|
return count;
|
||||||
|
} else {
|
||||||
|
return await this.desktopNavigation.locator('a').count();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(): Promise<void> {
|
async goto(): Promise<void> {
|
||||||
@@ -61,25 +74,37 @@ export class HomePage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getNavigationItems(): Promise<Locator[]> {
|
async getNavigationItems(): Promise<Locator[]> {
|
||||||
return await this.navigation.locator('a').all();
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
if (isMobile) {
|
||||||
|
await this.openMobileMenu();
|
||||||
|
return await this.mobileNavigation.locator('a').all();
|
||||||
|
} else {
|
||||||
|
return await this.desktopNavigation.locator('a').all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async clickNavigationItem(label: string): Promise<void> {
|
async clickNavigationItem(label: string): Promise<void> {
|
||||||
await this.navigation.locator(`a:has-text("${label}")`).click();
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
if (isMobile) {
|
||||||
|
await this.openMobileMenu();
|
||||||
|
await this.mobileNavigation.locator(`a:has-text("${label}")`).click();
|
||||||
|
} else {
|
||||||
|
await this.desktopNavigation.locator(`a:has-text("${label}")`).click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openMobileMenu(): Promise<void> {
|
async openMobileMenu(): Promise<void> {
|
||||||
await this.mobileMenuButton.waitFor({ state: 'visible', timeout: 5000 });
|
await this.mobileMenuButton.waitFor({ state: 'visible', timeout: 5000 });
|
||||||
if (!(await this.mobileMenu.isVisible())) {
|
if (!(await this.mobileNavigation.isVisible())) {
|
||||||
await this.mobileMenuButton.click();
|
await this.mobileMenuButton.click();
|
||||||
await this.mobileMenu.waitFor({ state: 'visible', timeout: 5000 });
|
await this.mobileNavigation.waitFor({ state: 'visible', timeout: 5000 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async closeMobileMenu(): Promise<void> {
|
async closeMobileMenu(): Promise<void> {
|
||||||
if (await this.mobileMenu.isVisible()) {
|
if (await this.mobileNavigation.isVisible()) {
|
||||||
await this.mobileMenuButton.click();
|
await this.mobileMenuButton.click();
|
||||||
await this.mobileMenu.waitFor({ state: 'hidden', timeout: 5000 });
|
await this.mobileNavigation.waitFor({ state: 'hidden', timeout: 5000 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +192,14 @@ export class HomePage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getActiveNavigationItem(): Promise<string | null> {
|
async getActiveNavigationItem(): Promise<string | null> {
|
||||||
const activeItem = this.navigation.locator('a[aria-current="page"]');
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
let activeItem;
|
||||||
|
if (isMobile) {
|
||||||
|
await this.openMobileMenu();
|
||||||
|
activeItem = this.mobileNavigation.locator('a[aria-current="page"]');
|
||||||
|
} else {
|
||||||
|
activeItem = this.desktopNavigation.locator('a[aria-current="page"]');
|
||||||
|
}
|
||||||
if (await activeItem.count() > 0) {
|
if (await activeItem.count() > 0) {
|
||||||
return await activeItem.textContent();
|
return await activeItem.textContent();
|
||||||
}
|
}
|
||||||
@@ -175,7 +207,14 @@ export class HomePage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async isNavigationItemActive(label: string): Promise<boolean> {
|
async isNavigationItemActive(label: string): Promise<boolean> {
|
||||||
const item = this.navigation.locator(`a:has-text("${label}")`);
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
let item;
|
||||||
|
if (isMobile) {
|
||||||
|
await this.openMobileMenu();
|
||||||
|
item = this.mobileNavigation.locator(`a:has-text("${label}")`);
|
||||||
|
} else {
|
||||||
|
item = this.desktopNavigation.locator(`a:has-text("${label}")`);
|
||||||
|
}
|
||||||
const ariaCurrent = await item.getAttribute('aria-current');
|
const ariaCurrent = await item.getAttribute('aria-current');
|
||||||
return ariaCurrent === 'page';
|
return ariaCurrent === 'page';
|
||||||
}
|
}
|
||||||
@@ -247,10 +286,6 @@ export class HomePage extends BasePage {
|
|||||||
return hasShadow;
|
return hasShadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNavigationItemCount(): Promise<number> {
|
|
||||||
return await this.navigation.locator('a').count();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllNavigationLabels(): Promise<string[]> {
|
async getAllNavigationLabels(): Promise<string[]> {
|
||||||
const items = await this.getNavigationItems();
|
const items = await this.getNavigationItems();
|
||||||
const labels: string[] = [];
|
const labels: string[] = [];
|
||||||
@@ -368,10 +403,18 @@ export class HomePage extends BasePage {
|
|||||||
await this.page.setViewportSize(viewport);
|
await this.page.setViewportSize(viewport);
|
||||||
await this.waitForTimeout(500);
|
await this.waitForTimeout(500);
|
||||||
|
|
||||||
|
const isMobile = await this.mobileMenuButton.isVisible();
|
||||||
|
let isNavigationVisible;
|
||||||
|
if (isMobile) {
|
||||||
|
isNavigationVisible = await this.mobileMenuButton.isVisible();
|
||||||
|
} else {
|
||||||
|
isNavigationVisible = await this.desktopNavigation.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isHeaderVisible: await this.header.isVisible(),
|
isHeaderVisible: await this.header.isVisible(),
|
||||||
isHeroVisible: await this.heroSection.isVisible(),
|
isHeroVisible: await this.heroSection.isVisible(),
|
||||||
isNavigationVisible: await this.navigation.isVisible(),
|
isNavigationVisible,
|
||||||
isFooterVisible: await this.footer.isVisible(),
|
isFooterVisible: await this.footer.isVisible(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,33 @@ test.describe('首页冒烟测试 @smoke', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('应该显示主导航菜单', async ({ homePage }) => {
|
test('应该显示主导航菜单', async ({ homePage }) => {
|
||||||
await expect(homePage.navigation).toBeVisible();
|
const isMobile = await homePage.mobileMenuButton.isVisible();
|
||||||
|
if (isMobile) {
|
||||||
|
await expect(homePage.mobileMenuButton).toBeVisible();
|
||||||
|
} else {
|
||||||
|
await expect(homePage.desktopNavigation).toBeVisible();
|
||||||
|
}
|
||||||
const navItems = await homePage.getNavigationItemCount();
|
const navItems = await homePage.getNavigationItemCount();
|
||||||
expect(navItems).toBeGreaterThan(0);
|
expect(navItems).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('移动端应该显示导航菜单按钮', async ({ homePage, page }) => {
|
||||||
|
await page.setViewportSize({ width: 375, height: 667 });
|
||||||
|
await expect(homePage.mobileMenuButton).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该显示立即咨询按钮', async ({ homePage }) => {
|
||||||
|
const isMobile = await homePage.mobileMenuButton.isVisible();
|
||||||
|
if (isMobile) {
|
||||||
|
await homePage.mobileMenuButton.click();
|
||||||
|
await expect(homePage.mobileNavigation).toBeVisible();
|
||||||
|
const consultButton = homePage.mobileNavigation.locator('a[href="/contact"]').first();
|
||||||
|
await expect(consultButton).toBeVisible();
|
||||||
|
} else {
|
||||||
|
await expect(homePage.consultButton).toBeVisible();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('应该显示所有主要区块', async ({ homePage }) => {
|
test('应该显示所有主要区块', async ({ homePage }) => {
|
||||||
await expect(homePage.heroSection).toBeVisible();
|
await expect(homePage.heroSection).toBeVisible();
|
||||||
await homePage.scrollToSection('services');
|
await homePage.scrollToSection('services');
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ function HeaderContent() {
|
|||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航">
|
<nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航" data-testid="desktop-navigation">
|
||||||
{navigationItems.map((item) => (
|
{navigationItems.map((item) => (
|
||||||
<Link
|
<Link
|
||||||
key={item.id}
|
key={item.id}
|
||||||
@@ -200,6 +200,7 @@ function HeaderContent() {
|
|||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
asChild
|
asChild
|
||||||
|
data-testid="consult-button"
|
||||||
>
|
>
|
||||||
<Link href="/contact">立即咨询</Link>
|
<Link href="/contact">立即咨询</Link>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -212,6 +213,7 @@ function HeaderContent() {
|
|||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
aria-controls="mobile-menu"
|
aria-controls="mobile-menu"
|
||||||
aria-label={isOpen ? '关闭菜单' : '打开菜单'}
|
aria-label={isOpen ? '关闭菜单' : '打开菜单'}
|
||||||
|
data-testid="mobile-menu-button"
|
||||||
style={{ minWidth: '44px', minHeight: '44px' }}
|
style={{ minWidth: '44px', minHeight: '44px' }}
|
||||||
>
|
>
|
||||||
{isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
|
{isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
|
||||||
@@ -244,6 +246,7 @@ function HeaderContent() {
|
|||||||
id="mobile-menu"
|
id="mobile-menu"
|
||||||
role="navigation"
|
role="navigation"
|
||||||
aria-label="移动端导航"
|
aria-label="移动端导航"
|
||||||
|
data-testid="mobile-navigation"
|
||||||
>
|
>
|
||||||
<nav className="container-wide py-6">
|
<nav className="container-wide py-6">
|
||||||
{navigationItems.map((item, index) => (
|
{navigationItems.map((item, index) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user