mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
chore: 同步 v5.0 基础设施完善到 v5.1
从 v5.0 cherry-pick 的开源项目基础设施改进: 新增配置文件: - .editorconfig, .gitattributes, .prettierrc, .markdownlint.json - commitlint.config.js 新增 GitHub 社区文件: - .github/dependabot.yml — 依赖自动更新 - .github/CODEOWNERS — 自动 PR 审查分配 - .github/FUNDING.yml — 开源赞助入口 新增文档: - ROADMAP.md — 路线图 - SUPPORT.md — 帮助指南 - docs/screenshots/ — 应用截图 新增 Git Hooks: - .husky/pre-commit — lint-staged 自动格式化+修复 - .husky/commit-msg — commitlint 校验 CI 强化: - 新增 Prettier 格式检查 - 新增 Vitest 覆盖率 + Codecov 上报 - 保留 v5.1 已有的 rust-cache + jsdom 全局环境 修复: - index.html 标题 v4.0 → v5.1 - PathEditDialog set-state-in-effect 改用 useRef prevOpen 守卫 - merge-preview.test.tsx no-explicit-any 修复 - 所有 TS/TSX 文件 Prettier 格式化统一 v5.1 保留特性: - @tanstack/react-virtual 虚拟滚动 - jsdom 全局测试环境 - Swatinem/rust-cache CI 加速 - 105 测试全部通过
This commit is contained in:
@@ -1,12 +1,24 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { UndoRedoManager, OperationType, TargetType, type OpRecord } from '../../src/core/undo-redo';
|
||||
import {
|
||||
UndoRedoManager,
|
||||
OperationType,
|
||||
TargetType,
|
||||
type OpRecord,
|
||||
} from '../../src/core/undo-redo';
|
||||
import type { PathEntry } from '../../src/core/path-entry';
|
||||
|
||||
function pe(s: string, enabled: boolean = true): PathEntry {
|
||||
return { path: s, enabled };
|
||||
}
|
||||
|
||||
function makeRecord(type: OperationType, target: TargetType, index: number, count: number, oldPaths: PathEntry[], newPaths: PathEntry[]): OpRecord {
|
||||
function makeRecord(
|
||||
type: OperationType,
|
||||
target: TargetType,
|
||||
index: number,
|
||||
count: number,
|
||||
oldPaths: PathEntry[],
|
||||
newPaths: PathEntry[],
|
||||
): OpRecord {
|
||||
return { type, target, index, count, oldPaths, newPaths };
|
||||
}
|
||||
|
||||
@@ -31,10 +43,10 @@ describe('UndoRedoManager', () => {
|
||||
mgr.push(makeRecord(OperationType.ADD, TargetType.SYSTEM, 2, 1, [], [pe('C:\\NewPath')]));
|
||||
|
||||
const u = mgr.undo(sys, user)!;
|
||||
expect(u[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
expect(u[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
|
||||
const r = mgr.redo(...u)!;
|
||||
expect(r[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files', 'C:\\NewPath']);
|
||||
expect(r[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files', 'C:\\NewPath']);
|
||||
});
|
||||
|
||||
it('DELETE 撤销/重做', () => {
|
||||
@@ -46,11 +58,20 @@ describe('UndoRedoManager', () => {
|
||||
expect(u[0][0].path).toBe(removed.path);
|
||||
|
||||
const r = mgr.redo(...u)!;
|
||||
expect(r[0].map(e => e.path)).toEqual(['C:\\Program Files']);
|
||||
expect(r[0].map((e) => e.path)).toEqual(['C:\\Program Files']);
|
||||
});
|
||||
|
||||
it('EDIT 撤销/重做', () => {
|
||||
mgr.push(makeRecord(OperationType.EDIT, TargetType.SYSTEM, 0, 1, [pe('C:\\Windows')], [pe('C:\\Edited')]));
|
||||
mgr.push(
|
||||
makeRecord(
|
||||
OperationType.EDIT,
|
||||
TargetType.SYSTEM,
|
||||
0,
|
||||
1,
|
||||
[pe('C:\\Windows')],
|
||||
[pe('C:\\Edited')],
|
||||
),
|
||||
);
|
||||
sys[0] = pe('C:\\Edited');
|
||||
|
||||
const u = mgr.undo(sys, user)!;
|
||||
@@ -65,10 +86,10 @@ describe('UndoRedoManager', () => {
|
||||
[sys[0], sys[1]] = [sys[1], sys[0]];
|
||||
|
||||
const u = mgr.undo(sys, user)!;
|
||||
expect(u[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
expect(u[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
|
||||
const r = mgr.redo(...u)!;
|
||||
expect(r[0].map(e => e.path)).toEqual(['C:\\Program Files', 'C:\\Windows']);
|
||||
expect(r[0].map((e) => e.path)).toEqual(['C:\\Program Files', 'C:\\Windows']);
|
||||
});
|
||||
|
||||
it('MOVE_DOWN 撤销/重做', () => {
|
||||
@@ -76,7 +97,7 @@ describe('UndoRedoManager', () => {
|
||||
[sys[0], sys[1]] = [sys[1], sys[0]];
|
||||
|
||||
const u = mgr.undo(sys, user)!;
|
||||
expect(u[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
expect(u[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
});
|
||||
|
||||
it('CLEAN 撤销/重做', () => {
|
||||
@@ -133,12 +154,12 @@ describe('UndoRedoManager', () => {
|
||||
it('超出栈底/栈顶的安全处理', () => {
|
||||
mgr.push(makeRecord(OperationType.ADD, TargetType.SYSTEM, 2, 1, [], [pe('C:\\NewPath')]));
|
||||
sys.push(pe('C:\\NewPath'));
|
||||
|
||||
|
||||
// undo一次
|
||||
mgr.undo(sys, user);
|
||||
// 再次undo,此时应到达底部返回null
|
||||
expect(mgr.undo(sys, user)).toBeNull();
|
||||
|
||||
|
||||
// redo一次
|
||||
mgr.redo(sys, user);
|
||||
// 再次redo,应到达顶部返回null
|
||||
@@ -160,9 +181,12 @@ describe('UndoRedoManager', () => {
|
||||
// 删除 indices [1, 3](C:\Program Files 和 C:\Extra2)
|
||||
const removed = [sys[1], sys[3]];
|
||||
mgr.push({
|
||||
type: OperationType.DELETE, target: TargetType.SYSTEM,
|
||||
index: 1, count: 2,
|
||||
oldPaths: removed, newPaths: [],
|
||||
type: OperationType.DELETE,
|
||||
target: TargetType.SYSTEM,
|
||||
index: 1,
|
||||
count: 2,
|
||||
oldPaths: removed,
|
||||
newPaths: [],
|
||||
indices: [1, 3],
|
||||
});
|
||||
sys.splice(3, 1);
|
||||
@@ -172,21 +196,29 @@ describe('UndoRedoManager', () => {
|
||||
expect(u[0]).toEqual(old);
|
||||
|
||||
const r = mgr.redo(...u)!;
|
||||
expect(r[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Extra1']);
|
||||
expect(r[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Extra1']);
|
||||
});
|
||||
|
||||
it('操作 USER 路径', () => {
|
||||
user.push(pe('C:\\NewUserPath'));
|
||||
mgr.push(makeRecord(OperationType.ADD, TargetType.USER, 1, 1, [], [pe('C:\\NewUserPath')]));
|
||||
const u = mgr.undo(sys, user)!;
|
||||
expect(u[1].map(e => e.path)).toEqual(['C:\\Users\\me\\AppData']);
|
||||
expect(u[0].map(e => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
expect(u[1].map((e) => e.path)).toEqual(['C:\\Users\\me\\AppData']);
|
||||
expect(u[0].map((e) => e.path)).toEqual(['C:\\Windows', 'C:\\Program Files']);
|
||||
});
|
||||
|
||||
it('TOGGLE 撤销/重做', () => {
|
||||
sys[0] = pe('C:\\Windows', false);
|
||||
mgr.push(makeRecord(OperationType.TOGGLE, TargetType.SYSTEM, 0, 1,
|
||||
[pe('C:\\Windows', true)], [pe('C:\\Windows', false)]));
|
||||
mgr.push(
|
||||
makeRecord(
|
||||
OperationType.TOGGLE,
|
||||
TargetType.SYSTEM,
|
||||
0,
|
||||
1,
|
||||
[pe('C:\\Windows', true)],
|
||||
[pe('C:\\Windows', false)],
|
||||
),
|
||||
);
|
||||
|
||||
const u = mgr.undo(sys, user)!;
|
||||
expect(u[0][0].enabled).toBe(true);
|
||||
@@ -204,9 +236,12 @@ describe('UndoRedoManager', () => {
|
||||
mgr.push({
|
||||
type: OperationType.IMPORT_BOTH,
|
||||
target: TargetType.SYSTEM,
|
||||
index: 0, count: 0,
|
||||
oldPaths: oldSys, newPaths: newSys,
|
||||
oldPathsOther: oldUser, newPathsOther: newUser,
|
||||
index: 0,
|
||||
count: 0,
|
||||
oldPaths: oldSys,
|
||||
newPaths: newSys,
|
||||
oldPathsOther: oldUser,
|
||||
newPathsOther: newUser,
|
||||
});
|
||||
sys = newSys;
|
||||
user = newUser;
|
||||
|
||||
Reference in New Issue
Block a user