import { test, expect, type Page } from '@playwright/test'; /** * UJ-08: 服务探索者旅程 * * 覆盖范围: * 服务列表 → 服务详情 → 联系表单 */ test.setTimeout(90000); // ==================== 辅助函数 ==================== /** * 关闭 Cookie 同意横幅(如果存在) */ async function closeCookieBanner(page: Page) { const acceptAllButton = page.locator('button:has-text("接受所有")').first(); if (await acceptAllButton.count() > 0 && await acceptAllButton.isVisible()) { await acceptAllButton.click(); await page.waitForTimeout(500); } } /** * 从桌面主导航的"服务"链接直接导航到服务页面 * 注意:服务导航项是直接链接,无下拉菜单(与产品/解决方案不同) */ async function navigateFromServiceNav(page: Page) { const desktopNav = page.locator('[data-testid="desktop-navigation"]').first(); const serviceLink = desktopNav.locator('a:has-text("服务")').first(); await expect(serviceLink).toBeVisible({ timeout: 5000 }); await serviceLink.click(); } // ==================== UJ-08: 服务探索者旅程 ==================== test.describe('UJ-08: 服务探索者旅程(服务列表 → 服务详情 → 联系表单)', () => { test('@journey @regression 访客从服务列表浏览到详情页并填写联系表单', async ({ page }) => { // === Step 1: 访问首页,确认 Hero 区域可见 === console.log('UJ-08: 访问首页'); await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 }); await page.waitForTimeout(2500); await closeCookieBanner(page); // 验证 Hero 区域可见 const heroTitle = page.locator('h1').first(); await expect(heroTitle).toBeVisible({ timeout: 15000 }); const titleText = await heroTitle.textContent(); expect(titleText).toBeTruthy(); expect(titleText!.length).toBeGreaterThan(0); console.log('UJ-08: 首页 Hero 区域可见'); // === Step 2: 通过桌面主导航的"服务"链接,导航到服务列表页 === console.log('UJ-08: 从导航进入服务列表页'); await navigateFromServiceNav(page); // 等待导航到服务列表页 await page.waitForURL(/\/services/, { timeout: 10000 }); await expect(page).toHaveURL(/\/services/); await page.waitForTimeout(2000); console.log('UJ-08: 已导航到服务列表页'); // === Step 3: 验证服务列表页加载成功 === // 服务列表页的 h1 可能为标语而非"服务"文字,验证 URL 和页面标题 const pageTitle = await page.title(); expect(pageTitle).toContain('服务'); console.log('UJ-08: 服务列表页页面标题:', pageTitle); // 验证服务卡片/链接存在 const serviceLinks = page.locator('a[href*="/services/"]:not([href$="/services"])'); const linkCount = await serviceLinks.count(); expect(linkCount).toBeGreaterThan(0); console.log('UJ-08: 找到服务链接数量:', linkCount); // === Step 4: 点击第一个服务链接进入详情页 === console.log('UJ-08: 点击第一个服务链接'); const firstServiceLink = serviceLinks.first(); const serviceHref = await firstServiceLink.getAttribute('href'); console.log('UJ-08: 服务链接地址:', serviceHref); await firstServiceLink.click(); await page.waitForURL(/\/services\/.+/, { timeout: 10000 }); await expect(page).toHaveURL(/\/services\/.+/); await page.waitForTimeout(2000); console.log('UJ-08: 已导航到服务详情页'); // === Step 5: 验证服务详情页加载成功 === // L1 Hero: 标题可见且有内容 const detailTitle = page.locator('h1').first(); await expect(detailTitle).toBeVisible({ timeout: 10000 }); const detailTitleText = await detailTitle.textContent(); expect(detailTitleText).toBeTruthy(); expect(detailTitleText!.length).toBeGreaterThan(0); console.log('UJ-08: 服务详情页标题:', detailTitleText); // 验证 main 内容长度 > 200 字符 const mainContent = page.locator('main').first(); await expect(mainContent).toBeVisible(); const mainText = await mainContent.textContent(); expect(mainText!.length).toBeGreaterThan(200); console.log('UJ-08: 服务详情页 main 内容长度:', mainText!.length); // === Step 6: 验证服务详情页包含四层叙事结构中的关键元素 === // L2 Value: 核心价值/服务内容/实施流程区域 // 服务详情页使用的 L2 区域标题为"解决什么问题","核心能力","服务流程" const valueIndicators = ['核心价值', '服务内容', '实施流程', 'Value Proposition', '解决什么问题', '核心能力', '服务流程']; let hasValueSection = false; for (const indicator of valueIndicators) { if (mainText!.includes(indicator)) { hasValueSection = true; console.log('UJ-08: 找到核心价值区域:', indicator); break; } } expect(hasValueSection).toBe(true); // L3 Trust: 信任证明(客户案例或资质认证) const trustIndicators = ['客户案例', '资质认证', '可衡量的成果', '成功案例', '真实案例']; let hasTrustSection = false; for (const indicator of trustIndicators) { if (mainText!.includes(indicator)) { hasTrustSection = true; console.log('UJ-08: 找到信任证明区域:', indicator); break; } } // 服务详情页的信任区域可能为"查看案例"链接而非文本块,软验证 if (!hasTrustSection) { const caseLink = page.locator('a:has-text("查看案例")').first(); const hasCaseLink = await caseLink.isVisible().catch(() => false); if (hasCaseLink) { hasTrustSection = true; console.log('UJ-08: 找到"查看案例"链接作为信任证明'); } } expect(hasTrustSection).toBe(true); // L4 CTA: 验证 CTA 区域存在(链接到联系页面) const ctaLink = page.locator('a[href="/contact"]').first(); await expect(ctaLink).toBeVisible(); console.log('UJ-08: CTA 链接可见'); // === Step 7: 从服务详情页导航到联系页面 === console.log('UJ-08: 导航到联系页面'); await page.goto('/contact', { waitUntil: 'domcontentloaded', timeout: 30000 }); await page.waitForTimeout(2500); // 验证联系页面加载成功 const contactTitle = page.locator('h1').first(); await expect(contactTitle).toBeVisible({ timeout: 10000 }); const contactTitleText = await contactTitle.textContent(); expect(contactTitleText).toBeTruthy(); expect(contactTitleText!.length).toBeGreaterThan(0); console.log('UJ-08: 联系页面标题:', contactTitleText); // === Step 8: 填写联系表单 === // 验证表单字段可见 const nameInput = page.locator('[data-testid="name-input"]').first(); await expect(nameInput).toBeVisible({ timeout: 5000 }); console.log('UJ-08: 表单字段可见'); // 填写表单字段 await page.locator('[data-testid="name-input"]').fill('张经理'); await page.locator('[data-testid="phone-input"]').fill('13812345678'); await page.locator('[data-testid="email-input"]').fill('zhang@example.com'); await page.locator('[data-testid="subject-input"]').fill('服务咨询 - 数字化转型咨询'); await page.locator('[data-testid="message-input"]').fill('您好,我在浏览了贵司的数字化转型服务后非常感兴趣,希望进一步了解服务内容和实施细节,请安排专人联系。'); // === Step 9: 验证表单字段可交互 === // 验证填写内容已正确填入 const filledName = await page.locator('[data-testid="name-input"]').inputValue(); expect(filledName).toBe('张经理'); const filledPhone = await page.locator('[data-testid="phone-input"]').inputValue(); expect(filledPhone).toBe('13812345678'); const filledEmail = await page.locator('[data-testid="email-input"]').inputValue(); expect(filledEmail).toBe('zhang@example.com'); const filledSubject = await page.locator('[data-testid="subject-input"]').inputValue(); expect(filledSubject).toBe('服务咨询 - 数字化转型咨询'); const filledMessage = await page.locator('[data-testid="message-input"]').inputValue(); expect(filledMessage).toBe('您好,我在浏览了贵司的数字化转型服务后非常感兴趣,希望进一步了解服务内容和实施细节,请安排专人联系。'); console.log('UJ-08: 表单字段已正确填写'); // === Step 10: 验证联系页面存在 CTA 提交按钮 === const submitButton = page.locator('[data-testid="submit-button"]').first(); await expect(submitButton).toBeVisible({ timeout: 5000 }); await submitButton.scrollIntoViewIfNeeded(); // 验证提交按钮可点击 await expect(submitButton).toBeEnabled({ timeout: 3000 }); const submitButtonText = await submitButton.textContent(); expect(submitButtonText).toBeTruthy(); console.log('UJ-08: 提交按钮可见且可点击:', submitButtonText); console.log('UJ-08: 服务探索者旅程测试完成'); }); });