Restore editor history after reload
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
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 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user