fix(buttons): 修复 RippleButton 文字显示问题并解决 ESLint 错误
修复了 RippleButton 组件因 CVA 默认样式与自定义 className 冲突导致的文字不可见问题。 同时修复了项目中的 TypeScript 类型错误和 ESLint 规范问题。 主要修改: 1. 按钮显示修复:为使用红色文字的按钮添加 variant=outline, 为使用白色背景的按钮添加 variant=secondary 2. TypeScript 类型修复:修复 subtle-dots.tsx 中的类型定义错误, 删除不必要的 jest-dom.d.ts 文件 3. ESLint 规范修复:修复 React Hooks 使用规范问题, 将 useRef+forceUpdate 反模式改为 useState, 使用 eslint-disable 注释处理合理的 setState in effect 场景 4. 测试增强:添加按钮显示验证脚本和全面的页面按钮检查脚本
This commit is contained in:
@@ -10,9 +10,11 @@ jest.mock('next/navigation', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('next/link', () => {
|
||||
return ({ children, href }: { children: React.ReactNode; href: string }) => {
|
||||
const MockLink = ({ children, href }: { children: React.ReactNode; href: string }) => {
|
||||
return <a href={href}>{children}</a>;
|
||||
};
|
||||
MockLink.displayName = 'MockLink';
|
||||
return MockLink;
|
||||
});
|
||||
|
||||
jest.mock('framer-motion', () => ({
|
||||
|
||||
@@ -41,7 +41,7 @@ jest.mock('@/lib/constants', () => ({
|
||||
|
||||
// Mock ProductDetailClient 组件
|
||||
jest.mock('./product-detail-client', () => ({
|
||||
ProductDetailClient: ({ productId }: any) => (
|
||||
ProductDetailClient: () => (
|
||||
<div data-testid="product-detail-client">
|
||||
<h1>测试产品</h1>
|
||||
<h2>产品优势</h2>
|
||||
@@ -60,7 +60,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product detail page', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const container = screen.getByText('测试产品').closest('div');
|
||||
expect(container).toBeInTheDocument();
|
||||
});
|
||||
@@ -68,7 +68,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product title', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const title = screen.getByRole('heading', { level: 1 });
|
||||
expect(title).toBeInTheDocument();
|
||||
expect(title).toHaveTextContent('测试产品');
|
||||
@@ -77,7 +77,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product category', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
// Mock 组件中没有产品类别,跳过此测试
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
@@ -85,7 +85,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product description', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
// Mock 组件中没有产品描述,跳过此测试
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
@@ -93,7 +93,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product overview section', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
// Mock 组件中没有产品概述,跳过此测试
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
@@ -101,7 +101,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product features section', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
// Mock 组件中没有核心功能,跳过此测试
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
@@ -109,7 +109,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render product benefits', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const benefits = screen.getByText('产品优势');
|
||||
expect(benefits).toBeInTheDocument();
|
||||
});
|
||||
@@ -117,7 +117,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should render pricing section', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const pricing = screen.getByText('价格方案');
|
||||
expect(pricing).toBeInTheDocument();
|
||||
});
|
||||
@@ -127,7 +127,7 @@ describe('ProductDetailPage', () => {
|
||||
it('should have contact link', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const contactLink = screen.getByRole('link', { name: /联系我们/i });
|
||||
expect(contactLink).toBeInTheDocument();
|
||||
});
|
||||
@@ -137,10 +137,10 @@ describe('ProductDetailPage', () => {
|
||||
it('should have proper heading hierarchy', async () => {
|
||||
const page = await ProductDetailPage({ params: Promise.resolve({ id: 'test-product' }) });
|
||||
render(page);
|
||||
|
||||
|
||||
const h1 = screen.getByRole('heading', { level: 1 });
|
||||
expect(h1).toBeInTheDocument();
|
||||
|
||||
|
||||
const h2s = screen.getAllByRole('heading', { level: 2 });
|
||||
expect(h2s.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -60,6 +60,7 @@ export function SolutionDetailClient({ solutionId }: SolutionDetailClientProps)
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
variant="outline"
|
||||
className="border-2 border-[#C41E3A] text-[#C41E3A] hover:bg-[#C41E3A] hover:text-white px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center"
|
||||
rippleColor="rgba(196, 30, 58, 0.2)"
|
||||
>
|
||||
@@ -195,6 +196,7 @@ export function SolutionDetailClient({ solutionId }: SolutionDetailClientProps)
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
variant="secondary"
|
||||
rippleColor="rgba(196, 30, 58, 0.3)"
|
||||
className="bg-white text-[#C41E3A] px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center w-full sm:w-auto"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user