import { describe, it, expect, jest } from '@jest/globals'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import HomeContentV15 from './home-content-v15'; jest.mock('framer-motion', () => ({ motion: { div: ({ children, initial, animate, className, style, ...props }: any) => (
{children}
), h1: ({ children, className, ...props }: any) => (

{children}

), p: ({ children, className, ...props }: any) => (

{children}

), span: ({ children, className, ...props }: any) => ( {children} ), a: ({ children, href, className, ...props }: any) => ( {children} ), }, useInView: jest.fn(() => true), AnimatePresence: ({ children }: any) => <>{children}, })); jest.mock('next/image', () => ({ __esModule: true, default: ({ src, alt, className }: any) => ( // eslint-disable-next-line @next/next/no-img-element {alt} ), })); jest.mock('@/components/ui/scroll-reveal', () => ({ ScrollReveal: ({ children, className }: any) => (
{children}
), StaggerReveal: ({ children, className }: any) => (
{children}
), })); jest.mock('@/components/ui/badge', () => ({ Badge: ({ children, className }: any) => ( {children} ), })); jest.mock('lucide-react', () => { const mockIcon = (name: string) => { const Icon = (props: any) => ; Icon.displayName = name; return Icon; }; return { ArrowRight: mockIcon('arrow-right'), ArrowUpRight: mockIcon('arrow-up-right'), ArrowDownRight: mockIcon('arrow-down-right'), Lightbulb: mockIcon('lightbulb'), Database: mockIcon('database'), Layers: mockIcon('layers'), Code: mockIcon('code'), Puzzle: mockIcon('puzzle'), Server: mockIcon('server'), Quote: mockIcon('quote'), Newspaper: mockIcon('newspaper'), Calendar: mockIcon('calendar'), LayoutDashboard: mockIcon('layout-dashboard'), BarChart3: mockIcon('bar-chart3'), Package: mockIcon('package'), Users: mockIcon('users'), Settings: mockIcon('settings'), Search: mockIcon('search'), Bell: mockIcon('bell'), TrendingUp: mockIcon('trending-up'), AlertCircle: mockIcon('alert-circle'), }; }); describe('HomeContentV15 - 浅色 Hero(暗黑模式 token 友好)', () => { it('does not repeat the brand logo inside the hero (dedup with header)', () => { render(); const hero = screen.getByTestId('hero-section'); expect(hero).toBeInTheDocument(); // hero 内不应再有 Logo(导航栏已展示,避免重复);slogan badge 保留 expect(hero.querySelector('img')).toBeNull(); }); it('mounts the brand-red dynamic particle layer (continuous drift loop)', () => { render(); const hero = screen.getByTestId('hero-section'); const particles = screen.getByTestId('hero-particle-field'); expect(particles.tagName).toBe('CANVAS'); expect(particles).toHaveAttribute('aria-hidden', 'true'); expect(hero.contains(particles)).toBe(true); }); it('keeps a single primary CTA and demotes the secondary action to a text link', () => { render(); expect(screen.getByTestId('hero-primary-cta')).toBeInTheDocument(); expect(screen.getByTestId('hero-primary-cta')).toHaveAttribute('href', '/contact'); expect(screen.getByTestId('hero-secondary-link')).toBeInTheDocument(); }); it('keeps hero declaration-first: stats sink out of hero into the results band', () => { render(); const hero = screen.getByTestId('hero-section'); // 声明先行:hero 内不再内联数据条(一屏只负责一句话声明 + 一个行动) expect(hero.querySelector('[data-testid="hero-stats"]')).toBeNull(); // 数据下沉为独立成果带,仍渲染(Glance 层滚动触发) expect(screen.getByTestId('hero-stats')).toBeInTheDocument(); }); }); describe('HomeContentV15 - 信任层与章节式叙事', () => { it('renders verifiable trust signals with a source annotation', () => { render(); expect(screen.getByTestId('trust-section')).toBeInTheDocument(); expect(screen.getByText('100%')).toBeInTheDocument(); expect(screen.getByText('成都')).toBeInTheDocument(); // 可验证来源标注存在(每个数据卡一个) expect(screen.getAllByText(/数据来源:/i).length).toBeGreaterThanOrEqual(4); }); it('renders an early-access co-creation label instead of fabricated testimonials', () => { render(); expect(screen.getByTestId('early-access-banner')).toBeInTheDocument(); expect(screen.getAllByText('首批客户共创中').length).toBeGreaterThanOrEqual(1); }); it('renders the problem-method-result narrative with chapter numbers', () => { render(); expect(screen.getByTestId('narrative-section')).toBeInTheDocument(); expect(screen.getAllByText('01').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('02').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('03').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText(/从问题到结果/).length).toBeGreaterThan(0); }); }); describe('HomeContentV15 - 行业洞察区(对标 Accenture Insights)', () => { it('renders the insights pillar with typed tags and verifiable methodology content', () => { render(); expect(screen.getByTestId('insights-section')).toBeInTheDocument(); // 类型标签(对标 Research Report / Perspective / Case Study) expect(screen.getAllByText('方法论').length).toBeGreaterThanOrEqual(2); expect(screen.getByText('观点')).toBeInTheDocument(); // 全部链接真实页面,不虚构研究报告 expect(screen.getByText('数字化转型诊断:从哪里开始,如何衡量')).toBeInTheDocument(); }); }); describe('HomeContentV15 - 创始人观点区(对标 Accenture CEO Quote)', () => { it('renders the founder quote with attribution (no fabricated persona)', () => { render(); expect(screen.getByTestId('founder-quote-section')).toBeInTheDocument(); expect(screen.getByText(/数字化不是一次性项目/)).toBeInTheDocument(); expect(screen.getByText('Novalon 创始团队')).toBeInTheDocument(); }); }); describe('HomeContentV15 - 新闻动态区(对标 Accenture News)', () => { it('renders the news section with latest items and a view-all entry', () => { render(); expect(screen.getByTestId('news-section')).toBeInTheDocument(); expect(screen.getByText('四川睿新致远科技有限公司正式成立')).toBeInTheDocument(); expect(screen.getByText('查看全部新闻')).toBeInTheDocument(); }); it('renders CMS-provided news when available', () => { render(); expect(screen.getByText('CMS 新闻条目')).toBeInTheDocument(); }); }); describe('HomeContentV15 - 案例区 Client Spotlight(对标 Accenture Client Spotlight)', () => { it('renders a co-creation spotlight card (verifiable, no fabricated clients) when no cases exist', () => { render(); // 空态 spotlight:共创流程 3 步 + 深色卡 CTA expect(screen.getAllByText('首批客户共创中').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('业务诊断').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('方案共创')).toBeInTheDocument(); expect(screen.getByText('验证发布')).toBeInTheDocument(); expect(screen.getAllByText('01').length).toBeGreaterThanOrEqual(1); expect(screen.getByTestId('cases-co-creation-cta')).toHaveAttribute('href', '/contact'); }); it('renders a dark spotlight card with metrics for the featured case when data exists', () => { const mockCases = [ { slug: 'spotlight-demo', industry: '制造业', title: 'Spotlight 案例标题', href: '/cases/spotlight-demo', verified: true, testimonial: { quote: '这是一段客户引言,用于验证 spotlight 渲染。', author: '客户 CIO', role: '某制造企业', }, metrics: [ { value: '38%', label: '交付效率提升' }, { value: '2x', label: '数据查询提速' }, { value: '3周', label: '上线周期' }, ], }, { slug: 'secondary-case', industry: '贸易零售', title: '次要案例标题', href: '/cases/secondary-case', metrics: [ { value: '15%', label: '库存周转改善' }, { value: '4h', label: '对账耗时' }, { value: '9成', label: '预测准确率' }, ], }, ]; render(); // spotlight 大卡:深色画布 + 引言 + 授权 badge + 量化指标 expect(screen.getByText('Spotlight 案例标题')).toBeInTheDocument(); expect(screen.getByText('这是一段客户引言,用于验证 spotlight 渲染。')).toBeInTheDocument(); expect(screen.getByText('已获客户授权')).toBeInTheDocument(); expect(screen.getByText('38%')).toBeInTheDocument(); expect(screen.getByText('查看完整案例')).toBeInTheDocument(); // 次要案例保持轻量卡片 expect(screen.getByText('次要案例标题')).toBeInTheDocument(); expect(screen.getAllByText('了解详情').length).toBeGreaterThanOrEqual(1); }); });