feat(fleet): preserve operator VESC integration before final driver merge
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
import ts from 'typescript';
|
||||
const code=ts.transpileModule(readFileSync(new URL('../../../packages/sensor-ui/src/boardLayout.ts',import.meta.url),'utf8'),{compilerOptions:{module:ts.ModuleKind.ESNext,target:ts.ScriptTarget.ES2022}}).outputText;
|
||||
const {createBoardLayoutStore,defaultBoardLayout}=await import('data:text/javascript;base64,'+Buffer.from(code).toString('base64'));
|
||||
const tick=()=>new Promise(resolve=>setImmediate(resolve));
|
||||
function server(){
|
||||
let value=structuredClone(defaultBoardLayout);const calls=[];
|
||||
return {calls,read:async()=>structuredClone(value),patch:async(section,open)=>{
|
||||
calls.push({section,open});await tick();
|
||||
value={...value,revision:value.revision+1,open_sections:defaultBoardLayout.open_sections.filter(id=>id===section?open:value.open_sections.includes(id))};
|
||||
return structuredClone(value);
|
||||
}};
|
||||
}
|
||||
test('rapid toggles persist after navigation and preserve all-closed state',async()=>{
|
||||
const api=server();const store=createBoardLayoutStore(api);await store.load();
|
||||
const unsubscribe=store.subscribe(()=>{});
|
||||
store.change(['settings','devices']);store.change(['devices']);store.change([]);
|
||||
unsubscribe();
|
||||
while(store.getSnapshot().saving)await tick();
|
||||
const reopened=createBoardLayoutStore(api);await reopened.load();
|
||||
assert.deepEqual(reopened.getSnapshot().value.open_sections,[]);
|
||||
assert.equal(api.calls.length,3);
|
||||
});
|
||||
test('a later toggle wins while an older patch is still in flight',async()=>{
|
||||
const api=server();const store=createBoardLayoutStore(api);await store.load();
|
||||
store.change(['settings','devices']);store.change(['computer','settings','devices']);
|
||||
while(store.getSnapshot().saving)await tick();
|
||||
assert.deepEqual((await api.read()).open_sections,defaultBoardLayout.open_sections);
|
||||
});
|
||||
test('different vehicles and simultaneous section changes do not clobber one another',async()=>{
|
||||
const api=server(),other=server();const a=createBoardLayoutStore(api),b=createBoardLayoutStore(api),c=createBoardLayoutStore(other);
|
||||
await Promise.all([a.load(),b.load(),c.load()]);
|
||||
a.change(['settings','devices']);b.change(['computer','devices']);
|
||||
while(a.getSnapshot().saving||b.getSnapshot().saving)await tick();
|
||||
assert.deepEqual((await api.read()).open_sections,['devices']);
|
||||
assert.deepEqual(c.getSnapshot().value.open_sections,defaultBoardLayout.open_sections);
|
||||
});
|
||||
test('failed save reports failure, rolls back, and explicit reload recovers',async()=>{
|
||||
const api=server();let fail=true;
|
||||
const store=createBoardLayoutStore({...api,patch:(...args)=>fail?Promise.reject(new Error('offline')):api.patch(...args)});
|
||||
await store.load();store.change([]);
|
||||
while(store.getSnapshot().saving)await tick();
|
||||
assert.ok(store.getSnapshot().error);
|
||||
assert.deepEqual(store.getSnapshot().value.open_sections,defaultBoardLayout.open_sections);
|
||||
fail=false;await store.load();store.change(['devices']);
|
||||
while(store.getSnapshot().saving)await tick();
|
||||
assert.equal(store.getSnapshot().error,null);
|
||||
assert.deepEqual((await api.read()).open_sections,['devices']);
|
||||
});
|
||||
test('invalid layout cannot overwrite stored preferences',async()=>{
|
||||
let writes=0;
|
||||
const store=createBoardLayoutStore({read:async()=>({...defaultBoardLayout,open_sections:['motor-start']}),patch:async()=>{writes++;return defaultBoardLayout;}});
|
||||
await store.load();store.change([]);
|
||||
assert.equal(store.getSnapshot().ready,false);assert.ok(store.getSnapshot().error);assert.equal(writes,0);
|
||||
});
|
||||
Reference in New Issue
Block a user