mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
重构(应用状态存储): 调整savePaths返回结构化结果并更新所有调用处
- 新增SaveResult类型统一标准化保存操作的结果状态 - 修改savePaths函数返回结构化结果而非布尔值,完善长路径超限、部分失败等场景的处理逻辑,部分失败时重新加载路径避免状态偏移 - 更新useAppActions与ProfileDialog的保存逻辑,适配新API并添加长路径确认弹窗 - 补充相关测试用例,修正导入导出测试的版本号预期
This commit is contained in:
@@ -239,19 +239,26 @@ describe('savePaths', () => {
|
||||
|
||||
it('保存成功', async () => {
|
||||
mockedInvoke.mockResolvedValue(undefined);
|
||||
await useAppStore.getState().savePaths();
|
||||
const result = await useAppStore.getState().savePaths();
|
||||
expect(result).toEqual({ kind: 'success' });
|
||||
const s = useAppStore.getState();
|
||||
expect(s.isSaving).toBe(false);
|
||||
expect(s.isModified).toBe(false);
|
||||
expect(s.statusMessage).toBe('保存成功');
|
||||
});
|
||||
|
||||
it('部分失败时报告具体 hive', async () => {
|
||||
it('部分失败时报告具体 hive 并回读', async () => {
|
||||
mockedInvoke
|
||||
.mockResolvedValueOnce(undefined) // backup_registry
|
||||
.mockResolvedValueOnce(undefined) // save_system_paths
|
||||
.mockRejectedValueOnce('权限不足'); // save_user_paths
|
||||
await useAppStore.getState().savePaths();
|
||||
.mockRejectedValueOnce('权限不足') // save_user_paths
|
||||
// 以下为 partial 触发的 loadPaths 调用
|
||||
.mockResolvedValueOnce(['A']) // load_system_paths
|
||||
.mockResolvedValueOnce(['B']) // load_user_paths
|
||||
.mockResolvedValueOnce([[], []]); // load_disabled_state
|
||||
|
||||
const result = await useAppStore.getState().savePaths();
|
||||
expect(result.kind).toBe('partial');
|
||||
const s = useAppStore.getState();
|
||||
expect(s.isSaving).toBe(false);
|
||||
expect(s.statusMessage).toContain('用户 PATH 保存失败');
|
||||
@@ -268,8 +275,8 @@ describe('savePaths', () => {
|
||||
// 第二次调用应被 isSaving 守卫拦截(此时 isSaving=true)
|
||||
const r2 = useAppStore.getState().savePaths();
|
||||
|
||||
// 第二次调用同步返回 false(被守卫拦截)
|
||||
await expect(r2).resolves.toBe(false);
|
||||
// 第二次调用同步返回 blocked(被守卫拦截)
|
||||
await expect(r2).resolves.toEqual({ kind: 'blocked' });
|
||||
|
||||
// 放行第一次调用的所有 invoke
|
||||
resolveAll!(undefined);
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('exportToJson', () => {
|
||||
it('导出结构化 JSON', () => {
|
||||
const json = exportToJson(sampleData);
|
||||
const parsed = JSON.parse(json);
|
||||
expect(parsed.version).toBe('5.0.0');
|
||||
expect(parsed.version).toBe('5.1.0');
|
||||
expect(parsed.timestamp).toBeDefined();
|
||||
expect(parsed.system.map((e: { path: string }) => e.path)).toEqual(sampleData.system.map(e => e.path));
|
||||
expect(parsed.user.map((e: { path: string }) => e.path)).toEqual(sampleData.user.map(e => e.path));
|
||||
|
||||
@@ -208,21 +208,22 @@ describe('useAppActions', () => {
|
||||
|
||||
it('handleSave 正常保存', async () => {
|
||||
mockedInvoke.mockResolvedValue(undefined);
|
||||
vi.spyOn(useAppStore.getState(), 'savePaths').mockResolvedValue({ kind: 'success' });
|
||||
const { useAppActions } = await import('@/hooks/use-app-actions');
|
||||
const { result } = renderHook(() => useAppActions('system', dialogs));
|
||||
await act(async () => { await result.current.handleSave(); });
|
||||
// invoke 被调用(backup + save_system + save_user + broadcast)
|
||||
expect(mockedInvoke).toHaveBeenCalled();
|
||||
// savePaths is called
|
||||
expect(useAppStore.getState().savePaths).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handleSave 超长确认后强制保存', async () => {
|
||||
// 第一次 savePaths 返回 false(超长)
|
||||
// 第二次(force=true)返回 true
|
||||
// 第一次 savePaths 返回 warning(超长)
|
||||
// 第二次(force=true)返回 success
|
||||
let callCount = 0;
|
||||
vi.spyOn(useAppStore.getState(), 'savePaths').mockImplementation(async (force?: boolean) => {
|
||||
callCount++;
|
||||
if (!force) return false; // 第一次:超长警告
|
||||
return true; // 第二次:强制保存成功
|
||||
if (!force) return { kind: 'warning', reason: 'lengthExceeded' }; // 第一次:超长警告
|
||||
return { kind: 'success' }; // 第二次:强制保存成功
|
||||
});
|
||||
const { useAppActions } = await import('@/hooks/use-app-actions');
|
||||
const { result } = renderHook(() => useAppActions('system', dialogs));
|
||||
@@ -230,4 +231,17 @@ describe('useAppActions', () => {
|
||||
expect(callCount).toBe(2);
|
||||
expect(mockAsk).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handleSave 普通失败不弹确认框', async () => {
|
||||
let callCount = 0;
|
||||
vi.spyOn(useAppStore.getState(), 'savePaths').mockImplementation(async () => {
|
||||
callCount++;
|
||||
return { kind: 'failure', message: '权限不足' };
|
||||
});
|
||||
const { useAppActions } = await import('@/hooks/use-app-actions');
|
||||
const { result } = renderHook(() => useAppActions('system', dialogs));
|
||||
await act(async () => { await result.current.handleSave(); });
|
||||
expect(callCount).toBe(1); // 仅调用一次,不重试
|
||||
expect(mockAsk).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user