const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const path = require('node:path'); function load(file, wx) { return require('./load-module.cjs')({wx, console, Promise, Date})(path.join(__dirname, '..', file)); } test('GET business parameters and POST bodies use clean paths with auth', async () => { const calls=[]; const {api}=load('utils/request.js', { getStorageSync:()=> 'test-token', hideLoading(){}, request(o){calls.push(o);o.success({statusCode:200,data:{items:[], pageSize:20}});} }); const response = await api.diaryList({page:2,page_size:20}); assert.equal(response.page_size,20); await api.periodVisibleSet({period_visible:0}); assert.equal(calls[0].url,'https://past.sundynix.cn/api/diaryList?page=2&pageSize=20'); assert.equal(calls[0].header.Authorization,'Bearer test-token'); assert.equal(calls[1].url,'https://past.sundynix.cn/api/periodVisibleSet'); assert.equal(calls[1].data.periodVisible,0); }); test('multipart upload retains action and token when Android omits headers',async()=>{ let upload; const {uploadFileCompat}=load('utils/request.js',{getStorageSync:()=> 'test-token',compressImage(o){o.fail();},uploadFile(o){upload=o;o.success({statusCode:200,data:'{"success":true,"path":"uploads/test.jpg"}'});} }); await uploadFileCompat({url:'https://past.sundynix.cn/api/uploadPartnerAvatar',filePath:'test.jpg',name:'file',formData:{partner_id:87}}); assert.equal(upload.url,'https://past.sundynix.cn/api/uploadPartnerAvatar?token=test-token'); assert.equal(upload.formData.action,'uploadPartnerAvatar'); assert.equal(upload.formData.token,'test-token'); assert.equal(upload.formData.partnerId,87); assert.equal(upload.formData.partner_id,undefined); }); test('navigation responds to phone statusbar and capsule geometry, with fallback',()=>{ for(const device of [{status:20,top:24,height:32,width:360,left:263},{status:54,top:58,height:32,width:393,left:285}]){ const {getLayout}=load('utils/layout.js',{getWindowInfo:()=>({statusBarHeight:device.status,windowWidth:device.width}),getMenuButtonBoundingClientRect:()=>({top:device.top,height:device.height,left:device.left})}); const layout=getLayout();assert.equal(layout.navHeight,device.status+40);assert.equal(layout.navSide,device.width-device.left+12); } const {getLayout}=load('utils/layout.js',{});assert.equal(getLayout().navHeight,64); }); test('failed homepage load ends the recent-record spinner',async()=>{ let definition; const api={coupleInfo:async()=>{throw { _statusCode:404 };}}; vm.runInNewContext(fs.readFileSync(path.join(__dirname,'../pages/index/index.js'),'utf8'),{ Page(p){definition=p;},require(name){return name.endsWith('/list-pagination')?require('../utils/list-pagination'):name.endsWith('/page-cache')?{withDataCache:p=>p}:name.endsWith('/request')?{api,getImageUrl:v=>v}:name.endsWith('/layout')?{getLayout:()=>({})}:{saveScrollPosition(){},getScrollPosition(){return 0;}};}, wx:{getStorageSync:()=> 'test-token'}, console:{error(){}}, Date, setTimeout }); const page={...definition,data:{...definition.data},setData(data){Object.assign(this.data,data);}}; await page.loadData(); assert.equal(page.data.homeError,true);assert.equal(page.data.statsLoading,false);assert.equal(page.data.statsError,true);assert.equal(page._loadingData,false); }); test('unbound newcomer loads homepage records without requesting couple-only pets',async()=>{ let definition;let petCalls=0; const api={coupleInfo:async()=>({not_bound:true,partner1:{nickname:'新用户'}}),timelineList:async()=>[],albumList:async()=>[],diaryList:async()=>({items:[],total:0}),songsList:async()=>[],checkinList:async()=>({items:[]}),petInfo:async()=>{petCalls++;throw Error('请先绑定情侣');}}; vm.runInNewContext(fs.readFileSync(path.join(__dirname,'../pages/index/index.js'),'utf8'),{ Page(p){definition=p;},require(name){return name.endsWith('/list-pagination')?require('../utils/list-pagination'):name.endsWith('/page-cache')?{withDataCache:p=>p}:name.endsWith('/request')?{api,getImageUrl:v=>v}:name.endsWith('/layout')?{getLayout:()=>({})}:name.endsWith('/journal')?{diaryEntry:v=>v}:{};}, wx:{getStorageSync:()=>1,removeStorageSync(){}},console,Date,setTimeout }); const page={...definition,data:{...definition.data,coupleId:99},setData(data){Object.assign(this.data,data);}}; await page.loadData(); assert.equal(petCalls,0);assert.equal(page.data.coupleId,null); assert.equal(page.data.homeError,false);assert.equal(page.data.statsError,false);assert.equal(page.data.statsLoading,false); assert.equal(page.data.recentDiary.length,0);assert.equal(page.data.stats.pet,0); });