cloud-drive-renamer/tests/unit/crash-recovery.test.ts
Zain e369349811 test: 添加全面的单元测试、集成测试和性能测试
添加了包括单元测试、集成测试和性能测试在内的全面测试套件,覆盖核心功能如批量重命名、崩溃恢复、冲突检测等。测试文件包括:
1. 单元测试:helpers、rules、storage、retry等核心模块
2. 集成测试:批量执行流程与网络恢复场景
3. 性能测试:100文件处理时间、内存占用等指标
4. E2E测试:扩展加载、批量重命名完整流程

所有测试遵循vitest和playwright规范,确保功能稳定性和性能达标
2025-12-16 15:56:38 +08:00

205 行
5.5 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { CrashRecoveryManager } from '../../src/core/crash-recovery';
import { OperationState } from '../../src/types/core';
import { storage } from '../../src/utils/storage';
// Mock storage
vi.mock('../../src/utils/storage', () => ({
storage: {
set: vi.fn(),
get: vi.fn(),
remove: vi.fn(),
},
}));
// Mock logger
vi.mock('../../src/utils/logger', () => ({
logger: {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
}));
describe('CrashRecoveryManager', () => {
let recovery: CrashRecoveryManager;
let mockState: OperationState;
beforeEach(() => {
recovery = new CrashRecoveryManager();
mockState = {
timestamp: Date.now(),
platform: 'quark',
files: [
{ id: '1', name: 'file1.txt' },
{ id: '2', name: 'file2.txt' },
{ id: '3', name: 'file3.txt' },
],
rule: { type: 'prefix', params: { prefix: 'test_' } },
completed: [0],
failed: [],
};
// 重置mocks
vi.clearAllMocks();
});
describe('saveOperationState', () => {
it('应该保存操作状态', async () => {
await recovery.saveOperationState(mockState);
expect(storage.set).toHaveBeenCalledWith(
'rename_operation_state',
expect.objectContaining({
platform: 'quark',
files: mockState.files,
rule: mockState.rule,
completed: [0],
failed: [],
})
);
});
it('保存时应该包含时间戳', async () => {
await recovery.saveOperationState(mockState);
expect(storage.set).toHaveBeenCalledWith(
'rename_operation_state',
expect.objectContaining({
timestamp: expect.any(Number),
})
);
});
});
describe('checkRecoverableOperation', () => {
it('没有保存状态时应该返回null', async () => {
vi.mocked(storage.get).mockResolvedValue(null);
const result = await recovery.checkRecoverableOperation();
expect(result).toBeNull();
});
it('状态超过30分钟应该返回null并清理', async () => {
const oldState = {
...mockState,
timestamp: Date.now() - 31 * 60 * 1000, // 31分钟前
};
vi.mocked(storage.get).mockResolvedValue(oldState);
const result = await recovery.checkRecoverableOperation();
expect(result).toBeNull();
expect(storage.remove).toHaveBeenCalledWith('rename_operation_state');
});
it('30分钟内的状态应该返回', async () => {
const recentState = {
...mockState,
timestamp: Date.now() - 10 * 60 * 1000, // 10分钟前
};
vi.mocked(storage.get).mockResolvedValue(recentState);
const result = await recovery.checkRecoverableOperation();
expect(result).not.toBeNull();
expect(result?.platform).toBe('quark');
});
it('已完成的操作应该返回null并清理', async () => {
const completedState = {
...mockState,
completed: [0, 1, 2], // 所有文件都完成
};
vi.mocked(storage.get).mockResolvedValue(completedState);
const result = await recovery.checkRecoverableOperation();
expect(result).toBeNull();
expect(storage.remove).toHaveBeenCalled();
});
});
describe('clearOperationState', () => {
it('应该清除保存的状态', async () => {
await recovery.clearOperationState();
expect(storage.remove).toHaveBeenCalledWith('rename_operation_state');
});
});
describe('getPendingFiles', () => {
it('应该返回未完成的文件', () => {
const pendingFiles = recovery.getPendingFiles(mockState);
expect(pendingFiles.length).toBe(2); // file2和file3
expect(pendingFiles[0].id).toBe('2');
expect(pendingFiles[1].id).toBe('3');
});
it('所有文件完成时应该返回空数组', () => {
const completedState = {
...mockState,
completed: [0, 1, 2],
};
const pendingFiles = recovery.getPendingFiles(completedState);
expect(pendingFiles.length).toBe(0);
});
});
describe('markAsCompleted', () => {
it('应该标记文件为已完成', async () => {
vi.mocked(storage.get).mockResolvedValue(mockState);
await recovery.markAsCompleted(1);
expect(storage.set).toHaveBeenCalledWith(
'rename_operation_state',
expect.objectContaining({
completed: [0, 1],
})
);
});
});
describe('markAsFailed', () => {
it('应该标记文件为失败', async () => {
vi.mocked(storage.get).mockResolvedValue(mockState);
await recovery.markAsFailed(1);
expect(storage.set).toHaveBeenCalledWith(
'rename_operation_state',
expect.objectContaining({
failed: [1],
})
);
});
});
describe('showRecoveryDialog', () => {
it('应该显示包含操作信息的对话框', () => {
// Mock confirm
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
const result = recovery.showRecoveryDialog(mockState);
expect(result).toBe(true);
expect(confirmSpy).toHaveBeenCalled();
// 检查对话框消息包含关键信息
const message = confirmSpy.mock.calls[0][0];
expect(message).toContain('quark');
expect(message).toContain('3'); // 总文件数
expect(message).toContain('1'); // 已完成
expect(message).toContain('2'); // 待完成
confirmSpy.mockRestore();
});
});
});