fix: bound document downloads and cancel stale sessions

This commit is contained in:
2026-09-06 13:56:05 +03:00
parent 34da54a080
commit ae32382ffa
4 changed files with 106 additions and 21 deletions
+45
View File
@@ -22,3 +22,48 @@ test('account switch during file reading prevents upload and download delivery',
if(storage) Object.defineProperty(globalThis,'localStorage',storage);else delete globalThis.localStorage;
}
});
test('download timeouts bound both successful and failed response bodies',async t=>{
const storage=Object.getOwnPropertyDescriptor(globalThis,'localStorage'),originalFetch=globalThis.fetch;
Object.defineProperty(globalThis,'localStorage',{configurable:true,value:{getItem:()=> 'qa-token'}});
t.mock.timers.enable({apis:['setTimeout']});
try {
for(const ok of [true,false]){
let started;const reading=new Promise(resolve=>{started=resolve;});let fetchSignal;
const body=()=>{started();return new Promise(()=>{});};
globalThis.fetch=async(_url,options)=>{fetchSignal=options.signal;return {ok,status:503,blob:body,json:body};};
const downloading=downloadDocument('qa','qa.txt',{timeoutMs:50});await reading;t.mock.timers.tick(50);
await assert.rejects(downloading,/zamanında indirilemedi/);assert.equal(fetchSignal.aborted,true);
}
}finally{globalThis.fetch=originalFetch;t.mock.timers.reset();if(storage)Object.defineProperty(globalThis,'localStorage',storage);else delete globalThis.localStorage;}
});
test('cancelled or unauthenticated downloads cannot start or deliver a file',async()=>{
const storage=Object.getOwnPropertyDescriptor(globalThis,'localStorage'),originalFetch=globalThis.fetch;
let token=null,calls=0;
Object.defineProperty(globalThis,'localStorage',{configurable:true,value:{getItem:()=>token}});
try{
globalThis.fetch=async()=>{calls++;return {ok:true,blob:async()=>new Blob(['QA'])};};
await assert.rejects(downloadDocument('qa','qa.txt'),/giriş yapın/);assert.equal(calls,0);
token='qa-token';const controller=new AbortController();controller.abort();
await assert.rejects(downloadDocument('qa','qa.txt',{signal:controller.signal}),{name:'AbortError'});assert.equal(calls,0);
const later=new AbortController();
globalThis.fetch=async()=>({ok:true,blob:async()=>{later.abort();return new Blob(['QA']);}});
await assert.rejects(downloadDocument('qa','qa.txt',{signal:later.signal}),{name:'AbortError'});
}finally{globalThis.fetch=originalFetch;if(storage)Object.defineProperty(globalThis,'localStorage',storage);else delete globalThis.localStorage;}
});
test('download delivers original bytes and releases URL and link if clicking fails',async t=>{
const storage=Object.getOwnPropertyDescriptor(globalThis,'localStorage'),originalFetch=globalThis.fetch,originalDocument=globalThis.document;
const create=URL.createObjectURL,revoke=URL.revokeObjectURL;let removed=0,revoked=0,clicks=0,receivedBlob,link,fail=false;
Object.defineProperty(globalThis,'localStorage',{configurable:true,value:{getItem:()=> 'qa-token'}});
t.mock.timers.enable({apis:['setTimeout']});
try{
globalThis.fetch=async()=>({ok:true,blob:async()=>new Blob(['Özgün test belgesi'])});
URL.createObjectURL=blob=>{receivedBlob=blob;return 'blob:qa';};URL.revokeObjectURL=url=>{assert.equal(url,'blob:qa');revoked++;};
globalThis.document={body:{appendChild:()=>{}},createElement:()=>link={click:()=>{clicks++;if(fail)throw new Error('click failed');},remove:()=>{removed++;}}};
await downloadDocument('qa','Türkçe belge.txt');
assert.equal(link.download,'Türkçe belge.txt');assert.equal(await receivedBlob.text(),'Özgün test belgesi');
t.mock.timers.tick(5000);assert.equal(clicks,1);assert.equal(removed,1);assert.equal(revoked,1);
fail=true;await assert.rejects(downloadDocument('qa','qa.txt'),/click failed/);
t.mock.timers.tick(5000);assert.equal(removed,2);assert.equal(revoked,2);
}finally{globalThis.fetch=originalFetch;globalThis.document=originalDocument;URL.createObjectURL=create;URL.revokeObjectURL=revoke;t.mock.timers.reset();if(storage)Object.defineProperty(globalThis,'localStorage',storage);else delete globalThis.localStorage;}
});