Add hierarchical geography and cloud-hosted profile images
This commit is contained in:
+20
-1
@@ -36,7 +36,7 @@ test('backup messages distinguish local-only, network copy, and failure',()=>{
|
||||
});
|
||||
test('place cards group by city without exposing an inline photo payload',()=>{
|
||||
const out={innerHTML:''},filter={};const c=vm.createContext({state:{familyId:'a',households:[{id:'a',name:'Home',province:'Province',city:'City A',members:1,sites:1,coverUrl:'/api/households/cover?id=a',coverData:'PRIVATE-PHOTO'},{id:'b',name:'Office',city:'City B',kind:'office',members:1,sites:0}]},
|
||||
activePage:'households',setOptions:()=>{},$:s=>s==='#household-list'?out:filter,isAdmin:()=>false,esc:s=>String(s),scopeKind:h=>h.kind||'home'});
|
||||
ZhaoGeography:require('./web/geography.js'),activePage:'households',setOptions:()=>{},$:s=>s==='#household-list'?out:filter,isAdmin:()=>false,esc:s=>String(s),scopeKind:h=>h.kind||'home'});
|
||||
vm.runInContext(part(homes,'function renderHouseholds(','async function switchHousehold('),c);c.renderHouseholds();
|
||||
assert.match(out.innerHTML,/City A/);assert.match(out.innerHTML,/City B/);assert.match(out.innerHTML,/\/api\/households\/cover\?id=a/);
|
||||
assert.doesNotMatch(out.innerHTML,/PRIVATE-PHOTO|data-edit-household/);
|
||||
@@ -66,3 +66,22 @@ test('replacing or resetting an image invalidates older decode jobs',()=>{
|
||||
const first=c.nextImageJob('logo'),second=c.nextImageJob('logo');assert.equal(c.imageJobCurrent('logo',first),false);assert.equal(c.imageJobCurrent('logo',second),true);
|
||||
c.invalidateBrandImages();assert.equal(c.imageJobCurrent('logo',second),false);
|
||||
});
|
||||
|
||||
test('cover accepts a large original but compresses below proxy request limits',async()=>{
|
||||
let size=0;const canvas={getContext:()=>({drawImage(){}}),toDataURL:()=> 'data:image/png;base64,'+'A'.repeat(++size===1?1000000:500000)};
|
||||
const c=vm.createContext({createImageBitmap:async()=>({width:8000,height:6000,close(){}}),document:{createElement:()=>canvas}});
|
||||
vm.runInContext(part(source,'async function readImage(','for(const [id,type,max]'),c);
|
||||
const result=await c.readImage({type:'image/jpeg',size:15*1024*1024},960);
|
||||
assert.ok((result.length-22)*.75<600*1024);assert.ok(canvas.width<=960);
|
||||
await assert.rejects(c.readImage({type:'image/jpeg',size:31*1024*1024},960),/30 MB/);
|
||||
await assert.rejects(c.readImage({type:'image/jpeg',size:15*1024*1024},256),/5 MB/);
|
||||
});
|
||||
|
||||
test('failed and still-processing covers block profile save instead of reporting success',async()=>{
|
||||
let submit,calls=0;const error={textContent:''},f={querySelector:()=>error,addEventListener:(_,fn)=>submit=fn};
|
||||
const jobs=new Map([['cover',{error:true}]]);
|
||||
const c=vm.createContext({coverSaving:false,$:()=>f,imageJobs:jobs,imageJobPending:()=>false,api:async()=>{calls++;},formValues:()=>{throw Error('must not serialize failed image');}});
|
||||
vm.runInContext(part(homes,"$('#household-form').addEventListener('submit'",'document.addEventListener'),c);
|
||||
await submit({preventDefault(){},currentTarget:f});assert.equal(calls,0);assert.match(error.textContent,/封面未准备成功/);
|
||||
c.imageJobPending=()=>true;await submit({preventDefault(){},currentTarget:f});assert.match(error.textContent,/仍在处理/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user