Develop (#26)
统一简化多个页面里的CopyButton调用,删除不再需要的空回调参数 * feat: 添加clearCookies函数的单元测试并修复cookie域名处理逻辑 * feat: 增强 data URI 处理,支持带参数的前缀并更新相关测试 * fix: 修正 AGENTS.md 中 TypeScript 类型检查命令的描述 * feat: 添加 settings.local.json 文件以配置 Bash 权限 * perf: 预设背景色避免 Popup 弹窗白屏闪烁 * perf: 避免图标过早实例化,传递组件引用而非 JSX 节点 * feat: 添加 useLazyTranslation 和 preloadNamespaces 函数以支持动态加载 i18n 命名空间 * feat: 使用 useLazyTranslation 替换 useTranslation 以支持懒加载翻译 * feat: 添加 PageSkeleton 组件及其测试用例以支持页面加载骨架屏 * feat: 使用骨架屏替换加载状态指示器,优化用户体验 * feat: 优化 CopyButton 组件的复制功能,添加定时器管理复制状态 * feat: 调整 chunk 大小警告阈值以优化构建性能
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { render } from '@testing-library/react';
|
||||
import PageSkeleton from '@/components/PageSkeleton';
|
||||
|
||||
describe('PageSkeleton 组件', () => {
|
||||
describe('渲染测试', () => {
|
||||
it('默认应渲染 dashboard 骨架屏', () => {
|
||||
const { container } = render(<PageSkeleton />);
|
||||
|
||||
// dashboard 骨架屏包含 6 个卡片
|
||||
const skeletons = container.querySelectorAll('.MuiSkeleton-root');
|
||||
expect(skeletons.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('variant 为 dashboard 时应渲染仪表盘卡片骨架', () => {
|
||||
const { container } = render(<PageSkeleton variant="dashboard" />);
|
||||
|
||||
// 每个卡片有 4 个 Skeleton(图标、标题、描述、箭头),6 个卡片共 24 个
|
||||
const skeletons = container.querySelectorAll('.MuiSkeleton-root');
|
||||
expect(skeletons.length).toBe(24);
|
||||
});
|
||||
|
||||
it('variant 为 tool 时应渲染工具页面骨架', () => {
|
||||
const { container } = render(<PageSkeleton variant="tool" />);
|
||||
|
||||
// tool 骨架屏包含标题、输入区、控制栏 3 个按钮、结果区
|
||||
const skeletons = container.querySelectorAll('.MuiSkeleton-root');
|
||||
expect(skeletons.length).toBe(6);
|
||||
});
|
||||
});
|
||||
|
||||
describe('布局结构测试', () => {
|
||||
it('dashboard 骨架屏应使用 grid 布局', () => {
|
||||
const { container } = render(<PageSkeleton variant="dashboard" />);
|
||||
const gridContainer = container.firstChild as HTMLElement;
|
||||
|
||||
expect(gridContainer).toHaveStyle({ display: 'grid' });
|
||||
});
|
||||
|
||||
it('tool 骨架屏应有内边距', () => {
|
||||
const { container } = render(<PageSkeleton variant="tool" />);
|
||||
const toolContainer = container.firstChild as HTMLElement;
|
||||
|
||||
expect(toolContainer).toHaveStyle({ padding: '20px' }); // 2.5 * 8px
|
||||
});
|
||||
});
|
||||
|
||||
describe('骨架屏元素测试', () => {
|
||||
it('dashboard 骨架屏应包含圆角和边框样式', () => {
|
||||
const { container } = render(<PageSkeleton variant="dashboard" />);
|
||||
|
||||
// 获取第一个卡片容器
|
||||
const card = container.querySelector('[class*="MuiBox-root"]');
|
||||
expect(card).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('tool 骨架屏应包含圆形和矩形变体', () => {
|
||||
const { container } = render(<PageSkeleton variant="tool" />);
|
||||
|
||||
const roundedSkeletons = container.querySelectorAll('.MuiSkeleton-rounded');
|
||||
const textSkeletons = container.querySelectorAll('.MuiSkeleton-text');
|
||||
|
||||
expect(roundedSkeletons.length).toBeGreaterThan(0);
|
||||
expect(textSkeletons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render } from '@testing-library/react';
|
||||
import RouterContainer from '@/components/RouterContainer';
|
||||
import { RouterProvider } from '@/providers/RouterProvider';
|
||||
import { SnackbarProvider } from '@/components/GlobalSnackbar';
|
||||
@@ -37,10 +37,12 @@ describe('RouterContainer 组件', () => {
|
||||
};
|
||||
|
||||
describe('渲染测试', () => {
|
||||
it('isLoaded 为 false 时应渲染加载状态', () => {
|
||||
it('isLoaded 为 false 时应渲染骨架屏', () => {
|
||||
mockRouterValue.isLoaded = false;
|
||||
renderWithProvider(<RouterContainer />);
|
||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||
const { container } = renderWithProvider(<RouterContainer />);
|
||||
// 骨架屏使用 Skeleton 组件
|
||||
const skeletons = container.querySelectorAll('.MuiSkeleton-root');
|
||||
expect(skeletons.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('isLoaded 为 true 时应渲染页面内容', () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('ToolCard 组件', () => {
|
||||
title="测试工具"
|
||||
description="这是一个测试工具"
|
||||
colorKey="primary"
|
||||
icon={<AccessTimeIcon />}
|
||||
icon={AccessTimeIcon}
|
||||
onClick={() => {}}
|
||||
/>,
|
||||
);
|
||||
@@ -27,23 +27,19 @@ describe('ToolCard 组件', () => {
|
||||
|
||||
it('无描述时仅渲染标题', () => {
|
||||
render(
|
||||
<ToolCard title="仅标题" colorKey="primary" icon={<AccessTimeIcon />} onClick={() => {}} />,
|
||||
<ToolCard title="仅标题" colorKey="primary" icon={AccessTimeIcon} onClick={() => {}} />,
|
||||
);
|
||||
|
||||
expect(screen.getByText('仅标题')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('应渲染图标', () => {
|
||||
render(
|
||||
<ToolCard
|
||||
title="带图标"
|
||||
colorKey="primary"
|
||||
icon={<AccessTimeIcon data-testid="test-icon" />}
|
||||
onClick={() => {}}
|
||||
/>,
|
||||
const { container } = render(
|
||||
<ToolCard title="带图标" colorKey="primary" icon={AccessTimeIcon} onClick={() => {}} />,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('test-icon')).toBeInTheDocument();
|
||||
const svgElement = container.querySelector('svg');
|
||||
expect(svgElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('提供快照内容时应渲染快照', () => {
|
||||
@@ -51,7 +47,7 @@ describe('ToolCard 组件', () => {
|
||||
<ToolCard
|
||||
title="带快照"
|
||||
colorKey="primary"
|
||||
icon={<AccessTimeIcon />}
|
||||
icon={AccessTimeIcon}
|
||||
onClick={() => {}}
|
||||
snapshot={<div data-testid="snapshot">快照内容</div>}
|
||||
/>,
|
||||
@@ -62,7 +58,7 @@ describe('ToolCard 组件', () => {
|
||||
|
||||
it('未提供快照时不渲染快照区域', () => {
|
||||
const { container } = render(
|
||||
<ToolCard title="无快照" colorKey="primary" icon={<AccessTimeIcon />} onClick={() => {}} />,
|
||||
<ToolCard title="无快照" colorKey="primary" icon={AccessTimeIcon} onClick={() => {}} />,
|
||||
);
|
||||
|
||||
expect(container.querySelector('[data-testid="snapshot"]')).not.toBeInTheDocument();
|
||||
@@ -70,7 +66,7 @@ describe('ToolCard 组件', () => {
|
||||
|
||||
it('应使用 CardActionArea 渲染,支持键盘聚焦', () => {
|
||||
render(
|
||||
<ToolCard title="可聚焦" colorKey="primary" icon={<AccessTimeIcon />} onClick={() => {}} />,
|
||||
<ToolCard title="可聚焦" colorKey="primary" icon={AccessTimeIcon} onClick={() => {}} />,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: /可聚焦/ });
|
||||
@@ -83,12 +79,7 @@ describe('ToolCard 组件', () => {
|
||||
it('点击时应调用 onClick', () => {
|
||||
const handleClick = vi.fn();
|
||||
render(
|
||||
<ToolCard
|
||||
title="可点击"
|
||||
colorKey="primary"
|
||||
icon={<AccessTimeIcon />}
|
||||
onClick={handleClick}
|
||||
/>,
|
||||
<ToolCard title="可点击" colorKey="primary" icon={AccessTimeIcon} onClick={handleClick} />,
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button', { name: /可点击/ });
|
||||
@@ -103,7 +94,7 @@ describe('ToolCard 组件', () => {
|
||||
<ToolCard
|
||||
title="键盘可触发"
|
||||
colorKey="primary"
|
||||
icon={<AccessTimeIcon />}
|
||||
icon={AccessTimeIcon}
|
||||
onClick={handleClick}
|
||||
/>,
|
||||
);
|
||||
@@ -120,16 +111,12 @@ describe('ToolCard 组件', () => {
|
||||
|
||||
describe('样式测试', () => {
|
||||
it('应应用自定义颜色代码', () => {
|
||||
render(
|
||||
<ToolCard
|
||||
title="自定义颜色"
|
||||
colorKey="warning"
|
||||
icon={<AccessTimeIcon data-testid="custom-color-icon" />}
|
||||
onClick={() => {}}
|
||||
/>,
|
||||
const { container } = render(
|
||||
<ToolCard title="自定义颜色" colorKey="warning" icon={AccessTimeIcon} onClick={() => {}} />,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('custom-color-icon')).toBeInTheDocument();
|
||||
const svgElement = container.querySelector('svg');
|
||||
expect(svgElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user