feat: 增加测试覆盖率并优化代码质量
test: 添加单元测试和端到端测试 refactor: 重构登录页面和上传模块 ci: 更新测试覆盖率阈值至42% build: 添加测试相关依赖 docs: 更新测试文档 style: 修复代码格式问题
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { NewsDetailClient } from './NewsDetailClient';
|
||||
|
||||
jest.mock('next/navigation', () => ({
|
||||
useRouter: () => ({
|
||||
push: jest.fn(),
|
||||
back: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: { children: React.ReactNode; href: string }) => {
|
||||
return <a href={href}>{children}</a>;
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
},
|
||||
useInView: () => true,
|
||||
}));
|
||||
|
||||
const mockNews = {
|
||||
id: 'test-news',
|
||||
title: '测试新闻标题',
|
||||
category: '公司新闻',
|
||||
date: '2024-01-01',
|
||||
excerpt: '这是测试新闻摘要',
|
||||
content: '这是测试新闻内容',
|
||||
};
|
||||
|
||||
describe('NewsDetailClient', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render news detail page', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const container = screen.getByText('测试新闻标题').closest('div');
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render news title', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const title = screen.getByRole('heading', { level: 1 });
|
||||
expect(title).toBeInTheDocument();
|
||||
expect(title).toHaveTextContent('测试新闻标题');
|
||||
});
|
||||
|
||||
it('should render news category', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const categories = screen.getAllByText('公司新闻');
|
||||
expect(categories.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render news date', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const date = screen.getByText('2024-01-01');
|
||||
expect(date).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render news excerpt', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const excerpt = screen.getByText('这是测试新闻摘要');
|
||||
expect(excerpt).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render news content', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const content = screen.getByText('这是测试新闻内容');
|
||||
expect(content).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Navigation', () => {
|
||||
it('should have back button', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const backButtons = screen.getAllByRole('button', { name: /返回/i });
|
||||
expect(backButtons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have proper heading hierarchy', () => {
|
||||
render(<NewsDetailClient news={mockNews as any} />);
|
||||
const h1 = screen.getByRole('heading', { level: 1 });
|
||||
expect(h1).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
import { describe, it, expect, jest, beforeAll } from '@jest/globals';
|
||||
import { render, screen, fireEvent } 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>
|
||||
),
|
||||
},
|
||||
AnimatePresence: ({ children }: any) => <>{children}</>,
|
||||
useInView: () => [null, true],
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href, ...props }: any) => (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock('lucide-react', () => ({
|
||||
Search: () => <span data-testid="search-icon" />,
|
||||
Calendar: () => <span data-testid="calendar-icon" />,
|
||||
ArrowRight: () => <span data-testid="arrow-right-icon" />,
|
||||
ArrowLeft: () => <span data-testid="arrow-left-icon" />,
|
||||
Filter: () => <span data-testid="filter-icon" />,
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/button', () => ({
|
||||
Button: ({ children, className, onClick, ...props }: any) => (
|
||||
<button className={className} onClick={onClick} {...props}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/badge', () => ({
|
||||
Badge: ({ children, className, ...props }: any) => (
|
||||
<span className={className} {...props}>
|
||||
{children}
|
||||
</span>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/card', () => ({
|
||||
Card: ({ children, className, ...props }: any) => (
|
||||
<div className={className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
CardContent: ({ children, className, ...props }: any) => (
|
||||
<div className={className} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/input', () => ({
|
||||
Input: ({ className, ...props }: any) => (
|
||||
<input className={className} {...props} />
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/components/ui/page-header', () => ({
|
||||
PageHeader: ({ title, description }: any) => (
|
||||
<header>
|
||||
<h1>{title}</h1>
|
||||
<p>{description}</p>
|
||||
</header>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('@/lib/constants', () => ({
|
||||
NEWS: [
|
||||
{
|
||||
id: 'news-1',
|
||||
title: '公司成立新闻',
|
||||
category: '公司新闻',
|
||||
date: '2026-01-15',
|
||||
excerpt: '公司正式成立,开启数字化转型之旅',
|
||||
},
|
||||
{
|
||||
id: 'news-2',
|
||||
title: '产品发布新闻',
|
||||
category: '产品发布',
|
||||
date: '2026-02-01',
|
||||
excerpt: '新产品正式发布',
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
import NewsListPage from './page';
|
||||
|
||||
describe('NewsListPage', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render news page', () => {
|
||||
const { container } = render(<NewsListPage />);
|
||||
const pageContainer = container.querySelector('.min-h-screen');
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render page header', () => {
|
||||
render(<NewsListPage />);
|
||||
const title = screen.getByText(/新闻动态/i);
|
||||
expect(title).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render back to home link', () => {
|
||||
render(<NewsListPage />);
|
||||
const backLink = screen.getByText(/返回首页/i);
|
||||
expect(backLink).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render news cards', () => {
|
||||
render(<NewsListPage />);
|
||||
const newsCards = screen.getAllByRole('heading', { level: 3 });
|
||||
expect(newsCards.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should render category filter', () => {
|
||||
render(<NewsListPage />);
|
||||
const filterLabel = screen.getByText(/分类筛选/i);
|
||||
expect(filterLabel).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render search input', () => {
|
||||
render(<NewsListPage />);
|
||||
const searchInput = screen.getByPlaceholderText(/搜索新闻/i);
|
||||
expect(searchInput).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Filtering', () => {
|
||||
it('should filter news by category', () => {
|
||||
render(<NewsListPage />);
|
||||
const companyNewsButton = screen.getByRole('button', { name: '公司新闻' });
|
||||
fireEvent.click(companyNewsButton);
|
||||
|
||||
const newsCards = screen.getAllByRole('heading', { level: 3 });
|
||||
expect(newsCards.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should filter news by search query', () => {
|
||||
render(<NewsListPage />);
|
||||
const searchInput = screen.getByPlaceholderText(/搜索新闻/i);
|
||||
fireEvent.change(searchInput, { target: { value: '成立' } });
|
||||
|
||||
const newsCards = screen.getAllByRole('heading', { level: 3 });
|
||||
expect(newsCards.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Navigation', () => {
|
||||
it('should have news detail links', () => {
|
||||
render(<NewsListPage />);
|
||||
const links = screen.getAllByRole('link');
|
||||
const newsLinks = links.filter(link => link.getAttribute('href')?.startsWith('/news/'));
|
||||
expect(newsLinks.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility', () => {
|
||||
it('should have proper heading hierarchy', () => {
|
||||
render(<NewsListPage />);
|
||||
const h1 = screen.getByRole('heading', { level: 1 });
|
||||
expect(h1).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user