import {test} from 'node:test'; import assert from 'node:assert/strict'; import vm from 'node:vm'; import {readFileSync} from 'node:fs'; const source=readFileSync(new URL('../deploy-admin-functions.mjs',import.meta.url),'utf8').match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1]; const payroll=readFileSync(new URL('../cloud/payroll-integrity.js',import.meta.url),'utf8'); test('business dates preserve Shanghai boundaries and invalid values without constructing formatters per record',()=>{ let slowCalls=0,formatters=0; class MeasuredDate extends Date {toLocaleDateString(...args){slowCalls++;return super.toLocaleDateString(...args);}} const c=vm.createContext({Date:MeasuredDate,Intl:{DateTimeFormat:function(...args){formatters++;return new Intl.DateTimeFormat(...args);}}}); vm.runInContext(source+'\n'+payroll,c); const values=['2026-10-31T15:59:59Z','2026-10-31T16:00:00Z','1990-07-01T16:00:00Z','2024-02-29T16:00:00Z','bad','',null,0]; for(let i=0;i<1000;i++)values.push(new Date(Date.UTC(1985+i%45,i%12,i%28+1,i%24,i%60)).toISOString()); for(const value of values)assert.equal(c.businessDate(value),new Date(value).toLocaleDateString('sv-SE',{timeZone:'Asia/Shanghai'})); for(const value of values){const iso=c.payrollDateIso(value);assert.equal(c.payrollBusinessDate(value),iso?new Date(iso).toLocaleDateString('sv-SE',{timeZone:'Asia/Shanghai'}):'');} assert.equal(slowCalls,0,'record loops must reuse the timezone formatter'); assert.equal(formatters,2); }); test('coach list starts its independent reads together instead of serial round trips',async()=>{ const pending=[],calls=[]; const c=vm.createContext({Date,Psql:{query:sql=>{calls.push(sql);return new Promise(resolve=>pending.push(resolve));}}});vm.runInContext(source,c); c.companyIdOf=()=> 'tenant';c.availabilityRows=async()=>[]; const result=c.coachRows({roles:['ops-manager']},{}); await Promise.resolve(); const started=calls.length; // Let both old serial and new parallel implementations finish before asserting. for(let i=0;i<10;i++){for(const resolve of pending.splice(0))resolve([]);await new Promise(r=>setImmediate(r));} await result; assert.equal(started,3,'users, appointments and lesson facts have no dependency on one another'); }); test('release patch changes only the named read helpers and preserves unrelated deployed fixes',async()=>{ const {patchAdminSpeed,speedHelpers}=await import('../admin-speed-patch.mjs'); const fixture='const privateDeploymentSetting="preserve";\nfunction unrelatedLatestFix(){return 71;}\n'+speedHelpers.map(name=>`function ${name}(){return "old";}`).join('\n'); const patched=patchAdminSpeed(fixture);assert.ok(patched.startsWith('const privateDeploymentSetting="preserve";\nfunction unrelatedLatestFix(){return 71;}')); assert.match(patched,/function lessonHistoryLabelColumns/);assert.match(patched,/function lessonHistoryLabelJoins/);assert.throws(()=>patchAdminSpeed('function unrelatedLatestFix(){}'),/Missing helper/); }); test('store membership does not load coach payroll or lesson history',async()=>{ const c=vm.createContext({Date,Psql:{query:async()=>[]}});vm.runInContext(source,c); c.companyIdOf=()=> 'tenant';c.queryUsers=async()=>[];c.optionalLegacyMemberSnapshot=async()=>({available:false,items:[],coachIds:[]});c.appointmentSnapshot=async()=>({appointments:[],live:{}});c.operationalSyncIndicator=async()=>({}); c.coachRows=()=>{throw Error('unnecessary coach history lookup');}; const page=await c.storeRows({roles:['ops-manager']},{});assert.equal(page.total,0); });