Files
novalon-website/e2e/uj-11-home-conversion.spec.ts
T
zhangxiang 5de01531bf fix(e2e): remove stale hero-product-visual assertions from uj-11
v15 removed the product mockup; assert hero-section visibility instead. 7/7 pass chromium.

docs: add impeccable AI-slop audit for Hero + FounderQuoteSection (18/20, no tells).
2026-09-01 11:07:45 +08:00

190 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect, type Page } from '@playwright/test';
/**
* UJ-11: 首页转化旅程(设计优化专项)
*
* 覆盖首页 Vibe Design 优化后的关键转化路径,作为封版验收依据:
* UJ-11a: 首屏说服链路 — Hero 产品视觉 + 单一 CTA + 数据条 → 信任层(可验证信号)→ 叙事区 → 转化 CTA
* UJ-11b: 信任验证旅程 — 数据来源标注 + 首批客户共创标签 → 联系转化
* UJ-11c: 移动端首屏转化旅程 — 390px 下 CTA 首屏可见、无横向滚动
*
* 关联设计优化计划:docs/plans/2026-08-18-vibe-design-optimization-plan.md
* 关联 critique.impeccable/critique/
*/
test.setTimeout(90000);
// ==================== 辅助函数 ====================
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);
}
}
/**
* 断言页面无横向滚动(scrollWidth <= clientWidth + 1px 容差)
*/
async function expectNoHorizontalOverflow(page: Page) {
const overflow = await page.evaluate(() => {
const doc = document.documentElement;
return { scrollWidth: doc.scrollWidth, clientWidth: doc.clientWidth };
});
expect(overflow.scrollWidth).toBeLessThanOrEqual(overflow.clientWidth + 1);
}
// ==================== UJ-11a: 首屏说服链路 ====================
test.describe('UJ-11a: 首屏说服链路(Hero → 信任 → 叙事 → CTA', () => {
test('@journey @critical 首页首屏产品视觉、单一 CTA、数据条渲染正常', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
// === L1 Hero:浅色工程网格 Hero 可见(v15 已移除产品 Mockup,改为声明先行 + 单一 CTA===
const heroSection = page.locator('[data-testid="hero-section"]').first();
await expect(heroSection).toBeVisible({ timeout: 15000 });
// === 单一主 CTA ===
const primaryCta = page.locator('[data-testid="hero-primary-cta"]').first();
await expect(primaryCta).toBeVisible();
await expect(primaryCta).toHaveAttribute('href', '/contact');
// 次级 CTA 降级为文字链接
const secondaryLink = page.locator('[data-testid="hero-secondary-link"]').first();
await expect(secondaryLink).toBeVisible();
// === 主标题可见 ===
const heroTitle = page.locator('h1').first();
await expect(heroTitle).toBeVisible();
// 无横向滚动
await expectNoHorizontalOverflow(page);
});
test('@journey @critical 首页信任层展示可验证信号与来源标注', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
// 滚动到信任层
const trustSection = page.locator('[data-testid="trust-section"]').first();
await trustSection.scrollIntoViewIfNeeded();
await expect(trustSection).toBeVisible({ timeout: 10000 });
const trustText = await trustSection.textContent();
// 可验证信任信号存在(私有化部署 / 本地化 / 全流程 / 共创)
expect(trustText).toContain('100%');
expect(trustText).toContain('成都');
expect(trustText).toContain('全流程');
expect(trustText).toContain('共创');
// 数据来源标注存在(零编造,可追溯)
expect(trustText).toContain('数据来源');
});
test('@journey @critical 首页叙事区按 01/02/03 章节呈现问题→方法→结果', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
const narrativeSection = page.locator('[data-testid="narrative-section"]').first();
await narrativeSection.scrollIntoViewIfNeeded();
await expect(narrativeSection).toBeVisible({ timeout: 10000 });
const narrativeText = await narrativeSection.textContent();
// 三幕章节编号存在
expect(narrativeText).toContain('01');
expect(narrativeText).toContain('02');
expect(narrativeText).toContain('03');
// 叙事主题存在
expect(narrativeText).toContain('诊断现状');
expect(narrativeText).toContain('设计路径');
expect(narrativeText).toContain('交付成果');
// 每章保留详情入口
const narrativeLinks = narrativeSection.locator('a');
expect(await narrativeLinks.count()).toBeGreaterThanOrEqual(3);
});
});
// ==================== UJ-11b: 信任验证旅程 ====================
test.describe('UJ-11b: 信任验证旅程(共创标签 → 转化)', () => {
test('@journey @critical 首页首批客户共创标签引导至联系转化', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
// 首批客户共创横幅存在(无虚构客户,如实标注)
const earlyAccessBanner = page.locator('[data-testid="early-access-banner"]').first();
await earlyAccessBanner.scrollIntoViewIfNeeded();
await expect(earlyAccessBanner).toBeVisible({ timeout: 10000 });
const bannerText = await earlyAccessBanner.textContent();
expect(bannerText).toContain('首批客户共创中');
// 引导至联系转化
const cta = earlyAccessBanner.locator('a[href="/contact"]').first();
await expect(cta).toBeVisible();
await expect(cta).toHaveAttribute('href', '/contact');
});
test('@journey @critical 空案例区呈现共创内容块而非裸空态', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
const bodyText = await page.locator('body').textContent();
// 无「暂无案例数据」裸空态
expect(bodyText).not.toContain('暂无案例数据');
// 出现「共创进行时」前瞻内容块
expect(bodyText).toContain('共创进行时');
// 共创块包含转化 CTA
expect(bodyText).toContain('成为首批共创客户');
});
});
// ==================== UJ-11c: 移动端首屏转化旅程 ====================
test.describe('UJ-11c: 移动端首屏转化旅程', () => {
test('@mobile @journey @critical 移动端 CTA 首屏可见且无横向滚动', async ({ page }) => {
// 模拟移动端视口
await page.setViewportSize({ width: 390, height: 844 });
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
// 无横向滚动
await expectNoHorizontalOverflow(page);
// CTA 首屏可达(在当前视口内可见)
const primaryCta = page.locator('[data-testid="hero-primary-cta"]').first();
await expect(primaryCta).toBeVisible({ timeout: 15000 });
// 首屏 Hero 区块可见(v15 已移除产品 Mockup)
const heroSection = page.locator('[data-testid="hero-section"]').first();
await expect(heroSection).toBeVisible();
});
test('@mobile @journey @critical 移动端信任层与叙事区单列堆叠无溢出', async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2500);
await closeCookieBanner(page);
// 信任层
const trustSection = page.locator('[data-testid="trust-section"]').first();
await trustSection.scrollIntoViewIfNeeded();
await expect(trustSection).toBeVisible();
const trustText = await trustSection.textContent();
expect(trustText).toContain('数据来源');
// 叙事区
const narrativeSection = page.locator('[data-testid="narrative-section"]').first();
await narrativeSection.scrollIntoViewIfNeeded();
await expect(narrativeSection).toBeVisible();
expect(await narrativeSection.textContent()).toContain('01');
// 全程无横向滚动
await expectNoHorizontalOverflow(page);
});
});