import {test} from 'node:test';import assert from 'node:assert/strict';import {readFileSync} from 'node:fs';import vm from 'node:vm'; const source=readFileSync(new URL('../cloud/lesson-study.js',import.meta.url),'utf8'); test('待确认批次从词库批量补中文释义,保留词序与掌握状态',async()=>{ const calls=[];const context={DEFAULT_COMPANY_ID:'co',assertLessonTenant:()=>{},orderDetailRow:async()=>({szyh:20}),parseArray:v=>Array.isArray(v)?v:JSON.parse(v||'[]'),fail:(_s,m)=>{throw Error(m);},Psql:{oneOrNone:async()=>null,query:async(sql,args)=>{calls.push({sql,args});if(sql.includes('LessonStudyBatch'))return[{batchId:'b',status:'draft',words:[{GeneralID:12,Title:'crop',check:1},{GeneralID:13,Title:'gather',check:2}]},{batchId:'recovered',status:'confirmed',provenance:'user-confirmed-recovery',words:[{GeneralID:14,Title:'church',check:0},{GeneralID:15,Title:'other',jssy:'旧词义',check:0}]}];if(sql.includes('VocabularyWord'))return[{generalId:13,sy:'聚集'},{generalId:12,sy:'庄稼'},{generalId:14,sy:'教堂'}];return[];}}}; vm.createContext(context);vm.runInContext(source,context);const result=await context.appLessonStudy({orderId:'1'},{}); assert.deepEqual(Array.from(result.batches[0].words,w=>[w.Title,w.sy,w.check]),[['crop','庄稼',1],['gather','聚集',2]]); assert.equal(result.batches[1].words[0].sy,'教堂');assert.equal(result.batches[1].words[1].jssy,'旧词义');assert.equal(result.batches[1].words[1].sy,undefined); assert.equal(calls.filter(c=>c.sql.includes('VocabularyWord')).length,1); }); test('真实 SQL 可按单词编号关联词库并恢复含掌握状态的释义',async()=>{ const {PGlite}=await import('@electric-sql/pglite');const db=new PGlite();try{ await db.exec(`CREATE TABLE "LessonStudyBatch"(company text,"orderId" text,"batchId" text,status text,provenance text,"bindingId" text,words jsonb,"updatedAt" timestamptz); CREATE TABLE "CourseBinding"(company text,"objectId" text,kcid text);CREATE TABLE "Node"(company text,"nodeId" numeric,"nodeName" text); CREATE TABLE "DailyStudyRecord"(company text,id numeric,dsid text,"recordScope" text,xxqs text); CREATE TABLE "CommonModel"(company text,"modelId" numeric,"itemId" numeric,"generalId" numeric); CREATE TABLE "VocabularyWord"(company text,id numeric,sy text); INSERT INTO "LessonStudyBatch" VALUES('co','1','recovery','confirmed','user-confirmed-recovery',null,'[{"GeneralID":12,"Title":"crop","check":2}]',now()); INSERT INTO "CommonModel" VALUES('co',52,7,12);INSERT INTO "VocabularyWord" VALUES('co',7,'庄稼');`); const query=async(s,p=[])=>(await db.query(s,p)).rows,context={DEFAULT_COMPANY_ID:'co',assertLessonTenant:()=>{},orderDetailRow:async()=>({szyh:20}),parseArray:v=>Array.isArray(v)?v:JSON.parse(v||'[]'),Psql:{query,oneOrNone:async(s,p)=>(await query(s,p))[0]||null}}; vm.createContext(context);vm.runInContext(source,context);const result=await context.appLessonStudy({orderId:'1'},{});assert.equal(result.batches[0].words[0].sy,'庄稼');assert.equal(result.batches[0].words[0].check,2); }finally{await db.close();} });