const test=require('node:test'); const assert=require('node:assert/strict'); const path=require('node:path'); const createLoader=require('./load-module.cjs'); const {metadataRows}=require('../utils/photo-metadata'); function setup(update=async()=>({success:true})) { let definition;const calls=[],toasts=[],prompts=[]; const wx={getStorageSync:key=>key==='userId'?1:2,showToast:v=>toasts.push(v),showModal:v=>prompts.push(v)}; const api={photoUpdate:async data=>{calls.push(data);return update(data);}}; const load=createLoader({wx,console,Promise,Date,Page:p=>definition=p},{'../../utils/request':{api,getImageUrl:v=>v}, '../../utils/user-location':{currentUserLocation:async()=>({location:'',lat:0,lng:0})}}); load(path.join(__dirname,'../pages/album/album.js')); const photos=[{id:1,url:'one.jpg',taken_at:'2026-10-07',location:'公园',activity:'散步',lat:23},{id:2,url:'two.jpg',taken_at:'',location:'',activity:''}]; const page={...definition,data:{...definition.data,batches:[{batch_id:'batch',photos,metadata:metadataRows(photos)}]},setData(v){Object.assign(this.data,v);}}; return {page,calls,toasts,prompts}; } const event=(dataset,value)=>({currentTarget:{dataset},detail:{value}}); test('card combines identical information and labels individual photos when their stories differ',()=>{ assert.deepEqual(metadataRows([{id:1},{id:2}]),[]); const same=metadataRows([{id:1,location:'公园'},{id:2,location:'公园'}]);assert.equal(same.length,1);assert.equal(same[0].label,''); const different=metadataRows([{id:1,activity:'散步'},{id:2,location:'公园'}]);assert.equal(different.length,2);assert.equal(different[1].label,'第 2 张'); }); test('saving updates only the chosen photo and preview while preserving the list and coordinates',async()=>{ const e=setup(),p=e.page;p.onPhotoTap(event({batch:0,index:0}));assert.equal(p.data.previewImages[0].location,'公园'); p.openPhotoEditor(event({batch:0}));p.onEditPhotoInput(event({field:'activity'},'第一次一起看日落'));await p.savePhotoInfo(); assert.equal(e.calls.length,1);assert.equal(e.calls[0].id,1);assert.equal(p.data.batches[0].photos[0].activity,'第一次一起看日落');assert.equal(p.data.batches[0].photos[0].lat,23); assert.equal(p.data.batches[0].photos[1].activity,'');assert.equal(p.data.previewImages[0].activity,'第一次一起看日落');assert.equal(p.data.showPhotoEditor,false);assert.equal(p.data.savingPhoto,false); }); test('failed saves keep the draft and original card; switching photos confirms discarding changes',async()=>{ const e=setup(async()=>{throw {error:'保存失败'};}),p=e.page;p.openPhotoEditor(event({batch:0}));p.onEditPhotoInput(event({field:'location'},'新的地点')); p.selectEditPhoto(event({index:1}));assert.equal(e.prompts.length,1);assert.equal(p.data.editPhotoIdx,0);e.prompts[0].success({confirm:false});assert.equal(p.data.editForm.location,'新的地点'); await p.savePhotoInfo();assert.equal(p.data.showPhotoEditor,true);assert.equal(p.data.savingPhoto,false);assert.equal(p.data.editForm.location,'新的地点');assert.equal(p.data.batches[0].photos[0].location,'公园'); p.selectEditPhoto(event({index:1}));e.prompts[1].success({confirm:true});assert.equal(p.data.editPhotoIdx,1);assert.equal(p.data.editForm.location,''); }); test('date and optional fields can be cleared without duplicate saves',async()=>{ let resolve;const e=setup(()=>new Promise(done=>resolve=done)),p=e.page;p.openPhotoEditor(event({batch:0}));p.clearPhotoDate(); p.onEditPhotoInput(event({field:'location'},''));p.onEditPhotoInput(event({field:'activity'},''));const saving=p.savePhotoInfo();await p.savePhotoInfo();assert.equal(e.calls.length,1);assert.equal(e.calls[0].taken_at,''); resolve({success:true});await saving;assert.equal(p.data.batches[0].metadata.length,0); }); test('blank edit address uses current user location; a supplied address wins',async()=>{ const e=setup(),p=e.page; // 使用实际页面的保存逻辑和可控的地址提供者。 let definition; const loader=createLoader({wx:{getStorageSync:()=>1,showToast(){}},Date,Promise,console,Page:d=>definition=d},{'../../utils/request':{api:{photoUpdate:async data=>{e.calls.push(data);return {success:true,location:data.location};}},getImageUrl:v=>v},'../../utils/user-location':{currentUserLocation:async()=>({location:'当前用户地址',lat:25,lng:102})}}); loader(path.join(__dirname,'../pages/album/album.js')); p.savePhotoInfo=definition.savePhotoInfo; p.openPhotoEditor(event({batch:0}));p.onEditPhotoInput(event({field:'location'},' '));await p.savePhotoInfo();assert.equal(e.calls[0].location,'当前用户地址');assert.equal(e.calls[0].lat,25);assert.equal(p.data.batches[0].photos[0].location,'当前用户地址'); p.openPhotoEditor(event({batch:0}));p.onEditPhotoInput(event({field:'location'},' 手填地址 '));await p.savePhotoInfo();assert.equal(e.calls[1].location,'手填地址');assert.equal(e.calls[1].lat,0); });