import test from 'node:test';import assert from 'node:assert/strict'; import {mkdtemp,rm} from 'node:fs/promises';import {tmpdir} from 'node:os';import {join} from 'node:path'; import {runDirectSync} from '../run-nightly-direct-sync.mjs'; test('所有课次同步后分页核定工资,待核定原因进入回执,写入重试复用同一批次',async()=>{ const root=await mkdtemp(join(tmpdir(),'review-sync-runner-')),original=globalThis.fetch,order=[],receipts=new Map();let simulatedLostResponse=false,applied=0,final; try{ globalThis.fetch=async(url,options)=>{const p=JSON.parse(options.body).params;order.push(p.action==='source'?p.modelId:p.action);let data; if(p.action==='status')data={source:'old-api/WXAPP',bridgeUsed:false,reviewSyncVersion:'source-owned-v1'}; else if(p.action==='claim')data={runId:'review-sync-test-run',businessDate:'2026-11-02'}; else if(p.action==='supplement')data={accounts:{missing:0},nodes:{missing:0}}; else if(p.action==='source')data={items:[],page:{itemCount:0,pageCount:1}}; else if(p.action==='evidence')data={sourceChecksum:'d41d8cd98f00b204e9800998ecf8427e',targetChecksum:'d41d8cd98f00b204e9800998ecf8427e',reconciled:true}; else if(p.action==='review-income'){ if(!receipts.has(p.batchKey)){applied++;receipts.set(p.batchKey,p.afterTaskId?{processed:0,earned:0,excluded:0,amount:0,pending:1,errors:[{taskId:'z',reason:'来源课次时长仍不明确'}],hasMore:false,afterTaskId:'z'}:{processed:1,earned:1,excluded:0,amount:.5,pending:1,errors:[],hasMore:true,afterTaskId:'a'});} data=receipts.get(p.batchKey);if(!simulatedLostResponse){simulatedLostResponse=true;throw Error('response lost after commit');} } else if(p.action==='finance-members'||p.action==='read')data=[]; else if(p.action==='finish'){final=p.summary;data=p.summary;} else throw Error('Unexpected action '+p.action); return {ok:true,json:async()=>({success:true,data})};}; const result=await runDirectSync({XIAOSHU_SYNC_REPORT_DIR:root,XIAOSHU_SYNC_OPERATOR_TOKEN:'test'}); assert.equal(result.status,'completed-with-preserved-conflicts',result.reason);assert.equal(applied,2);assert.equal(receipts.size,2); assert.equal(final.reviewIncome.earned,1);assert.equal(final.reviewIncome.amount,.5);assert.equal(final.reviewIncome.pending,1);assert.equal(final.conflicts,1);assert.match(final.reviewIncome.errors[0].reason,/时长/); assert(order.lastIndexOf(59)