Files
Endoleap/tests/headless/publication-guard.test.mjs
T

14 lines
2.6 KiB
JavaScript

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {createDocument,createRegistry,builtinComponents,createEditor} from '../../src/lib/canvas-core/index.ts';
const registry=createRegistry(builtinComponents()),record={id:'A',incarnation:1,structure:'node',componentId:'text',dataVersion:1,ownerCanvasId:'P',data:{title:'A',text:''},geometry:{x:0,y:0,width:100,height:100,rotation:0}},document=createDocument('project',[{id:'P',parent:null}],[record]);
test('coordinator prepares runtime atomically for commands, history, metadata and canonical replacement',()=>{
let nextId=0,reject=false,calls=0;const editor=createEditor({document,registry,runtime:{prepared:0},createId:()=>`op${++nextId}`,prepareRuntime:(previous,next)=>{calls++;assert.equal(previous,editor.getSnapshot());assert.ok(Object.isFrozen(next));if(reject)throw Error('reserved resource');return Object.freeze({...next.runtime,prepared:previous.runtime.prepared+1});}});
const snapshots=[];editor.subscribe((_,snapshot)=>{assert.equal(snapshot.runtime.prepared,snapshots.length+1);assert.equal(editor.getQueries().document,snapshot.document);snapshots.push(snapshot);});
assert.equal(editor.dispatch({type:'element.data',target:{id:'A',incarnation:1},patch:{text:'new'}}).status,'applied');assert.equal(editor.history.undo().status,'applied');assert.equal(editor.history.redo().status,'applied');assert.equal(editor.updateRuntime(previous=>({...previous,extra:true})).status,'applied');const source=editor.getSnapshot();assert.equal(editor.reconcile(document,source.runtime,source.rootRevision).status,'applied');assert.equal(calls,5);
reject=true;const root=editor.getSnapshot(),query=editor.getQueries();for(const operation of [()=>editor.dispatch({type:'element.data',target:{id:'A',incarnation:1},patch:{text:'blocked'}}),()=>editor.history.undo(),()=>editor.updateRuntime(()=>({prepared:100})),()=>editor.reconcile(source.document,source.runtime,root.rootRevision)]){assert.equal(operation().status,'rejected');assert.equal(editor.getSnapshot(),root);assert.equal(editor.getQueries(),query);}assert.equal(snapshots.length,5);
});
test('an async coordinator cannot publish a partially prepared root',()=>{
const editor=createEditor({document,registry,runtime:0,prepareRuntime:()=>Promise.resolve(1)}),root=editor.getSnapshot();assert.equal(editor.dispatch({type:'element.data',target:{id:'A',incarnation:1},patch:{text:'blocked'}}).code,'async_transaction');assert.equal(editor.updateRuntime(()=>1).code,'async_transaction');assert.equal(editor.reconcile(document,1,root.rootRevision).code,'async_transaction');assert.equal(editor.getSnapshot(),root);
});