Backup:
- Neues Setting backupIncludeDownloads (Default aus) — Backup sichert
standardmaessig NUR Einstellungen, nicht die Download-Liste/History.
- buildBackupPayload/planBackupImport (testbare backup-payload.ts): Export
omittet session+history wenn Flag aus (explizites kind-Marker); Import folgt
dem FILE-Inhalt, nicht dem lokalen Toggle.
- importBackup: settings-only -> frueher Return nach setSettings, KEIN stop/
Queue-Wipe/Relaunch. Return {restored,relaunch,message}; main.ts gated den
Auto-Relaunch auf relaunch. Renderer re-seeded settingsDraft bei !relaunch.
Bugfixes:
- Ctrl+A waehlte das ungefilterte Paket-Map -> Loeschen nach Suche traf
versteckte Pakete. Jetzt visibleOrderIds (sichtbare Zeilen, inkl. Items).
- selectedIds nie geprunt bei Delta-Removal -> aufgeblaehte Counts. Neue pure
pruneSelection (selection.ts) + Effect.
- link-status-dot conditional -> Dateiname sprang ~14px. Platzhalter-Slot.
- sortPackagesForDisplay sortierte aktive Pakete nach Live-Progress -> Reshuffle
pro Tick. Jetzt stabile Queue-Reihenfolge je Gruppe (Anti-Flicker).
+17 Tests (backup-payload 9, selection 5, package-order anti-flicker 3).
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { pruneSelection } from "../src/renderer/selection";
|
|
import type { SessionState } from "../src/shared/types";
|
|
|
|
function session(packageIds: string[], itemIds: string[]): Pick<SessionState, "packages" | "items"> {
|
|
const packages: Record<string, never> = {};
|
|
const items: Record<string, never> = {};
|
|
for (const id of packageIds) packages[id] = {} as never;
|
|
for (const id of itemIds) items[id] = {} as never;
|
|
return { packages, items };
|
|
}
|
|
|
|
describe("pruneSelection", () => {
|
|
it("drops ids whose package/item no longer exists", () => {
|
|
const sel = new Set(["p1", "i1", "ghost-p", "ghost-i"]);
|
|
const next = pruneSelection(sel, session(["p1"], ["i1"]));
|
|
expect([...next].sort()).toEqual(["i1", "p1"]);
|
|
});
|
|
|
|
it("returns the SAME set instance when nothing changed (no needless re-render)", () => {
|
|
const sel = new Set(["p1", "i1"]);
|
|
const next = pruneSelection(sel, session(["p1"], ["i1"]));
|
|
expect(next).toBe(sel);
|
|
});
|
|
|
|
it("returns the same instance for an empty selection", () => {
|
|
const sel = new Set<string>();
|
|
expect(pruneSelection(sel, session(["p1"], ["i1"]))).toBe(sel);
|
|
});
|
|
|
|
it("prunes everything when the whole session was swapped out", () => {
|
|
const sel = new Set(["p1", "i1"]);
|
|
const next = pruneSelection(sel, session([], []));
|
|
expect(next.size).toBe(0);
|
|
expect(next).not.toBe(sel);
|
|
});
|
|
|
|
it("keeps a mixed package+item selection when both survive", () => {
|
|
const sel = new Set(["p1", "p2", "i1"]);
|
|
const next = pruneSelection(sel, session(["p1", "p2"], ["i1", "i2"]));
|
|
expect([...next].sort()).toEqual(["i1", "p1", "p2"]);
|
|
expect(next).toBe(sel); // unchanged → same instance
|
|
});
|
|
});
|