|
|
@@ -0,0 +1,50 @@
|
|
|
+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';
|
|
|
+
|
|
|
+const mobile=readFileSync(new URL('../cloud/mobile-teaching.js',import.meta.url),'utf8');
|
|
|
+const gateway=readFileSync(new URL('../deploy-admin-functions.mjs',import.meta.url),'utf8').match(/const appGatewayCode = String.raw`([\s\S]*?)\n`;/)[1].replace("const DEFAULT_COMPANY_ID = '7pIbDBJmKx';","const DEFAULT_COMPANY_ID = 'co';");
|
|
|
+async function fixture(run){
|
|
|
+ const db=new PGlite();try{
|
|
|
+ await db.exec(readFileSync(new URL('./fixtures/teacher-review-schema.sql',import.meta.url),'utf8'));
|
|
|
+ await db.exec(`ALTER TABLE "DailyStudyRecord" ADD COLUMN pl text,ADD COLUMN "canonicalStudyId" text;
|
|
|
+ INSERT INTO "CommonModel"(company,"modelId","generalId","itemId",status,"sourceKey") VALUES('co',56,100,101,99,'legacy:model:56:general:100'),('co',54,200,201,99,'legacy:model:54:general:200');
|
|
|
+ INSERT INTO "DailyStudyRecord"(company,id,learned,xxqs,dsid,"userId",pl) VALUES('co',101,0,'','200',20,'30');
|
|
|
+ INSERT INTO "CourseAppointment" VALUES('co',201,'20','30',NULL,'398','legacy:model:54:general:200');
|
|
|
+ INSERT INTO "Node" VALUES('co',398,'阅读写作');`);
|
|
|
+ const query=async(s,a)=>(await db.query(s,a)).rows;
|
|
|
+ const ctx=vm.createContext({Date,Promise,Parse:{},Psql:{query,one:async(s,a)=>(await query(s,a))[0],oneOrNone:async(s,a)=>(await query(s,a))[0]||null}});
|
|
|
+ vm.runInContext(gateway+'\n'+mobile,ctx);
|
|
|
+ ctx.authorizeRequestedUser=async()=>30;ctx.appOverviewToday=()=> '2026-10-14';ctx.appLiveVersionSnapshot=async()=>({});ctx.legacyStudyRecordWords=async()=>[];ctx.appLearningTarget=async()=>{throw Error('forbidden');};
|
|
|
+ const coach={get:k=>({legacyUserId:30,legacyGroupId:3}[k])};
|
|
|
+ await run({db,ctx,coach});
|
|
|
+ }finally{await db.close();}
|
|
|
+}
|
|
|
+
|
|
|
+test('旧阅读写作398无学段分类时正常列出任务、统计和学员,并能直接进入笔记复习',()=>fixture(async({db,ctx,coach})=>{
|
|
|
+ const page=await ctx.appReviewPage({scope:'today',pageSize:1,includeIncome:false},coach);
|
|
|
+ assert.equal(page.page.itemCount,2);assert.equal(page.items.length,1);assert.equal(page.summary.todayTotal,2);assert.equal(page.summary.todayPending,1);assert.equal(page.students[0].id,'20');
|
|
|
+ const next=await ctx.appReviewPage({scope:'today',page:2,pageSize:1,includeIncome:false},coach);assert.equal(next.items.length,1);
|
|
|
+ const detail=await ctx.recordDetailData({id:100},coach);assert.equal(detail.words.length,0);assert.equal(detail.addon[0].reviewContentMode,'notes');assert.equal(detail.record.__notesReviewSource,undefined);
|
|
|
+ assert.equal((await db.query('SELECT "courseCategoryKey" FROM "CourseAppointment"')).rows[0].courseCategoryKey,null);
|
|
|
+ await assert.rejects(ctx.recordDetailData({id:100},{get:k=>({legacyUserId:99,legacyGroupId:3}[k])}),/forbidden/);
|
|
|
+}));
|
|
|
+
|
|
|
+test('普通空词表、错误学生、未完课、回收和无可信来源的398不得冒充旧写作复习',()=>fixture(async({db,ctx,coach})=>{
|
|
|
+ const reset=`UPDATE "CourseAppointment" SET szyh='20',dszt='30',"courseCategoryKey"=NULL,kcid='398',"sourceKey"='legacy:model:54:general:200';UPDATE "CommonModel" SET status=99,"sourceKey"='legacy:model:54:general:200' WHERE "modelId"=54;`;
|
|
|
+ for(const patch of [
|
|
|
+ `UPDATE "CourseAppointment" SET "courseCategoryKey"='word'`,
|
|
|
+ `UPDATE "CourseAppointment" SET kcid='399'`,
|
|
|
+ `UPDATE "CourseAppointment" SET szyh='21'`,
|
|
|
+ `UPDATE "CourseAppointment" SET dszt='10'`,
|
|
|
+ `UPDATE "CourseAppointment" SET dszt='20'`,
|
|
|
+ `UPDATE "CourseAppointment" SET "sourceKey"='cloud:appointment:new'`,
|
|
|
+ `UPDATE "CommonModel" SET "sourceKey"='cloud:appointment:new' WHERE "modelId"=54`,
|
|
|
+ `UPDATE "CommonModel" SET status=-2 WHERE "modelId"=54`,
|
|
|
+ ]){
|
|
|
+ await db.exec(reset+patch);const page=await ctx.appReviewPage({scope:'today',includeIncome:false},coach);assert.equal(page.items.length,0,patch);assert.equal(page.summary.todayTotal,0,patch);assert.equal(page.students.length,0,patch);
|
|
|
+ const detail=await ctx.recordDetailData({id:100},coach);assert.equal(detail.addon[0].reviewContentMode,undefined,patch);
|
|
|
+ }
|
|
|
+}));
|