Compare commits

..

2 Commits

Author SHA1 Message Date
rsgltzyd c220bb3b7c Merge branch 'main' of https://git.yulinling.site/rsgltzyd/testing-tool into develop 2026-06-30 19:33:11 +08:00
LingandRX 36b6bfd20d Develop (#74)
* feat: 生成成功改为 toast 提示
* refactor: 数据预览改为显示示例数据,简化组件逻辑
* fix: 非必填字段预览显示 null
* fix: 修复空值率与必填状态的逻辑
* fix: 切换为非必填时默认空值率 100%
* feat: 字段编辑弹窗添加「完成」按钮 去除关闭按钮,添加取消按钮
* refactor: 删除未使用的 defaultNullRate 功能
* feat: 优化规则管理功能
* fix: 更新 features 测试断言以匹配新增的 testDataGenerator
* refactor: 将 formatFileSize 重命名为 formatBytes 并移至通用工具模块
* refactor: 使用 Label 组件替换原生 label 元素,并在 DecodeResultPaper 中引入 Input 组件
* refactor: 规范化页面组件目录结构
* refactor(JsonTools): 规范化页面组件目录结构
* refactor(StorageCleaner): 规范化页面组件目录结构
* refactor(Timestamp): 规范化页面组件目录结构
* refactor(i18n): 移除 chrome.i18n 国际化,统一使用中文硬编码
* refactor(AppRoot): 移除 RouterProvider 组件,直接渲染子组件
* fix(RouterProvider): 将 goBack 重命名为 goHome,修复跨窗同步 merge 不一致
* fix(ThemeModeProvider): 修复主题快照同步与首屏闪烁问题
* refactor: 将 UI 文案改为中文并优化相关逻辑
* refactor: 清理代码注释并优化组件结构
* feat(Dashboard): 重构仪表板功能组件和逻辑
* refactor: 更新功能键名称并移除 README 文件
* refactor: 重构 TopBar 组件并更新项目结构
* feat(TopBar): 添加搜索功能组件并优化结构
* refactor: 统一使用 Button 组件替换原有 button 元素
* feat: 添加 EmptyPlaceholder 组件并更新相关页面
* feat(TextStatistics): 引入 StatCard 组件以优化统计信息展示
* feat(Timestamp): 重构时间戳转换功能,新增 ConverterForm 组件
* feat(Jwt): 重构 JWT 组件,新增常量和结果视图
* refactor(RightClickRestorer): 用状态配置表简化页面 UI 结构
* fix(business): 修复 skewedRandom 函数中的数学计算错误
* refactor(ImageUploader): 移除预览 URL 相关逻辑并简化粘贴事件处理
* feat(TestDataGenerator): 更新规则编辑提示和警告显示逻辑
* refactor(CopyButton.test): 移除冗余测试用例
* refactor(RouterProvider, chromeStorage, useContextMenuData): 更新存储获取逻辑以移除默认值参数
* refactor(代码重复): 抽取共享工具函数与 UI 组件,消除多处重复实现
* fix(RouterProvider): 修复初始加载状态逻辑,确保在加载前不覆盖 chrome.storage
* feat(TopBar): 添加搜索框快捷键提示功能及相关测试
* refactor(StorageCleaner): 移动 isRestrictedUrl 函数到独立模块并更新相关引用
* fix(StorageCleaner): 修复 IndexedDB 清理竞态、部分成功计数与刷新后状态同步
* fix: 修复路由初始化竞态、存储状态静默覆盖与存储清理误删
* refactor: 统一中文文案并简化组件结构,提升代码可读性
* refactor: 更新 Worker 消息类型以支持生成任务 ID
* fix: 修复 ruleStorage 写入失败处理与 CopyButton 成功态样式
2026-06-27 17:58:59 +08:00
3 changed files with 13 additions and 135 deletions
@@ -234,38 +234,29 @@ export default function FieldList({
if (!ruleName.trim()) return; if (!ruleName.trim()) return;
const trimmedName = ruleName.trim(); const trimmedName = ruleName.trim();
const existingRule = ruleStorage.getByName(trimmedName);
// 检查名称是否重复 // 检查名称是否重复
if (!overwrite && existingRule) { if (!overwrite) {
const existingRule = ruleStorage.getByName(trimmedName);
if (existingRule) {
setShowConfirmOverwrite(true); setShowConfirmOverwrite(true);
return; return;
} }
const savedRule = ruleStorage.save(
overwrite && existingRule
? {
id: existingRule.id,
name: trimmedName,
description: ruleDescription.trim(),
fields: fields,
} }
: {
const newRule = ruleStorage.save({
name: trimmedName, name: trimmedName,
description: ruleDescription.trim(), description: ruleDescription.trim(),
fields: fields, fields: fields,
}, });
);
if (savedRule) { if (newRule) {
setShowSaveDialog(false); setShowSaveDialog(false);
setShowConfirmOverwrite(false); setShowConfirmOverwrite(false);
setRuleName(''); setRuleName('');
setRuleDescription(''); setRuleDescription('');
toast.success(overwrite ? '规则已覆盖' : '规则已保存'); toast.success('规则已保存');
onRuleSaved?.(); onRuleSaved?.();
} else {
toast.error('规则保存失败');
} }
}, },
[ruleName, ruleDescription, fields, onRuleSaved], [ruleName, ruleDescription, fields, onRuleSaved],
@@ -1,92 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { FieldConfig } from '@/types/testDataGenerator';
vi.mock('@/utils/ruleStorage', () => ({
getByName: vi.fn(),
save: vi.fn(),
update: vi.fn(),
}));
vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}));
import FieldList from '../FieldList';
import * as ruleStorage from '@/utils/ruleStorage';
import { toast } from 'sonner';
const mockedRuleStorage = vi.mocked(ruleStorage);
const mockedToast = vi.mocked(toast);
const mockFields: FieldConfig[] = [
{
id: 'field-1',
name: 'username',
generatorId: 'string',
params: {},
required: true,
nullRate: 0,
unique: false,
},
];
const defaultProps = {
fields: mockFields,
onUpdate: vi.fn(),
onRemove: vi.fn(),
onAdd: vi.fn(),
onEdit: vi.fn(),
onReorder: vi.fn(),
};
describe('FieldList 规则保存', () => {
beforeEach(() => {
vi.clearAllMocks();
mockedRuleStorage.getByName.mockReturnValue(undefined);
mockedRuleStorage.save.mockReturnValue({
id: 'rule-1',
name: 'My Rule',
fields: mockFields,
createdAt: Date.now(),
updatedAt: Date.now(),
useCount: 0,
});
});
it('覆盖同名规则时应更新已有规则而非新建', async () => {
const user = userEvent.setup();
const existingRule = {
id: 'existing-rule-id',
name: 'My Rule',
fields: mockFields,
createdAt: Date.now(),
updatedAt: Date.now(),
useCount: 0,
};
mockedRuleStorage.getByName.mockReturnValue(existingRule);
render(<FieldList {...defaultProps} />);
await user.click(screen.getByRole('button', { name: /保存规则/ }));
await user.type(screen.getByPlaceholderText('规则名称'), 'My Rule');
await user.click(screen.getByRole('button', { name: '确认' }));
expect(screen.getByText('已存在同名规则,是否覆盖保存?')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: '覆盖' }));
expect(mockedRuleStorage.save).toHaveBeenCalledWith({
id: 'existing-rule-id',
name: 'My Rule',
description: '',
fields: mockFields,
});
expect(mockedToast.success).toHaveBeenCalledWith('规则已覆盖');
});
});
-21
View File
@@ -48,27 +48,6 @@ describe('ruleStorage', () => {
expect(updated).toBeNull(); expect(updated).toBeNull();
}); });
it('save 带 id 时应更新已有规则而非新建', () => {
const first = ruleStorage.save({
name: 'Test Rule',
fields: [mockField],
});
expect(first).not.toBeNull();
const updatedField = { ...mockField, name: 'email' };
const updated = ruleStorage.save({
id: first!.id,
name: 'Test Rule',
description: 'Updated',
fields: [updatedField],
});
expect(updated).not.toBeNull();
expect(ruleStorage.getCount()).toBe(1);
expect(ruleStorage.getById(first!.id)?.fields[0].name).toBe('email');
expect(ruleStorage.getById(first!.id)?.description).toBe('Updated');
});
it('deleteRule 在 localStorage 写入失败时应返回 false', () => { it('deleteRule 在 localStorage 写入失败时应返回 false', () => {
const saved = ruleStorage.save({ const saved = ruleStorage.save({
name: 'Test Rule', name: 'Test Rule',