Add verified camera settings, family version recovery and account self service
This commit is contained in:
@@ -72,3 +72,53 @@ test('older family request errors cannot repopulate logged-out view',async()=>{
|
||||
vm.runInContext(section('family.js','async function loadFamily(','function relationText('),c);
|
||||
const p=c.loadFamily();c.loggedIn=false;c.familyGeneration++;pending.reject(Error('late error'));assert.equal(await p,false);assert.equal(messages,0);
|
||||
});
|
||||
|
||||
const historySource=section('family-history.js','async function showFamilyChange(','function prepareFamilyRestore(');
|
||||
test('history prose is never translated as an enum value',()=>{
|
||||
const c=context({personName:id=>'Person '+id});vm.runInContext(section('family-history.js','function historyValue(','async function openFamilyHistory('),c);
|
||||
assert.equal(c.historyValue('body','published'),'published');assert.equal(c.historyValue('status','published'),'已发布');
|
||||
assert.equal(c.historyValue('personIds',['a','b']),'Person a、Person b');assert.equal(c.historyValue('active',false),'否');
|
||||
});
|
||||
test('history detail from a previous selection cannot replace newer detail',async()=>{
|
||||
const a=deferred(),b=deferred(),calls=[a,b],elements=new Map(),$=s=>{if(!elements.has(s))elements.set(s,{});return elements.get(s);};
|
||||
const c=context({historyContext:{},historyDetailGeneration:0,historySelection:null,api:()=>calls.shift().promise,$,historyFields:{name:'Name'},esc:String,historyValue:(_,v)=>v});
|
||||
vm.runInContext(historySource,c);const old=c.showFamilyChange(1),latest=c.showFamilyChange(2);
|
||||
b.resolve({revision:2,before:null,after:{name:'New'}});await latest;const html=$('#history-detail').innerHTML;
|
||||
a.resolve({revision:1,before:null,after:{name:'Old'}});await old;assert.equal($('#history-detail').innerHTML,html);assert.equal(c.historySelection.revision,2);
|
||||
});
|
||||
test('closing history prevents late private detail from rendering',async()=>{
|
||||
const pending=deferred(),detail={};const c=context({historyContext:{},historyDetailGeneration:0,historySelection:null,api:()=>pending.promise,$:()=>detail});
|
||||
vm.runInContext(historySource,c);const request=c.showFamilyChange(1);c.historyContext=null;c.historyDetailGeneration++;pending.resolve({after:{name:'Private'}});await request;
|
||||
assert.equal(detail.innerHTML,undefined);assert.equal(c.historySelection,null);
|
||||
});
|
||||
test('password form requires matching, distinct and bounded new password',()=>{
|
||||
const c=context();vm.runInContext(section('app.js','function validateNewPassword(','$(\'#account-password\').onclick='),c);
|
||||
for(const data of [{newPassword:'different',confirmPassword:'mismatch'},{newPassword:'samepass',confirmPassword:'samepass',currentPassword:'samepass'},{newPassword:'short',confirmPassword:'short'},{newPassword:'x'.repeat(129),confirmPassword:'x'.repeat(129)}])assert.throws(()=>c.validateNewPassword(data));
|
||||
assert.doesNotThrow(()=>c.validateNewPassword({newPassword:'new-password',confirmPassword:'new-password',currentPassword:'old-password'}));
|
||||
});
|
||||
test('history restore sends the reviewed revision and never the full text',async()=>{
|
||||
let sent;const elements=new Map(),$=s=>{if(!elements.has(s))elements.set(s,{replaceChildren(){}});return elements.get(s);};
|
||||
const c=context({historyContext:{revision:10},historySelection:{revision:3,before:{name:'Original'}},historyDetailGeneration:1,$,$$:()=>[],
|
||||
api:async(path,data)=>{sent={path,data};},loadFamilyHistory:async()=>{},loadFamily:async()=>true,toast:()=>{}});
|
||||
vm.runInContext(section('family-history.js','async function restoreFamilyChange(','$(\'#history-more\').onclick='),c);await c.restoreFamilyChange('before');
|
||||
assert.equal(sent.path,'/api/family/restore');assert.equal(JSON.stringify(sent.data),JSON.stringify({changeRevision:3,side:'before',revision:10}));assert.equal(c.historySelection,null);
|
||||
});
|
||||
|
||||
test('camera form sends only changed and advertised parameters',()=>{
|
||||
const c=context();vm.runInContext(section('camera-settings.js','function changedCameraValues(','async function saveCameraSettings('),c);
|
||||
const form={elements:{brightness:{value:'60'},dayNight:{value:'AUTO'},malicious:{value:'anything'}}};
|
||||
const settings={imaging:{brightness:{value:50,min:0,max:100},dayNight:{value:'AUTO',choices:['AUTO','ON']}}};
|
||||
assert.equal(JSON.stringify(c.changedCameraValues(form,'imaging',settings)),JSON.stringify({brightness:60}));
|
||||
});
|
||||
test('late camera settings cannot populate a closed or different camera dialog',async()=>{
|
||||
const pending=deferred(),elements=new Map(),$=s=>{if(!elements.has(s))elements.set(s,{value:'main'});return elements.get(s);};let renders=0;
|
||||
const c=context({cameraSettingsContext:{id:'old'},cameraSettingsGeneration:0,$,$$:()=>[],URLSearchParams,api:()=>pending.promise,renderCameraSettings:()=>renders++});
|
||||
vm.runInContext(section('camera-settings.js','async function loadCameraSettings(','async function openCameraSettings('),c);const request=c.loadCameraSettings();c.cameraSettingsContext={id:'new'};c.cameraSettingsGeneration++;pending.resolve({device:{}});await request;assert.equal(renders,0);
|
||||
});
|
||||
test('ambiguous device save requires re-read before another write',async()=>{
|
||||
const elements=new Map(),$=s=>{if(!elements.has(s))elements.set(s,{});return elements.get(s);};const buttons=[{disabled:false}];
|
||||
const c=context({cameraSettingsContext:{id:'camera',quality:'main',settings:{revision:'old'}},cameraSettingsGeneration:0,$,$$:()=>buttons,
|
||||
changedCameraValues:()=>({brightness:60}),api:async()=>{throw Error('connection lost');},toast:()=>{}});
|
||||
vm.runInContext(section('camera-settings.js','async function saveCameraSettings(','for(const [id,section]'),c);await c.saveCameraSettings({},'imaging');
|
||||
assert.equal(c.cameraSettingsContext.settings,null);assert.equal(buttons[0].disabled,true);assert.equal($('#camera-settings-reload').disabled,false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user