import {test} from 'node:test'; import assert from 'node:assert/strict'; import {readFileSync} from 'node:fs'; import vm from 'node:vm'; import {PGlite} from '@electric-sql/pglite'; import {teacherEarningsSupport} from '../teacher-earnings-transform.mjs'; const source=readFileSync(new URL('../deploy-admin-functions.mjs',import.meta.url),'utf8'); const ops=source.match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1]; const integrity=readFileSync(new URL('../cloud/payroll-integrity.js',import.meta.url),'utf8'); const mobile=readFileSync(new URL('../cloud/mobile-teaching.js',import.meta.url),'utf8'); const support=teacherEarningsSupport(ops,integrity); test('老师工资复用后台计算器:快照、合法零元、规则版本和缺失分类结果一致',()=>{ const admin=vm.createContext({Date});vm.runInContext(ops+integrity,admin); const app=vm.createContext({Date});vm.runInContext(support,app);const c=app.teacherEarningsCalculator(); const base={objectId:'l1',coachId:30,lessonAt:'2026-10-14T10:00:00+08:00',courseCategoryKey:'word',courseId:1,classType:2,durationMinutes:60,deliveryMode:'online'}; for(const row of [base,{...base,teacherPaySnapshot:45},{...base,teacherPaySnapshot:0},{...base,courseCategoryKey:''},{...base,teacherPaySnapshot:-1},{...base,lessonAt:'2026-08-15',teacherPaySnapshot:null}]){ const a=admin.payrollCalculatedLine(row,c.defaultRates(),'',c.defaultRules(),new Map()),b=c.calculate(row,c.defaultRates(),'',c.defaultRules(),new Map()); assert.equal(a.amount,b.amount);assert.equal(a.exception,b.exception);assert.equal(a.rateAmount,b.rateAmount); } assert.equal(c.calculate({...base,teacherPaySnapshot:45},[],'',[],new Map()).amount,45); assert.equal(c.calculate({...base,teacherPaySnapshot:0},[],'',[],new Map()).amount,0); }); test('今日查询在分页前筛选,超过20条未来任务仍不遮挡今日;统计与列表一致且精简响应',async()=>{ const db=new PGlite();try{ await db.exec(readFileSync(new URL('./fixtures/teacher-review-schema.sql',import.meta.url),'utf8')); const calls=[];const query=async(sql,args)=>{calls.push(sql);return(await db.query(sql,args)).rows;}; const ctx=vm.createContext({Date,Promise,DEFAULT_COMPANY_ID:'co',number:(v,f=0)=>Number(v)||f,authorizeRequestedUser:async()=>30,appOverviewToday:()=> '2026-10-14',legacyAliases:r=>r,appLiveVersionSnapshot:async()=>({}),reviewIncomeTotal:async()=>{throw Error('首页不应读取收入');}}); ctx.Psql={query,one:async(s,a)=>(await query(s,a))[0]};vm.runInContext(mobile,ctx); const current={get:()=>3};const today=await ctx.appReviewPage({scope:'today',includeMetadata:false,includeIncome:false,pageSize:4},current); assert.equal(today.items.length,2);assert.equal(today.page.itemCount,2);assert.equal(Number(today.items[0].id),1);assert.equal(today.summary.todayTotal,2);assert.equal(today.summary.todayCompleted,1);assert.equal(today.summary.todayPending,1);assert.equal(today.summary.overduePending,1);assert.equal(today.students.length,0);assert.equal(today.dates.length,0);assert.equal(calls.length,3); const overdue=await ctx.appReviewPage({scope:'overdue',includeMetadata:false,includeIncome:false},current);assert.equal(overdue.items.length,1);assert.equal(overdue.items[0].kywrq,'2026-10-13'); }finally{await db.close();} });