test: 新增User Journey和UAT测试用例覆盖dogfood测试流程
- 新增5个User Journey测试(UJ-014~UJ-018):页面标题验证、新闻筛选流程、品牌名一致性 - 新增19个UAT测试(UAT-053增强、UAT-130~142):标题无重复公司名、简体品牌名、结构化数据 - 新增Playwright验证测试用于修复效果确认
This commit is contained in:
@@ -0,0 +1,437 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('UAT: 页面加载与基础功能', () => {
|
||||
const corePages = [
|
||||
{ name: '首页', url: '/', titlePattern: /睿新致远/ },
|
||||
{ name: '产品列表', url: '/products', titlePattern: /产品/ },
|
||||
{ name: '服务列表', url: '/services', titlePattern: /服务/ },
|
||||
{ name: '解决方案列表', url: '/solutions', titlePattern: /解决方案/ },
|
||||
{ name: '关于我们', url: '/about', titlePattern: /关于/ },
|
||||
{ name: '联系我们', url: '/contact', titlePattern: /联系/ },
|
||||
{ name: '新闻列表', url: '/news', titlePattern: /新闻/ },
|
||||
{ name: '隐私政策', url: '/privacy', titlePattern: /隐私/ },
|
||||
{ name: '服务条款', url: '/terms', titlePattern: /条款/ },
|
||||
];
|
||||
|
||||
for (const pageInfo of corePages) {
|
||||
test(`UAT-001: ${pageInfo.name}页面正常加载`, async ({ page }) => {
|
||||
await page.goto(pageInfo.url);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveTitle(pageInfo.titlePattern);
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('UAT: 导航组件', () => {
|
||||
test('UAT-010: 顶部导航栏在滚动后样式变化', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const header = page.locator('header');
|
||||
await expect(header).toBeVisible();
|
||||
await page.evaluate(() => window.scrollTo(0, 500));
|
||||
await page.waitForTimeout(300);
|
||||
await expect(header).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-011: 产品Mega Dropdown菜单展开与关闭', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const productButton = page.locator('nav button:has-text("产品")');
|
||||
await productButton.click();
|
||||
await page.waitForTimeout(300);
|
||||
await expect(page.locator('text=财务·采购·销售·库存·生产')).toBeVisible();
|
||||
await page.keyboard.press('Escape');
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
test('UAT-012: 解决方案Mega Dropdown菜单展开与关闭', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const solutionButton = page.locator('nav button:has-text("解决方案")');
|
||||
await solutionButton.click();
|
||||
await page.waitForTimeout(300);
|
||||
await expect(page.locator('text=制造业').or(page.locator('text=零售业'))).toBeVisible();
|
||||
await page.keyboard.press('Escape');
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
test('UAT-013: Logo点击返回首页', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('a[aria-label="返回首页"]').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\//);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 产品页面', () => {
|
||||
test('UAT-020: 产品列表页显示所有产品', async ({ page }) => {
|
||||
await page.goto('/products');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const productCards = page.locator('a[href*="/products/"]');
|
||||
const count = await productCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(6);
|
||||
});
|
||||
|
||||
test('UAT-021: ERP产品详情页正常显示', async ({ page }) => {
|
||||
await page.goto('/products/erp');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
await expect(page.locator('text=ERP')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-022: CRM产品详情页正常显示', async ({ page }) => {
|
||||
await page.goto('/products/crm');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
await expect(page.locator('text=CRM')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-023: 产品详情页包含功能特性区域', async ({ page }) => {
|
||||
await page.goto('/products/erp');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const featuresSection = page.locator('h2, h3', { hasText: /功能|特性|核心/ });
|
||||
const count = await featuresSection.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 服务页面', () => {
|
||||
const serviceIds = ['software', 'data', 'consulting', 'solutions'];
|
||||
|
||||
test('UAT-030: 服务列表页显示所有服务', async ({ page }) => {
|
||||
await page.goto('/services');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const serviceCards = page.locator('a[href*="/services/"]');
|
||||
const count = await serviceCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
for (const serviceId of serviceIds) {
|
||||
test(`UAT-031: 服务详情页 ${serviceId} 正常显示`, async ({ page }) => {
|
||||
await page.goto(`/services/${serviceId}`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('UAT: 解决方案页面', () => {
|
||||
const solutionIds = ['manufacturing', 'retail', 'education', 'healthcare'];
|
||||
|
||||
test('UAT-040: 解决方案列表页显示所有方案', async ({ page }) => {
|
||||
await page.goto('/solutions');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const solutionCards = page.locator('a[href*="/solutions/"]');
|
||||
const count = await solutionCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
for (const solutionId of solutionIds) {
|
||||
test(`UAT-041: 解决方案详情页 ${solutionId} 正常显示`, async ({ page }) => {
|
||||
await page.goto(`/solutions/${solutionId}`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('UAT: 新闻页面', () => {
|
||||
test('UAT-050: 新闻列表页显示新闻条目', async ({ page }) => {
|
||||
await page.goto('/news');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const newsCards = page.locator('a[href*="/news/"]');
|
||||
const count = await newsCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test('UAT-051: 新闻详情页 company-founded 正常显示', async ({ page }) => {
|
||||
await page.goto('/news/company-founded');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1', { hasText: '正式成立' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-052: 新闻详情页 digital-transformation-solution 正常显示', async ({ page }) => {
|
||||
await page.goto('/news/digital-transformation-solution');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1', { hasText: '数字化转型' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-053: 新闻分类筛选功能', async ({ page }) => {
|
||||
await page.goto('/news');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const allNews = page.locator('a[href*="/news/"]');
|
||||
const initialCount = await allNews.count();
|
||||
expect(initialCount).toBeGreaterThanOrEqual(2);
|
||||
|
||||
const companyNewsBtn = page.locator('button:has-text("公司新闻")');
|
||||
await companyNewsBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const companyFiltered = await allNews.count();
|
||||
expect(companyFiltered).toBe(1);
|
||||
|
||||
const productNewsBtn = page.locator('button:has-text("产品发布")');
|
||||
await productNewsBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const productFiltered = await allNews.count();
|
||||
expect(productFiltered).toBe(1);
|
||||
|
||||
const allBtn = page.locator('button:has-text("全部")');
|
||||
await allBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const restoredCount = await allNews.count();
|
||||
expect(restoredCount).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test('UAT-054: 新闻搜索功能', async ({ page }) => {
|
||||
await page.goto('/news');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const searchInput = page.locator('input[aria-label="搜索新闻"]');
|
||||
if (await searchInput.isVisible()) {
|
||||
await searchInput.fill('数字化转型');
|
||||
await page.waitForTimeout(500);
|
||||
const visibleNews = page.locator('a[href*="/news/"]');
|
||||
const count = await visibleNews.count();
|
||||
expect(count).toBeGreaterThanOrEqual(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 联系页面', () => {
|
||||
test('UAT-060: 联系页面显示联系信息', async ({ page }) => {
|
||||
await page.goto('/contact');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=contact@novalon.cn')).toBeVisible();
|
||||
await expect(page.locator('text=成都市龙泉驿区')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-061: 联系表单所有必填字段标记正确', async ({ page }) => {
|
||||
await page.goto('/contact');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const requiredFields = page.locator('input[required], textarea[required]');
|
||||
const count = await requiredFields.count();
|
||||
expect(count).toBe(5);
|
||||
});
|
||||
|
||||
test('UAT-062: 联系表单提交按钮状态', async ({ page }) => {
|
||||
await page.goto('/contact');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const submitButton = page.locator('[data-testid="submit-button"]');
|
||||
await expect(submitButton).toBeVisible();
|
||||
await expect(submitButton).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 关于页面', () => {
|
||||
test('UAT-070: 关于页面显示公司信息', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-071: 关于页面包含团队信息', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const teamSection = page.locator('h2, h3', { hasText: /团队|成员/ });
|
||||
const count = await teamSection.count();
|
||||
if (count > 0) {
|
||||
expect(count).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: Cookie同意机制', () => {
|
||||
test('UAT-080: Cookie横幅首次访问时显示', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=我们使用 Cookie')).toBeVisible();
|
||||
await expect(page.locator('button:has-text("管理偏好")')).toBeVisible();
|
||||
await expect(page.locator('button:has-text("仅必要")')).toBeVisible();
|
||||
await expect(page.locator('button:has-text("接受所有")')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-081: Cookie偏好设置弹窗功能', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('button:has-text("管理偏好")').click();
|
||||
await page.waitForTimeout(300);
|
||||
await expect(page.locator('text=Cookie 偏好设置')).toBeVisible();
|
||||
await expect(page.locator('text=必要 Cookie')).toBeVisible();
|
||||
await expect(page.locator('text=分析 Cookie')).toBeVisible();
|
||||
await expect(page.locator('text=营销 Cookie')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-082: 必要Cookie不可取消', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('button:has-text("管理偏好")').click();
|
||||
await page.waitForTimeout(300);
|
||||
const necessaryCheckbox = page.locator('input[type="checkbox"]').first();
|
||||
expect(await necessaryCheckbox.isChecked()).toBe(true);
|
||||
expect(await necessaryCheckbox.isDisabled()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 404错误页面', () => {
|
||||
test('UAT-090: 不存在的页面显示404', async ({ page }) => {
|
||||
await page.goto('/this-page-does-not-exist');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=404')).toBeVisible();
|
||||
await expect(page.locator('text=页面未找到')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-091: 404页面提供导航建议', async ({ page }) => {
|
||||
await page.goto('/this-page-does-not-exist');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=您可能在寻找')).toBeVisible();
|
||||
await expect(page.locator('a:has-text("关于我们")')).toBeVisible();
|
||||
await expect(page.locator('a:has-text("产品")')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-092: 404页面返回首页功能', async ({ page }) => {
|
||||
await page.goto('/this-page-does-not-exist');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('a:has-text("返回首页")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\//);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 页脚组件', () => {
|
||||
test('UAT-100: 页脚显示公司版权信息', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=四川睿新致远科技有限公司')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-101: 页脚显示备案信息', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=蜀ICP备')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UAT-102: 页脚快速导航链接可用', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const footerNavLinks = page.locator('footer a');
|
||||
const count = await footerNavLinks.count();
|
||||
expect(count).toBeGreaterThanOrEqual(5);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 可访问性基础', () => {
|
||||
test('UAT-110: 页面有跳转到主内容的链接', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const skipLink = page.locator('a:has-text("跳转到主内容")');
|
||||
await expect(skipLink).toBeAttached();
|
||||
});
|
||||
|
||||
test('UAT-111: 导航区域有正确的ARIA标签', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const mainNav = page.locator('nav[aria-label="主导航"]');
|
||||
await expect(mainNav).toBeAttached();
|
||||
});
|
||||
|
||||
test('UAT-112: 图片有alt文本', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const images = page.locator('img');
|
||||
const count = await images.count();
|
||||
for (let i = 0; i < count; i++) {
|
||||
const alt = await images.nth(i).getAttribute('alt');
|
||||
expect(alt).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 响应式设计', () => {
|
||||
test('UAT-120: 移动端导航菜单可打开', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const menuButton = page.locator('button[aria-label="打开菜单"]').or(
|
||||
page.locator('button[aria-label="关闭菜单"]')
|
||||
);
|
||||
if (await menuButton.isVisible()) {
|
||||
await menuButton.click();
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
});
|
||||
|
||||
test('UAT-121: 桌面端导航菜单直接显示', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1280, height: 720 });
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const desktopNav = page.locator('nav[aria-label="主导航"]');
|
||||
await expect(desktopNav).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('UAT: 页面标题与SEO', () => {
|
||||
const titlePages = [
|
||||
{ name: '产品列表', url: '/products' },
|
||||
{ name: '服务列表', url: '/services' },
|
||||
{ name: '解决方案', url: '/solutions' },
|
||||
{ name: '关于我们', url: '/about' },
|
||||
{ name: '联系我们', url: '/contact' },
|
||||
{ name: '新闻动态', url: '/news' },
|
||||
{ name: '隐私政策', url: '/privacy' },
|
||||
{ name: '服务条款', url: '/terms' },
|
||||
];
|
||||
|
||||
for (const pageInfo of titlePages) {
|
||||
test(`UAT-130: ${pageInfo.name}页面标题无重复公司名`, async ({ page }) => {
|
||||
await page.goto(pageInfo.url);
|
||||
await page.waitForLoadState('networkidle');
|
||||
const title = await page.title();
|
||||
const companyNameCount = (title.match(/四川睿新致远科技有限公司/g) || []).length;
|
||||
expect(companyNameCount).toBeLessThanOrEqual(1);
|
||||
});
|
||||
}
|
||||
|
||||
for (const pageInfo of titlePages) {
|
||||
test(`UAT-131: ${pageInfo.name}页面标题使用简体品牌名`, async ({ page }) => {
|
||||
await page.goto(pageInfo.url);
|
||||
await page.waitForLoadState('networkidle');
|
||||
const title = await page.title();
|
||||
expect(title).not.toContain('睿新致遠');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('UAT: 品牌名一致性', () => {
|
||||
test('UAT-140: 视觉展示使用繁体品牌名(配合青柳隷書字体)', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const brandElement = page.locator('.font-brand').first();
|
||||
if (await brandElement.isVisible()) {
|
||||
const text = await brandElement.textContent();
|
||||
expect(text).toContain('睿新致遠');
|
||||
}
|
||||
});
|
||||
|
||||
test('UAT-141: SEO元数据使用简体品牌名', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const metaDescription = await page.locator('meta[name="description"]').getAttribute('content');
|
||||
if (metaDescription) {
|
||||
expect(metaDescription).not.toContain('睿新致遠');
|
||||
}
|
||||
});
|
||||
|
||||
test('UAT-142: 结构化数据使用完整公司名', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const ldJsonScripts = page.locator('script[type="application/ld+json"]');
|
||||
const count = await ldJsonScripts.count();
|
||||
if (count > 0) {
|
||||
const content = await ldJsonScripts.first().textContent();
|
||||
const schema = JSON.parse(content || '{}');
|
||||
expect(schema.name).toBe('四川睿新致远科技有限公司');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,407 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('用户旅程:潜在客户了解产品并咨询', () => {
|
||||
test('UJ-001: 首页浏览 → 产品探索 → 咨询联系', async ({ page }) => {
|
||||
await test.step('步骤1: 访问首页', async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveTitle(/睿新致远/);
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤2: 查看产品矩阵区域', async () => {
|
||||
await page.locator('h2', { hasText: '产品矩阵' }).scrollIntoViewIfNeeded();
|
||||
await expect(page.locator('h2', { hasText: '产品矩阵' })).toBeVisible();
|
||||
const productCards = page.locator('a', { hasText: '了解详情' });
|
||||
await expect(productCards.first()).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤3: 点击产品卡片进入详情页', async () => {
|
||||
await page.locator('a', { hasText: '睿新ERP管理系统' }).first().click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/products\//);
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤4: 点击"立即咨询"按钮', async () => {
|
||||
const consultButton = page.locator('a', { hasText: '立即咨询' }).first();
|
||||
await expect(consultButton).toBeVisible();
|
||||
await consultButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/contact/);
|
||||
});
|
||||
|
||||
await test.step('步骤5: 填写联系表单', async () => {
|
||||
await page.fill('[data-testid="name-input"]', '张三');
|
||||
await page.fill('[data-testid="phone-input"]', '13800138000');
|
||||
await page.fill('[data-testid="email-input"]', 'zhangsan@example.com');
|
||||
await page.fill('[data-testid="subject-input"]', 'ERP产品咨询');
|
||||
await page.fill('[data-testid="message-input"]', '我想了解贵公司的ERP产品,请提供更多详情和报价信息。');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:了解公司服务与解决方案', () => {
|
||||
test('UJ-002: 服务浏览 → 方案探索 → 了解公司', async ({ page }) => {
|
||||
await test.step('步骤1: 从首页导航到服务页', async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('a', { hasText: '服务' }).first().click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/services/);
|
||||
});
|
||||
|
||||
await test.step('步骤2: 查看服务列表', async () => {
|
||||
await expect(page.locator('h1', { hasText: '服务' })).toBeVisible();
|
||||
const serviceCards = page.locator('a[href*="/services/"]');
|
||||
const count = await serviceCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
await test.step('步骤3: 进入服务详情页', async () => {
|
||||
await page.locator('a[href="/services/software"]').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/services\/software/);
|
||||
await expect(page.locator('h1', { hasText: '软件开发' })).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤4: 导航到解决方案页', async () => {
|
||||
await page.locator('a', { hasText: '解决方案' }).first().click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/solutions/);
|
||||
});
|
||||
|
||||
await test.step('步骤5: 进入行业方案详情', async () => {
|
||||
const solutionLink = page.locator('a[href*="/solutions/"]').first();
|
||||
await expect(solutionLink).toBeVisible();
|
||||
await solutionLink.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/solutions\//);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:阅读新闻了解公司动态', () => {
|
||||
test('UJ-003: 新闻列表 → 新闻详情 → 返回列表', async ({ page }) => {
|
||||
await test.step('步骤1: 访问新闻列表页', async () => {
|
||||
await page.goto('/news');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1', { hasText: '新闻动态' })).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤2: 查看新闻列表内容', async () => {
|
||||
const newsCards = page.locator('a[href*="/news/"]');
|
||||
const count = await newsCards.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
await test.step('步骤3: 点击进入新闻详情', async () => {
|
||||
await page.locator('a[href="/news/company-founded"]').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/news\/company-founded/);
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤4: 返回新闻列表', async () => {
|
||||
const backButton = page.locator('a', { hasText: '返回新闻列表' }).or(
|
||||
page.locator('button', { hasText: '返回新闻列表' })
|
||||
).first();
|
||||
if (await backButton.isVisible()) {
|
||||
await backButton.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/news/);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:导航菜单探索全站', () => {
|
||||
test('UJ-004: 通过导航菜单访问所有主要页面', async ({ page }) => {
|
||||
const pages = [
|
||||
{ label: '服务', url: /\/services/ },
|
||||
{ label: '关于我们', url: /\/about/ },
|
||||
{ label: '联系我们', url: /\/contact/ },
|
||||
];
|
||||
|
||||
for (const pageInfo of pages) {
|
||||
await test.step(`导航到${pageInfo.label}页`, async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const navLink = page.locator(`nav a:has-text("${pageInfo.label}")`).first();
|
||||
await navLink.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(pageInfo.url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('UJ-005: 通过Mega Dropdown菜单访问产品详情', async ({ page }) => {
|
||||
await test.step('步骤1: 打开产品下拉菜单', async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const productButton = page.locator('nav button:has-text("产品")');
|
||||
await productButton.click();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
await test.step('步骤2: 点击下拉菜单中的产品链接', async () => {
|
||||
const erpLink = page.locator('nav a:has-text("ERP 管理系统")').first();
|
||||
await expect(erpLink).toBeVisible();
|
||||
await erpLink.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\/products\/erp/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:Cookie同意与隐私', () => {
|
||||
test('UJ-006: Cookie同意横幅交互', async ({ page }) => {
|
||||
await test.step('步骤1: 首次访问显示Cookie横幅', async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const cookieBanner = page.locator('text=我们使用 Cookie');
|
||||
await expect(cookieBanner).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤2: 点击"管理偏好"打开设置', async () => {
|
||||
const manageButton = page.locator('button:has-text("管理偏好")');
|
||||
await manageButton.click();
|
||||
await page.waitForTimeout(300);
|
||||
await expect(page.locator('h3:has-text("Cookie 偏好设置")')).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤3: 验证必要Cookie默认勾选且禁用', async () => {
|
||||
const necessaryCheckbox = page.locator('input[type="checkbox"]').first();
|
||||
expect(await necessaryCheckbox.isChecked()).toBe(true);
|
||||
expect(await necessaryCheckbox.isDisabled()).toBe(true);
|
||||
});
|
||||
|
||||
await test.step('步骤4: 保存偏好后横幅消失', async () => {
|
||||
const saveButton = page.locator('button:has-text("保存偏好")');
|
||||
await saveButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
const cookieBanner = page.locator('text=我们使用 Cookie');
|
||||
await expect(cookieBanner).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test('UJ-007: 点击"仅必要"接受必要Cookie', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const necessaryButton = page.locator('button:has-text("仅必要")');
|
||||
await necessaryButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
const cookieBanner = page.locator('text=我们使用 Cookie');
|
||||
await expect(cookieBanner).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('UJ-008: 点击"接受所有"接受全部Cookie', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const acceptAllButton = page.locator('button:has-text("接受所有")');
|
||||
await acceptAllButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
const cookieBanner = page.locator('text=我们使用 Cookie');
|
||||
await expect(cookieBanner).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:联系表单验证', () => {
|
||||
test('UJ-009: 联系表单字段验证', async ({ page }) => {
|
||||
await page.goto('/contact');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await test.step('步骤1: 空表单提交显示验证错误', async () => {
|
||||
await page.click('[data-testid="submit-button"]');
|
||||
await page.waitForTimeout(500);
|
||||
const errorMessages = page.locator('[data-testid="name-error"], .text-destructive');
|
||||
const count = await errorMessages.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
await test.step('步骤2: 无效手机号验证', async () => {
|
||||
await page.fill('[data-testid="phone-input"]', '12345678901');
|
||||
await page.locator('[data-testid="phone-input"]').blur();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
await test.step('步骤3: 无效邮箱验证', async () => {
|
||||
await page.fill('[data-testid="email-input"]', 'invalid-email');
|
||||
await page.locator('[data-testid="email-input"]').blur();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
await test.step('步骤4: 填写正确信息后可提交', async () => {
|
||||
await page.fill('[data-testid="name-input"]', '测试用户');
|
||||
await page.fill('[data-testid="phone-input"]', '13800138000');
|
||||
await page.fill('[data-testid="email-input"]', 'test@example.com');
|
||||
await page.fill('[data-testid="subject-input"]', '产品咨询');
|
||||
await page.fill('[data-testid="message-input"]', '我想了解贵公司的产品详情,请提供更多信息。');
|
||||
await expect(page.locator('[data-testid="submit-button"]')).toBeEnabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:404页面与错误处理', () => {
|
||||
test('UJ-010: 访问不存在的页面显示404', async ({ page }) => {
|
||||
await page.goto('/nonexistent-page');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('text=404')).toBeVisible();
|
||||
await expect(page.locator('text=页面未找到')).toBeVisible();
|
||||
await expect(page.locator('a:has-text("返回首页")')).toBeVisible();
|
||||
});
|
||||
|
||||
test('UJ-011: 404页面导航功能正常', async ({ page }) => {
|
||||
await page.goto('/nonexistent-page');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator('a:has-text("返回首页")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\//);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:页脚导航', () => {
|
||||
test('UJ-012: 通过页脚链接导航到各页面', async ({ page }) => {
|
||||
const footerLinks = [
|
||||
{ text: '隐私政策', url: /\/privacy/ },
|
||||
{ text: '服务条款', url: /\/terms/ },
|
||||
];
|
||||
|
||||
for (const link of footerLinks) {
|
||||
await test.step(`点击页脚"${link.text}"链接`, async () => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.locator(`footer a:has-text("${link.text}")`).first().click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(link.url);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:面包屑导航', () => {
|
||||
test('UJ-013: 产品详情页面包屑导航', async ({ page }) => {
|
||||
await page.goto('/products/erp');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await test.step('步骤1: 面包屑显示正确路径', async () => {
|
||||
const breadcrumb = page.locator('nav[aria-label="breadcrumb"]');
|
||||
await expect(breadcrumb).toBeVisible();
|
||||
await expect(breadcrumb.locator('text=返回首页')).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤2: 点击面包屑返回首页', async () => {
|
||||
await page.locator('nav[aria-label="breadcrumb"] a:has-text("返回首页")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).toHaveURL(/\//);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:页面标题与SEO一致性', () => {
|
||||
const pagesWithTitle = [
|
||||
{ name: '产品列表', url: '/products', expectedTitle: '产品 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '服务列表', url: '/services', expectedTitle: '服务 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '解决方案', url: '/solutions', expectedTitle: '解决方案 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '关于我们', url: '/about', expectedTitle: '关于我们 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '联系我们', url: '/contact', expectedTitle: '联系我们 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '新闻动态', url: '/news', expectedTitle: '新闻动态 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '隐私政策', url: '/privacy', expectedTitle: '隐私政策 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
{ name: '服务条款', url: '/terms', expectedTitle: '服务条款 - 睿新致远 | 四川睿新致远科技有限公司' },
|
||||
];
|
||||
|
||||
test('UJ-014: 所有页面标题无重复公司名', async ({ page }) => {
|
||||
for (const pageInfo of pagesWithTitle) {
|
||||
await page.goto(pageInfo.url);
|
||||
await page.waitForLoadState('networkidle');
|
||||
const title = await page.title();
|
||||
const companyNameCount = (title.match(/四川睿新致远科技有限公司/g) || []).length;
|
||||
expect(companyNameCount, `${pageInfo.name}页面标题中公司名出现${companyNameCount}次,应不超过1次`).toBeLessThanOrEqual(1);
|
||||
}
|
||||
});
|
||||
|
||||
test('UJ-015: 页面标题使用简体品牌名(非繁体)', async ({ page }) => {
|
||||
for (const pageInfo of pagesWithTitle) {
|
||||
await page.goto(pageInfo.url);
|
||||
await page.waitForLoadState('networkidle');
|
||||
const title = await page.title();
|
||||
expect(title, `${pageInfo.name}页面标题包含繁体字"遠"`).not.toContain('睿新致遠');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:新闻筛选完整流程', () => {
|
||||
test('UJ-016: 新闻分类筛选→查看详情→返回列表', async ({ page }) => {
|
||||
await test.step('步骤1: 访问新闻列表页', async () => {
|
||||
await page.goto('/news');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('h1', { hasText: '新闻动态' })).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('步骤2: 验证初始显示全部新闻', async () => {
|
||||
const allNews = page.locator('a[href*="/news/"]');
|
||||
const count = await allNews.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
await test.step('步骤3: 点击"公司新闻"筛选', async () => {
|
||||
const companyNewsBtn = page.locator('button:has-text("公司新闻")');
|
||||
await companyNewsBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const filteredNews = page.locator('a[href*="/news/"]');
|
||||
const count = await filteredNews.count();
|
||||
expect(count).toBe(1);
|
||||
const text = await filteredNews.first().textContent();
|
||||
expect(text).toContain('公司新闻');
|
||||
});
|
||||
|
||||
await test.step('步骤4: 切换到"产品发布"筛选', async () => {
|
||||
const productNewsBtn = page.locator('button:has-text("产品发布")');
|
||||
await productNewsBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const filteredNews = page.locator('a[href*="/news/"]');
|
||||
const count = await filteredNews.count();
|
||||
expect(count).toBe(1);
|
||||
const text = await filteredNews.first().textContent();
|
||||
expect(text).toContain('产品发布');
|
||||
});
|
||||
|
||||
await test.step('步骤5: 点击"全部"恢复全部新闻', async () => {
|
||||
const allBtn = page.locator('button:has-text("全部")');
|
||||
await allBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const allNews = page.locator('a[href*="/news/"]');
|
||||
const count = await allNews.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
await test.step('步骤6: 搜索功能筛选', async () => {
|
||||
const searchInput = page.locator('input[aria-label="搜索新闻"]');
|
||||
await searchInput.fill('数字化转型');
|
||||
await page.waitForTimeout(500);
|
||||
const filteredNews = page.locator('a[href*="/news/"]');
|
||||
const count = await filteredNews.count();
|
||||
expect(count).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户旅程:品牌视觉一致性', () => {
|
||||
test('UJ-017: Hero区域品牌标题使用青柳隷書字体展示繁体品牌名', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const brandElement = page.locator('.font-brand').first();
|
||||
if (await brandElement.isVisible()) {
|
||||
const text = await brandElement.textContent();
|
||||
expect(text).toContain('睿新致遠');
|
||||
}
|
||||
});
|
||||
|
||||
test('UJ-018: 页面元数据使用简体品牌名', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const title = await page.title();
|
||||
expect(title).toContain('睿新致远');
|
||||
expect(title).not.toContain('睿新致遠');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user