Files
leistungsbilanz-ts/tests/circuit-editor-history.test.ts
T

127 lines
3.6 KiB
TypeScript

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { loadCircuitEditorSnapshot } from "../src/frontend/utils/circuit-editor-history.js";
import {
getProjectHistory,
redoProjectCommand,
undoProjectCommand,
} from "../src/frontend/utils/api.js";
import type {
CircuitTreeResponseDto,
ProjectHistoryStateDto,
} from "../src/frontend/types.js";
function tree(currentRevision: number): CircuitTreeResponseDto {
return {
id: "list-1",
projectId: "project-1",
distributionBoardId: "board-1",
name: "Liste",
currentRevision,
sections: [],
};
}
function history(currentRevision: number): ProjectHistoryStateDto {
return {
projectId: "project-1",
currentRevision,
undoDepth: currentRevision,
redoDepth: 0,
undoChangeSetId: currentRevision > 0 ? `change-${currentRevision}` : null,
redoChangeSetId: null,
};
}
describe("circuit editor history snapshot", () => {
it("returns tree and persistent history from the same project revision", async () => {
const snapshot = await loadCircuitEditorSnapshot(
async () => tree(4),
async () => history(4)
);
assert.equal(snapshot.tree.currentRevision, 4);
assert.equal(snapshot.history.undoDepth, 4);
});
it("retries when the project changes between the tree and history reads", async () => {
const treeRevisions = [4, 5];
const historyRevisions = [5, 5];
let attempts = 0;
const snapshot = await loadCircuitEditorSnapshot(
async () => tree(treeRevisions[attempts]),
async () => history(historyRevisions[attempts++])
);
assert.equal(attempts, 2);
assert.equal(snapshot.tree.currentRevision, 5);
assert.equal(snapshot.history.currentRevision, 5);
});
it("rejects a snapshot that remains inconsistent", async () => {
await assert.rejects(
() =>
loadCircuitEditorSnapshot(
async () => tree(4),
async () => history(5),
2
),
/während des Ladens geändert/
);
});
it("loads history and sends revision-safe undo/redo requests", async () => {
const requests: Array<{ url: string; body?: unknown }> = [];
const originalFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
const url = String(input);
requests.push({
url,
...(init?.body
? { body: JSON.parse(String(init.body)) as unknown }
: {}),
});
const currentRevision = requests.length - 1;
const state = history(currentRevision);
return new Response(
JSON.stringify(
init?.method === "POST"
? {
revision: {
revisionId: `revision-${currentRevision}`,
changeSetId: `change-${currentRevision}`,
projectId: "project-1",
revisionNumber: currentRevision,
createdAtIso: "2026-07-25T00:00:00.000Z",
},
history: state,
}
: state
),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
await getProjectHistory("project-1");
await undoProjectCommand("project-1", 4);
await redoProjectCommand("project-1", 5);
} finally {
globalThis.fetch = originalFetch;
}
assert.deepEqual(requests, [
{ url: "/api/projects/project-1/history" },
{
url: "/api/projects/project-1/history/undo",
body: { expectedRevision: 4 },
},
{
url: "/api/projects/project-1/history/redo",
body: { expectedRevision: 5 },
},
]);
});
});