fix(测试数据生成器): 修复 Worker 取消失效与规则存储静默失败 (#69)
- 为生成任务引入 generationId,忽略过期 Worker 响应,避免取消后展示错误数据 - Worker 每 100 行让出事件循环,使 cancel 消息能被及时处理 - ruleStorage.setAll 返回写入结果,save/update/delete 在 QuotaExceeded 时返回失败 - 补充 useGenerator 与 ruleStorage 单元测试
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import * as ruleStorage from '../ruleStorage';
|
||||
|
||||
const STORAGE_KEY = 'testDataGenerator_rules';
|
||||
|
||||
const mockField = {
|
||||
id: 'field-1',
|
||||
name: 'username',
|
||||
generatorId: 'string',
|
||||
params: {},
|
||||
required: true,
|
||||
nullRate: 0,
|
||||
unique: false,
|
||||
};
|
||||
|
||||
describe('ruleStorage', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('save 在 localStorage 写入失败时应返回 null', () => {
|
||||
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
|
||||
throw new DOMException('QuotaExceededError');
|
||||
});
|
||||
|
||||
const result = ruleStorage.save({
|
||||
name: 'Test Rule',
|
||||
fields: [mockField],
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(localStorage.getItem(STORAGE_KEY)).toBeNull();
|
||||
});
|
||||
|
||||
it('update 在 localStorage 写入失败时应返回 null', () => {
|
||||
const saved = ruleStorage.save({
|
||||
name: 'Test Rule',
|
||||
fields: [mockField],
|
||||
});
|
||||
expect(saved).not.toBeNull();
|
||||
|
||||
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
|
||||
throw new DOMException('QuotaExceededError');
|
||||
});
|
||||
|
||||
const updated = ruleStorage.update(saved!.id, { name: 'Updated Rule' });
|
||||
expect(updated).toBeNull();
|
||||
});
|
||||
|
||||
it('deleteRule 在 localStorage 写入失败时应返回 false', () => {
|
||||
const saved = ruleStorage.save({
|
||||
name: 'Test Rule',
|
||||
fields: [mockField],
|
||||
});
|
||||
expect(saved).not.toBeNull();
|
||||
|
||||
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
|
||||
throw new DOMException('QuotaExceededError');
|
||||
});
|
||||
|
||||
expect(ruleStorage.deleteRule(saved!.id)).toBe(false);
|
||||
expect(ruleStorage.getById(saved!.id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -78,7 +78,9 @@ export function save(
|
||||
useCount: 0,
|
||||
};
|
||||
rules.unshift(newRule);
|
||||
setAll(rules);
|
||||
if (!setAll(rules)) {
|
||||
return null;
|
||||
}
|
||||
return newRule;
|
||||
}
|
||||
|
||||
@@ -95,7 +97,9 @@ export function save(
|
||||
updatedAt: now,
|
||||
};
|
||||
rules[index] = updatedRule;
|
||||
setAll(rules);
|
||||
if (!setAll(rules)) {
|
||||
return null;
|
||||
}
|
||||
return updatedRule;
|
||||
}
|
||||
|
||||
@@ -117,7 +121,9 @@ export function update(id: string, updates: Partial<DataRule>): DataRule | null
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
rules[index] = updatedRule;
|
||||
setAll(rules);
|
||||
if (!setAll(rules)) {
|
||||
return null;
|
||||
}
|
||||
return updatedRule;
|
||||
}
|
||||
|
||||
@@ -132,8 +138,7 @@ export function deleteRule(id: string): boolean {
|
||||
return false;
|
||||
}
|
||||
rules.splice(index, 1);
|
||||
setAll(rules);
|
||||
return true;
|
||||
return setAll(rules);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +170,9 @@ export function duplicate(id: string, copySuffix = '(副本)'): DataRule | n
|
||||
|
||||
const rules = getAll();
|
||||
rules.unshift(newRule);
|
||||
setAll(rules);
|
||||
if (!setAll(rules)) {
|
||||
return null;
|
||||
}
|
||||
return newRule;
|
||||
}
|
||||
|
||||
@@ -267,11 +274,13 @@ export function clear(): void {
|
||||
/**
|
||||
* 保存所有规则到存储
|
||||
*/
|
||||
function setAll(rules: DataRule[]): void {
|
||||
function setAll(rules: DataRule[]): boolean {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(rules));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[ruleStorage] 保存规则失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user