const test=require('node:test'); const assert=require('node:assert/strict'); const path=require('node:path'); function setup({preflightQuota=false,uploadQuota=false,networkRetry=false,metadataFailure=false}={}){ const checks=[],uploads=[],modals=[],navigation=[]; const load=require('./load-module.cjs')({console,Date,Promise,wx:{ getStorageSync:()=> 'token',hideLoading(){},showLoading(){},showToast(){}, compressImage(o){o.success({tempFilePath:'compressed.jpg'});}, getFileInfo(o){if(metadataFailure)return o.fail();o.success({size:o.filePath==='compressed.jpg'?100:200,digest:'a'.repeat(32)});}, request(o){checks.push(o);o.success({statusCode:preflightQuota?403:200,data:preflightQuota?{error:'空间不足',code:10001}:{success:true}});}, uploadFile(o){uploads.push(o);if(networkRetry&&uploads.length===1)return o.fail({errMsg:'network'});o.success({statusCode:uploadQuota?403:200,data:JSON.stringify(uploadQuota?{error:'空间不足',code:10001}:{success:true,fileId:'file-id'})});}, showModal(o){modals.push(o);},navigateTo(o){navigation.push(o.url);} }}); const client=load(path.join(__dirname,'../utils/request.js')); return {...client,checks,uploads,modals,navigation}; } const options={url:'https://we.sundynix.cn/api/upload',filePath:'original.jpg'}; test('preflight checks the compressed bytes before any upload',async()=>{ const c=setup();await c.uploadFileCompat(options); assert.equal(c.checks[0].url,c.API_BASE+'/uploadPreflight'); assert.equal(c.checks[0].data.size,100);assert.equal(c.checks[0].data.md5,'a'.repeat(32)); assert.equal(c.uploads[0].filePath,'compressed.jpg'); }); test('preflight quota rejection blocks bytes, prompts once and offers purchase',async()=>{ const c=setup({preflightQuota:true}); await assert.rejects(c.uploadFileCompat(options),e=>e.code===10001); assert.equal(c.uploads.length,0);assert.equal(c.checks.length,1);assert.equal(c.modals.length,1); assert.equal(c.modals[0].title,'存储空间不足');c.modals[0].success({confirm:true}); assert.deepEqual(c.navigation,['/pages/storage/storage']); }); test('authoritative backend quota rejection after a successful preflight also prompts',async()=>{ const c=setup({uploadQuota:true});await assert.rejects(c.uploadFileCompat(options),e=>e.code===10001); assert.equal(c.uploads.length,1);assert.equal(c.modals.length,1); c.modals[0].success({confirm:false});assert.equal(c.navigation.length,0); }); test('avatar, partner avatar and album uploads all use quota preflight and show one modal on rejection',async()=>{ for(const run of [c=>c.api.uploadAvatar('original.jpg'),c=>c.api.uploadPartnerAvatar('original.jpg','partner'),c=>c.api.photoUpload('original.jpg','album')]){ const c=setup({uploadQuota:true});await assert.rejects(run(c),e=>e.code===10001); assert.equal(c.checks.length,1);assert.equal(c.uploads.length,1);assert.equal(c.modals.length,1); } }); test('network fallback rechecks the original file size; unreadable files never upload',async()=>{ const c=setup({networkRetry:true});await c.uploadFileCompat(options); assert.deepEqual(c.checks.map(o=>o.data.size),[100,200]);assert.equal(c.uploads[1].filePath,'original.jpg'); const bad=setup({metadataFailure:true});await assert.rejects(bad.uploadFileCompat(options));assert.equal(bad.uploads.length,0); });