Download tests/test_reader_engine_preload.js from VoiceOfML/Search: direct link, hf CLI and curl.
- Browser
- Download file 5.6 kB
-
https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/tests/test_reader_engine_preload.js
- Command line
-
hf download hf://spaces/VoiceOfML/Search/tests/test_reader_engine_preload.js
-
curl -L -o test_reader_engine_preload.js https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/tests/test_reader_engine_preload.js
5.6 kB
| const fs = require('fs'); | |
| const path = require('path'); | |
| const vm = require('vm'); | |
| const assert = require('assert'); | |
| const root = process.argv[2] ? path.resolve(process.argv[2]) : path.resolve(__dirname,'..'); | |
| const script = fs.readFileSync(path.join(root,'static/reader/pdf/reader-engine-preload.js'),'utf8'); | |
| const resources = require(path.join(root,'static/reader-resources.js')); | |
| const tick=()=>new Promise(resolve=>setImmediate(resolve)); | |
| function fixture(prefix,query,{saveData=false,held=false,httpFailure=false,readFailure=false}={}){ | |
| const links=[],fetches=[],events=new Map(),timers=new Map(); | |
| let reads=0; | |
| vm.runInNewContext(script,{URL,URLSearchParams,AbortController,Promise, | |
| navigator:{connection:{saveData}},location:{search:query},VoiceOfMLReaderResources:resources, | |
| VoiceOfMLReaderSecurity:{async readBytes(_response,limit){assert.equal(limit,1024*1024);reads++; | |
| if(readFailure)throw Error('optional bytes failed');return new Uint8Array();}}, | |
| setTimeout(fn,ms){assert.equal(ms,8000);timers.set(1,fn);return 1;},clearTimeout:id=>timers.delete(id), | |
| addEventListener:(name,fn)=>events.set(name,fn),removeEventListener:name=>events.delete(name), | |
| fetch(url,options){ | |
| fetches.push({url,options}); | |
| assert.ok(/\/static\/(?:reader\/pdf\/pdf-worker-wrapper\.[a-f0-9.]*mjs|reader\/pdf\/pdf-worker-wrapper\.mjs|vendor\/wasm\/qcms_bg\.wasm)$/.test(url),'byte warming is restricted to component paths'); | |
| assert.equal(options.mode,'same-origin');assert.equal(options.credentials,'same-origin'); | |
| if(held)return new Promise((_,reject)=>options.signal.addEventListener('abort',()=>reject(options.signal.reason),{once:true})); | |
| return Promise.resolve({ok:!httpFailure,body:{cancel:async()=>{}}}); | |
| }, | |
| document:{currentScript:{src:'https://site.test'+prefix+'reader/pdf/reader-engine-preload.abcdef123456.js'}, | |
| createElement:()=>({}),head:{appendChild:node=>links.push(node)}}}); | |
| return {links,fetches,events,timers,get reads(){return reads;}}; | |
| } | |
| (async()=>{ | |
| for(const prefix of ['/static/','/search/static/']){ | |
| for(const [query,pdf] of [['?ext=pdf',true],['?ext=PDF',true],['?ext=txt',false],['?id=abc',false], | |
| ['?url='+encodeURIComponent('https://example.test/Book.PDF'),true],['?url=invalid&ext=txt',false]]){ | |
| const f=fixture(prefix,query),base='https://site.test'+prefix; | |
| assert.deepStrictEqual(f.links.map(link=>link.href),pdf?['pdf','pdfWorker'].map(name=>resources.vendorUrl(name,base)):[]); | |
| assert.ok(f.links.every(link=>link.rel==='modulepreload')); | |
| assert.deepStrictEqual(f.fetches.map(row=>row.url),pdf?[base+'reader/pdf/pdf-worker-wrapper.mjs',...resources.pdfSupportAssets(base)]:[]); | |
| await tick();assert.equal(f.reads,pdf?2:0);assert.equal(f.timers.size,0);assert.equal(f.events.size,0); | |
| } | |
| for(const extension of ['md','markdown','html','htm','epub']){ | |
| const f=fixture(prefix,'?ext='+extension),base='https://site.test'+prefix,suffix=prefix==='/search/static/'?'?reader-v1':''; | |
| assert.deepStrictEqual(f.links.map(link=>link.href),resources.engineAssets(extension,base,suffix)); | |
| assert.equal(f.fetches.length,0); | |
| if(extension==='epub'){ | |
| assert.ok(f.links.some(link=>link.href===base+'foliate-reader/vendor/zip.js')); | |
| assert.ok(f.links.some(link=>link.href===base+'foliate-reader/epub.js')); | |
| assert.ok(f.links.every(link=>link.rel==='modulepreload')); | |
| }else{ | |
| assert.ok(f.links.every(link=>link.rel==='preload'&&link.as==='script')); | |
| if(extension==='html'||extension==='htm')assert.equal(f.links.length,1); | |
| } | |
| } | |
| } | |
| // Every static view.js import must be warmed with view.js, or it is only | |
| // discovered after view.js arrives (an extra round trip on first open). | |
| const view=path.join(root,'static/foliate-reader/view.js'); | |
| if(fs.existsSync(view)){ | |
| const imports=[...fs.readFileSync(view,'utf8').matchAll(/^import\s[^;]*?from\s+['"]\.\/([^'"]+)['"]/gm)].map(m=>m[1]); | |
| assert.ok(imports.length>=4,'expected view.js static imports'); | |
| for(const extension of ['epub','mobi','azw','azw3','fb2','fbz']){ | |
| const hrefs=resources.engineAssets(extension,'/static/'); | |
| for(const file of imports)assert.ok(hrefs.includes('/static/foliate-reader/'+file),extension+' must warm '+file); | |
| } | |
| }else console.log('foliate-reader not prepared; static import coverage skipped (run copy_reader_vendor.mjs)'); | |
| const lean=fixture('/static/','?ext=pdf',{saveData:true});await tick();assert.equal(lean.fetches.length,1); | |
| assert.ok(lean.fetches[0].url.endsWith('pdf-worker-wrapper.mjs')); | |
| for(const event of ['pagehide','voice-reader-dispose','timeout']){ | |
| const f=fixture('/static/','?ext=pdf',{held:true}); | |
| if(event==='timeout')f.timers.get(1)();else f.events.get(event)(); | |
| await tick();assert.ok(f.fetches.every(row=>row.options.signal.aborted));assert.equal(f.events.size,0);assert.equal(f.timers.size,0); | |
| } | |
| for(const options of [{httpFailure:true},{readFailure:true}]){ | |
| const f=fixture('/static/','?ext=pdf',options);await tick(); | |
| assert.equal(f.timers.size,0);assert.equal(f.events.size,0,'optional failure must release warming ownership'); | |
| } | |
| assert.ok(resources.readerFiles.indexOf('reader/pdf/pdf-worker-wrapper.mjs')<resources.readerFiles.indexOf('reader/pdf/reader-engine-preload.js'), | |
| 'topological hashing must know the Worker demand path before rewriting its warmup'); | |
| console.log('Pinned PDF/Markdown/HTML/EPUB byte warming, demand URLs and both prefixes passed'); | |
| })().catch(error=>{console.error(error);process.exitCode=1;}); | |