chore: remove GitHub Actions workflows, use Woodpecker CI exclusively
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { describe, it, expect, beforeEach } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { AboutSection } from './about-section';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: any) => <a href={href}>{children}</a>;
|
||||
});
|
||||
|
||||
describe('AboutSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render about section', () => {
|
||||
render(<AboutSection />);
|
||||
const section = document.querySelector('section#about');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<AboutSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render company slogan', () => {
|
||||
render(<AboutSection />);
|
||||
expect(screen.getByText(/企业需要的/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render company mission', () => {
|
||||
render(<AboutSection />);
|
||||
expect(screen.getByText(/我们只做一件事/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Statistics', () => {
|
||||
it('should render statistics cards', () => {
|
||||
render(<AboutSection />);
|
||||
const cards = document.querySelectorAll('.text-3xl');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should display statistics in grid layout', () => {
|
||||
const { container } = render(<AboutSection />);
|
||||
const grid = container.querySelector('.grid-cols-2');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Call to Action', () => {
|
||||
it('should render learn more button', () => {
|
||||
render(<AboutSection />);
|
||||
expect(screen.getByRole('link', { name: /了解更多关于我们/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should link to about page', () => {
|
||||
render(<AboutSection />);
|
||||
const link = screen.getByRole('link', { name: /了解更多关于我们/ });
|
||||
expect(link).toHaveAttribute('href', '/about');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have region role', () => {
|
||||
render(<AboutSection />);
|
||||
const section = screen.getByRole('region');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have aria-labelledby attribute', () => {
|
||||
render(<AboutSection />);
|
||||
const section = document.querySelector('section#about');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'about-heading');
|
||||
});
|
||||
|
||||
it('should have accessible heading', () => {
|
||||
render(<AboutSection />);
|
||||
const heading = screen.getByRole('heading', { level: 2 });
|
||||
expect(heading).toHaveAttribute('id', 'about-heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have background color', () => {
|
||||
render(<AboutSection />);
|
||||
const section = document.querySelector('section#about');
|
||||
expect(section).toHaveClass('bg-[#FAFAFA]');
|
||||
});
|
||||
|
||||
it('should have proper padding', () => {
|
||||
render(<AboutSection />);
|
||||
const section = document.querySelector('section#about');
|
||||
expect(section).toHaveClass('py-24');
|
||||
});
|
||||
|
||||
it('should have decorative background pattern', () => {
|
||||
const { container } = render(<AboutSection />);
|
||||
const pattern = container.querySelector('.absolute.inset-0');
|
||||
expect(pattern).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { CasesSection } from './cases-section';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: any) => <a href={href}>{children}</a>;
|
||||
});
|
||||
|
||||
jest.mock('@/lib/constants', () => ({
|
||||
CASES: [
|
||||
{
|
||||
id: 'case-1',
|
||||
client: '测试客户',
|
||||
title: '测试案例',
|
||||
description: '测试描述',
|
||||
industry: '制造业',
|
||||
results: [{ value: '40%', label: '效率提升' }],
|
||||
},
|
||||
{
|
||||
id: 'case-2',
|
||||
client: '测试客户2',
|
||||
title: '测试案例2',
|
||||
description: '测试描述2',
|
||||
industry: '零售业',
|
||||
results: [{ value: '50%', label: '成本降低' }],
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
describe('CasesSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render cases section', () => {
|
||||
render(<CasesSection />);
|
||||
const section = document.querySelector('section#cases');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText(/我们与优秀的企业同行/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render case cards', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText('测试案例')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render client names', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText('测试客户')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render industry badges', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText('制造业')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render results', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText('40%')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render view more button', () => {
|
||||
render(<CasesSection />);
|
||||
expect(screen.getByText('查看更多案例')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have section id', () => {
|
||||
render(<CasesSection />);
|
||||
const section = document.querySelector('section#cases');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have region role', () => {
|
||||
render(<CasesSection />);
|
||||
const section = document.querySelector('section[role="region"]');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have aria-labelledby', () => {
|
||||
render(<CasesSection />);
|
||||
const section = document.querySelector('section[aria-labelledby="cases-heading"]');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have correct background', () => {
|
||||
render(<CasesSection />);
|
||||
const section = document.querySelector('section.bg-white');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have container', () => {
|
||||
render(<CasesSection />);
|
||||
const container = document.querySelector('.container-wide');
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,227 @@
|
||||
import { describe, it, expect, jest, beforeAll, afterEach } from '@jest/globals';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, className, ...props }: any) => (
|
||||
<div className={className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
section: ({ children, className, ...props }: any) => (
|
||||
<section className={className} {...props}>
|
||||
{children}
|
||||
</section>
|
||||
),
|
||||
},
|
||||
AnimatePresence: ({ children }: any) => <>{children}</>,
|
||||
}));
|
||||
|
||||
jest.mock('lucide-react', () => ({
|
||||
Mail: () => <span data-testid="mail-icon" />,
|
||||
Phone: () => <span data-testid="phone-icon" />,
|
||||
MapPin: () => <span data-testid="map-pin-icon" />,
|
||||
Send: () => <span data-testid="send-icon" />,
|
||||
Loader2: () => <span data-testid="loader-icon" />,
|
||||
Clock: () => <span data-testid="clock-icon" />,
|
||||
HeadphonesIcon: () => <span data-testid="headphones-icon" />,
|
||||
CheckCircle2: () => <span data-testid="check-circle-icon" />,
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/sanitize', () => ({
|
||||
sanitizeInput: (value: string) => value,
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/csrf', () => ({
|
||||
generateCSRFToken: jest.fn(() => 'test-csrf-token'),
|
||||
setCSRFTokenToStorage: jest.fn(),
|
||||
getCSRFTokenFromStorage: jest.fn(() => 'test-csrf-token'),
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/constants', () => ({
|
||||
COMPANY_INFO: {
|
||||
name: '四川睿新致远科技有限公司',
|
||||
email: 'contact@novalon.cn',
|
||||
phone: '028-88888888',
|
||||
address: '中国四川省成都市龙泉驿区幸福路12号',
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/button', () => ({
|
||||
Button: ({ children, className, disabled, ...props }: any) => (
|
||||
<button className={className} disabled={disabled} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/input', () => ({
|
||||
Input: ({ label, id, placeholder, required, value, onChange, onBlur, error, ...props }: any) => (
|
||||
<div>
|
||||
<label htmlFor={id}>{label}{required && '*'}</label>
|
||||
<input
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
data-testid={`${id}-input`}
|
||||
{...props}
|
||||
/>
|
||||
{error && <span data-testid={`${id}-error`}>{error}</span>}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/textarea', () => ({
|
||||
Textarea: ({ label, id, placeholder, rows, required, value, onChange, onBlur, error, ...props }: any) => (
|
||||
<div>
|
||||
<label htmlFor={id}>{label}{required && '*'}</label>
|
||||
<textarea
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
rows={rows}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
data-testid={`${id}-input`}
|
||||
{...props}
|
||||
/>
|
||||
{error && <span data-testid={`${id}-error`}>{error}</span>}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/toast', () => ({
|
||||
Toast: ({ message, type, onClose, ...props }: any) => (
|
||||
<div data-testid="toast-notification" data-type={type} {...props}>
|
||||
{message}
|
||||
<button onClick={onClose}>关闭</button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
import { ContactSection } from './contact-section';
|
||||
|
||||
describe('ContactSection', () => {
|
||||
beforeAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render contact section', () => {
|
||||
render(<ContactSection />);
|
||||
const section = document.querySelector('section#contact');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render contact form', () => {
|
||||
render(<ContactSection />);
|
||||
expect(screen.getByTestId('name-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('phone-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('email-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('message-input')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render submit button', () => {
|
||||
render(<ContactSection />);
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render company contact information', () => {
|
||||
render(<ContactSection />);
|
||||
expect(screen.getByText('contact@novalon.cn')).toBeInTheDocument();
|
||||
expect(screen.getByText('028-88888888')).toBeInTheDocument();
|
||||
expect(screen.getByText('中国四川省成都市龙泉驿区幸福路12号')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render work hours card', () => {
|
||||
render(<ContactSection />);
|
||||
expect(screen.getByTestId('work-hours-card')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Validation', () => {
|
||||
it('should show error for invalid name', async () => {
|
||||
render(<ContactSection />);
|
||||
const nameInput = screen.getByTestId('name-input');
|
||||
|
||||
await userEvent.type(nameInput, '张');
|
||||
fireEvent.blur(nameInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('name-error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error for invalid phone', async () => {
|
||||
render(<ContactSection />);
|
||||
const phoneInput = screen.getByTestId('phone-input');
|
||||
|
||||
await userEvent.type(phoneInput, '1234567890');
|
||||
fireEvent.blur(phoneInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('phone-error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error for invalid email', async () => {
|
||||
render(<ContactSection />);
|
||||
const emailInput = screen.getByTestId('email-input');
|
||||
|
||||
await userEvent.type(emailInput, 'invalid-email');
|
||||
fireEvent.blur(emailInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('email-error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error for short message', async () => {
|
||||
render(<ContactSection />);
|
||||
const messageInput = screen.getByTestId('message-input');
|
||||
|
||||
await userEvent.type(messageInput, '短留言');
|
||||
fireEvent.blur(messageInput);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('message-error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have proper form labels', () => {
|
||||
render(<ContactSection />);
|
||||
|
||||
expect(screen.getByLabelText(/姓名/)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/电话/)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/邮箱/)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/留言/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have proper ARIA attributes', () => {
|
||||
render(<ContactSection />);
|
||||
const section = document.querySelector('section#contact');
|
||||
expect(section).toHaveAttribute('role', 'region');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'contact-heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CSRF Protection', () => {
|
||||
it('should generate CSRF token on mount', () => {
|
||||
const { generateCSRFToken, setCSRFTokenToStorage } = require('@/lib/csrf');
|
||||
render(<ContactSection />);
|
||||
|
||||
expect(generateCSRFToken).toHaveBeenCalled();
|
||||
expect(setCSRFTokenToStorage).toHaveBeenCalledWith('test-csrf-token');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,150 @@
|
||||
import { describe, it, expect, jest, beforeAll } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, className, ...props }: any) => (
|
||||
<div className={className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
section: ({ children, className, ...props }: any) => (
|
||||
<section className={className} {...props}>
|
||||
{children}
|
||||
</section>
|
||||
),
|
||||
span: ({ children, className, ...props }: any) => (
|
||||
<span className={className} {...props}>
|
||||
{children}
|
||||
</span>
|
||||
),
|
||||
h1: ({ children, className, ...props }: any) => (
|
||||
<h1 className={className} {...props}>
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
},
|
||||
AnimatePresence: ({ children }: any) => <>{children}</>,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href, ...props }: any) => (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock('lucide-react', () => ({
|
||||
ArrowRight: () => <span data-testid="arrow-right" />,
|
||||
Shield: () => <span data-testid="shield-icon" />,
|
||||
Zap: () => <span data-testid="zap-icon" />,
|
||||
Award: () => <span data-testid="award-icon" />,
|
||||
}));
|
||||
|
||||
jest.mock('next/dynamic', () => {
|
||||
const React = require('react');
|
||||
return {
|
||||
__esModule: true,
|
||||
default: (importFn: any, options: any) => {
|
||||
return React.forwardRef((props: any, ref: any) => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@/components/ui/ripple-button', () => ({
|
||||
RippleButton: ({ children, className, ...props }: any) => (
|
||||
<button className={className} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
SealButton: ({ children, className, ...props }: any) => (
|
||||
<button className={className} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/animations', () => ({
|
||||
GradientText: ({ children, className }: any) => (
|
||||
<span className={className}>{children}</span>
|
||||
),
|
||||
MagneticButton: ({ children, className }: any) => (
|
||||
<button className={className}>{children}</button>
|
||||
),
|
||||
BlurReveal: ({ children, className }: any) => (
|
||||
<div className={className}>{children}</div>
|
||||
),
|
||||
CounterWithEffect: ({ end, suffix, className }: any) => (
|
||||
<span className={className}>{end}{suffix || ''}</span>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/constants', () => ({
|
||||
COMPANY_INFO: {
|
||||
name: '四川睿新致远科技有限公司',
|
||||
shortName: '睿新致遠',
|
||||
description: '以智慧连接数字趋势,以伙伴身份陪您成长',
|
||||
},
|
||||
STATS: [
|
||||
{ value: '10+', label: '企业客户' },
|
||||
{ value: '20+', label: '成功案例' },
|
||||
{ value: '30+', label: '项目交付' },
|
||||
{ value: '12+', label: '年行业经验' },
|
||||
],
|
||||
}));
|
||||
|
||||
import { HeroSection } from './hero-section';
|
||||
|
||||
describe('HeroSection', () => {
|
||||
beforeAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render hero section', () => {
|
||||
render(<HeroSection />);
|
||||
const section = document.querySelector('section#home');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render company name', () => {
|
||||
render(<HeroSection />);
|
||||
expect(screen.getByText('睿新致遠')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render features', () => {
|
||||
render(<HeroSection />);
|
||||
expect(screen.getByText('安全可靠')).toBeInTheDocument();
|
||||
expect(screen.getByText('高效便捷')).toBeInTheDocument();
|
||||
expect(screen.getByText('专业服务')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Statistics', () => {
|
||||
it('should render statistics section', () => {
|
||||
render(<HeroSection />);
|
||||
expect(screen.getByText('企业客户')).toBeInTheDocument();
|
||||
expect(screen.getByText('成功案例')).toBeInTheDocument();
|
||||
expect(screen.getByText('项目交付')).toBeInTheDocument();
|
||||
expect(screen.getByText('年行业经验')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have proper ARIA labels', () => {
|
||||
render(<HeroSection />);
|
||||
const section = document.querySelector('section#home');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'hero-heading');
|
||||
});
|
||||
|
||||
it('should have accessible buttons', () => {
|
||||
render(<HeroSection />);
|
||||
const buttons = screen.getAllByRole('button');
|
||||
expect(buttons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { InsightsSection } from './insights-section';
|
||||
|
||||
jest.mock('@/components/ui/insight-card', () => ({
|
||||
InsightCard: ({ title, category }: any) => (
|
||||
<div data-testid="insight-card">
|
||||
<div>{title}</div>
|
||||
<div>{category}</div>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
describe('InsightsSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render insights section', () => {
|
||||
render(<InsightsSection />);
|
||||
const section = document.querySelector('section#insights');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<InsightsSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<InsightsSection />);
|
||||
expect(screen.getByText(/分享前沿技术趋势/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render insight cards', () => {
|
||||
render(<InsightsSection />);
|
||||
const cards = screen.getAllByTestId('insight-card');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render insight titles', () => {
|
||||
render(<InsightsSection />);
|
||||
expect(screen.getByText('2025年技术趋势:AI驱动的数字化转型')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render insight categories', () => {
|
||||
render(<InsightsSection />);
|
||||
expect(screen.getByText('技术趋势')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render view all button', () => {
|
||||
render(<InsightsSection />);
|
||||
expect(screen.getByText('查看全部洞察')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have section id', () => {
|
||||
render(<InsightsSection />);
|
||||
const section = document.querySelector('section#insights');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have correct background', () => {
|
||||
render(<InsightsSection />);
|
||||
const section = document.querySelector('section.bg-\\[\\#FAFAFA\\]');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have container', () => {
|
||||
render(<InsightsSection />);
|
||||
const container = document.querySelector('.container-wide');
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have grid layout', () => {
|
||||
render(<InsightsSection />);
|
||||
const grid = document.querySelector('.grid');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
import { describe, it, expect, beforeEach } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { NewsSection } from './news-section';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: any) => <a href={href}>{children}</a>;
|
||||
});
|
||||
|
||||
describe('NewsSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render news section', () => {
|
||||
render(<NewsSection />);
|
||||
const section = document.querySelector('section#news');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<NewsSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<NewsSection />);
|
||||
expect(screen.getByText(/了解公司最新动态/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('News Cards', () => {
|
||||
it('should render news cards', () => {
|
||||
render(<NewsSection />);
|
||||
const cards = document.querySelectorAll('[class*="flex-col"]');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should display news in grid layout', () => {
|
||||
const { container } = render(<NewsSection />);
|
||||
const grid = container.querySelector('.grid-cols-1');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render news categories', () => {
|
||||
render(<NewsSection />);
|
||||
const categories = document.querySelectorAll('[class*="rounded-full"]');
|
||||
expect(categories.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render news dates', () => {
|
||||
render(<NewsSection />);
|
||||
const dates = document.querySelectorAll('[class*="text-sm"]');
|
||||
expect(dates.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Call to Action', () => {
|
||||
it('should render view all news link', () => {
|
||||
render(<NewsSection />);
|
||||
expect(screen.getByRole('link', { name: /查看全部新闻/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should link to news page', () => {
|
||||
render(<NewsSection />);
|
||||
const link = screen.getByRole('link', { name: /查看全部新闻/ });
|
||||
expect(link).toHaveAttribute('href', '/news');
|
||||
});
|
||||
|
||||
it('should render read more links', () => {
|
||||
render(<NewsSection />);
|
||||
const readMoreLinks = screen.getAllByText(/阅读更多/);
|
||||
expect(readMoreLinks.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have region role', () => {
|
||||
render(<NewsSection />);
|
||||
const section = screen.getByRole('region');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have aria-labelledby attribute', () => {
|
||||
render(<NewsSection />);
|
||||
const section = document.querySelector('section#news');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'news-heading');
|
||||
});
|
||||
|
||||
it('should have accessible heading', () => {
|
||||
render(<NewsSection />);
|
||||
const heading = screen.getByRole('heading', { level: 2 });
|
||||
expect(heading).toHaveAttribute('id', 'news-heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have background color', () => {
|
||||
render(<NewsSection />);
|
||||
const section = document.querySelector('section#news');
|
||||
expect(section).toHaveClass('bg-[#F5F5F5]');
|
||||
});
|
||||
|
||||
it('should have proper padding', () => {
|
||||
render(<NewsSection />);
|
||||
const section = document.querySelector('section#news');
|
||||
expect(section).toHaveClass('py-24');
|
||||
});
|
||||
|
||||
it('should have container styling', () => {
|
||||
const { container } = render(<NewsSection />);
|
||||
const containerDiv = container.querySelector('.container-custom');
|
||||
expect(containerDiv).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
import { describe, it, expect, beforeEach } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { ProductsSection } from './products-section';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: any) => <a href={href}>{children}</a>;
|
||||
});
|
||||
|
||||
describe('ProductsSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render products section', () => {
|
||||
render(<ProductsSection />);
|
||||
const section = document.querySelector('section#products');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<ProductsSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<ProductsSection />);
|
||||
expect(screen.getByText(/自主研发的企业级产品/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Product Cards', () => {
|
||||
it('should render product cards', () => {
|
||||
render(<ProductsSection />);
|
||||
const cards = document.querySelectorAll('[class*="flex-col"]');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should display products in grid layout', () => {
|
||||
const { container } = render(<ProductsSection />);
|
||||
const grid = container.querySelector('.grid-cols-1');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render product categories', () => {
|
||||
render(<ProductsSection />);
|
||||
const badges = document.querySelectorAll('[class*="rounded-full"]');
|
||||
expect(badges.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render product features', () => {
|
||||
render(<ProductsSection />);
|
||||
const features = document.querySelectorAll('[class*="inline-flex"]');
|
||||
expect(features.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom Solution Section', () => {
|
||||
it('should render custom solution section', () => {
|
||||
render(<ProductsSection />);
|
||||
expect(screen.getByText(/需要定制化解决方案/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render custom solution description', () => {
|
||||
render(<ProductsSection />);
|
||||
expect(screen.getByText(/我们的专业团队/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render contact button', () => {
|
||||
render(<ProductsSection />);
|
||||
expect(screen.getByRole('link', { name: /联系我们/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should link to contact page', () => {
|
||||
render(<ProductsSection />);
|
||||
const link = screen.getByRole('link', { name: /联系我们/ });
|
||||
expect(link).toHaveAttribute('href', '/contact');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have region role', () => {
|
||||
render(<ProductsSection />);
|
||||
const section = screen.getByRole('region');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have aria-labelledby attribute', () => {
|
||||
render(<ProductsSection />);
|
||||
const section = document.querySelector('section#products');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'products-heading');
|
||||
});
|
||||
|
||||
it('should have accessible heading', () => {
|
||||
render(<ProductsSection />);
|
||||
const heading = screen.getByRole('heading', { level: 2 });
|
||||
expect(heading).toHaveAttribute('id', 'products-heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have background color', () => {
|
||||
render(<ProductsSection />);
|
||||
const section = document.querySelector('section#products');
|
||||
expect(section).toHaveClass('bg-[#F5F7FA]');
|
||||
});
|
||||
|
||||
it('should have proper padding', () => {
|
||||
render(<ProductsSection />);
|
||||
const section = document.querySelector('section#products');
|
||||
expect(section).toHaveClass('py-24');
|
||||
});
|
||||
|
||||
it('should have decorative background elements', () => {
|
||||
const { container } = render(<ProductsSection />);
|
||||
const decorativeElements = container.querySelectorAll('.blur-3xl');
|
||||
expect(decorativeElements.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,112 @@
|
||||
import { describe, it, expect, beforeEach } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { ServicesSection } from './services-section';
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: any) => <a href={href}>{children}</a>;
|
||||
});
|
||||
|
||||
describe('ServicesSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render services section', () => {
|
||||
render(<ServicesSection />);
|
||||
const section = document.querySelector('section#services');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<ServicesSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<ServicesSection />);
|
||||
expect(screen.getByText(/专业技术团队/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Service Cards', () => {
|
||||
it('should render service cards', () => {
|
||||
render(<ServicesSection />);
|
||||
const cards = document.querySelectorAll('.p-6');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should display services in grid layout', () => {
|
||||
const { container } = render(<ServicesSection />);
|
||||
const grid = container.querySelector('.grid-cols-1');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render service icons', () => {
|
||||
render(<ServicesSection />);
|
||||
const icons = document.querySelectorAll('svg');
|
||||
expect(icons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Call to Action', () => {
|
||||
it('should render view all services button', () => {
|
||||
render(<ServicesSection />);
|
||||
expect(screen.getByRole('link', { name: /查看全部服务/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should link to services page', () => {
|
||||
render(<ServicesSection />);
|
||||
const link = screen.getByRole('link', { name: /查看全部服务/ });
|
||||
expect(link).toHaveAttribute('href', '/services');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have section with id', () => {
|
||||
render(<ServicesSection />);
|
||||
const section = document.querySelector('section#services');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have aria-labelledby attribute', () => {
|
||||
render(<ServicesSection />);
|
||||
const section = document.querySelector('section#services');
|
||||
expect(section).toHaveAttribute('aria-labelledby', 'services-heading');
|
||||
});
|
||||
|
||||
it('should have accessible heading', () => {
|
||||
render(<ServicesSection />);
|
||||
const heading = screen.getByRole('heading', { level: 2 });
|
||||
expect(heading).toHaveAttribute('id', 'services-heading');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have white background', () => {
|
||||
render(<ServicesSection />);
|
||||
const section = document.querySelector('section#services');
|
||||
expect(section).toHaveClass('bg-white');
|
||||
});
|
||||
|
||||
it('should have proper padding', () => {
|
||||
render(<ServicesSection />);
|
||||
const section = document.querySelector('section#services');
|
||||
expect(section).toHaveClass('py-24');
|
||||
});
|
||||
|
||||
it('should have decorative background elements', () => {
|
||||
const { container } = render(<ServicesSection />);
|
||||
const decorativeElements = container.querySelectorAll('.blur-3xl');
|
||||
expect(decorativeElements.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { TestimonialsSection } from './testimonials-section';
|
||||
|
||||
jest.mock('@/components/ui/testimonial-card', () => ({
|
||||
TestimonialCard: ({ author, quote }: any) => (
|
||||
<div data-testid="testimonial-card">
|
||||
<div>{author}</div>
|
||||
<div>{quote}</div>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
describe('TestimonialsSection', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render testimonials section', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const section = document.querySelector('section#testimonials');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section heading', () => {
|
||||
render(<TestimonialsSection />);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render section description', () => {
|
||||
render(<TestimonialsSection />);
|
||||
expect(screen.getByText(/听听我们的客户怎么说/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render testimonial cards', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const cards = screen.getAllByTestId('testimonial-card');
|
||||
expect(cards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render testimonial authors', () => {
|
||||
render(<TestimonialsSection />);
|
||||
expect(screen.getByText('张总')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render testimonial quotes', () => {
|
||||
render(<TestimonialsSection />);
|
||||
expect(screen.getByText(/睿新致远的团队非常专业/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have section id', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const section = document.querySelector('section#testimonials');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Styling', () => {
|
||||
it('should have correct background', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const section = document.querySelector('section.bg-white');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have container', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const container = document.querySelector('.container-wide');
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should have grid layout', () => {
|
||||
render(<TestimonialsSection />);
|
||||
const grid = document.querySelector('.grid');
|
||||
expect(grid).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user