'use strict'; const assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm'); const source=fs.readFileSync(require('node:path').join(__dirname,'../js/app.js'),'utf8'); const helper=source.slice(source.indexOf(' function reportZoomSource('),source.indexOf(" document.querySelectorAll('.card-detail').forEach(function (card, group)")); const drawn=[],canvases=[]; const frame={getBoundingClientRect:()=>({left:0,top:0,width:100,height:90})}; const img={naturalWidth:1000,naturalHeight:1000,src:'original',getBoundingClientRect:()=>({left:-90,top:-104,width:280,height:252})}; const context={getComputedStyle:e=>e===frame?{backgroundColor:'#f6f6f6'}:{objectFit:'cover',objectPosition:'50% 50%'},document:{createElement:()=>{ const canvas={getContext:()=>({fillRect(){},drawImage(...args){drawn.push(args);}}),toDataURL:()=> 'cropped'};canvases.push(canvas);return canvas; }}}; vm.runInNewContext(helper,context); assert.equal(context.reportZoomSource(img,frame,1),'cropped'); assert.equal(context.reportZoomSource(img,frame,.5),'cropped'); assert.equal(drawn[1][3],drawn[0][3]*.5);assert.equal(drawn[1][4],drawn[0][4]*.5); assert.equal(canvases[0].width,canvases[1].width);assert.equal(canvases[0].height,canvases[1].height); assert(drawn[1][1]<=0&&drawn[1][1]+drawn[1][3]>=canvases[1].width); assert(drawn[1][2]<=0&&drawn[1][2]+drawn[1][4]>=canvases[1].height); assert.equal(context.reportZoomSource(img,frame,.5,.5),'cropped'); assert.equal(drawn[2][2]-drawn[1][2],drawn[1][4]*.5,'move down by exactly half the scaled photo height'); assert.equal(drawn[2][1],drawn[1][1]);assert.equal(drawn[2][3],drawn[1][3]);assert.equal(drawn[2][4],drawn[1][4]); assert.equal(canvases[2].height,canvases[1].height); assert.equal(context.reportZoomSource(img,frame,.5,.3),'cropped'); assert(Math.abs((drawn[2][2]-drawn[3][2])-drawn[1][4]*.2)<1e-9,'move fill upward 20% from previous 50% downward offset'); assert.equal(canvases[3].height,canvases[2].height);assert.equal(drawn[3][3],drawn[2][3]); assert.equal(context.reportZoomSource(img,frame,.5,.25),'cropped'); assert(Math.abs((drawn[3][2]-drawn[4][2])-drawn[1][4]*.05)<1e-9,'move fill upward another 5%'); assert.equal(drawn[4][3],drawn[3][3]);assert.equal(canvases[4].height,canvases[3].height); assert(source.includes('sideButton ? .25 : 0'),'net downward offset is 25%'); assert(source.includes('sideButton ? .5 : 1'),'half-sized fill applies only to side-photo large previews'); console.log('PASS side zoom fill: half size, shifted upward another5% to net downward25%; preview frame/front/small images unchanged');