mobile-course-bindings.test.mjs 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import test from 'node:test';
  2. import assert from 'node:assert/strict';
  3. import vm from 'node:vm';
  4. import { readFileSync } from 'node:fs';
  5. import { PGlite } from '@electric-sql/pglite';
  6. const extension = readFileSync(new URL('../cloud/mobile-teaching.js', import.meta.url), 'utf8');
  7. const gateway = readFileSync(new URL('../deploy-admin-functions.mjs', import.meta.url), 'utf8');
  8. test('学生已分配词库保留待分类和缺少通用记录的历史开通,排除回收、停用及其他学员', async () => {
  9. const db = new PGlite();
  10. try {
  11. await db.exec(`CREATE TABLE "CourseBinding"("objectId" text,company text,id bigint,yhid numeric,kcid text,"enrollmentStatus" text,syjd text,yxx numeric);
  12. CREATE TABLE "CommonModel"(company text,"modelId" int,"itemId" bigint,"generalId" bigint,title text,"createTime" timestamptz,status int);
  13. CREATE TABLE "Node"(company text,"nodeId" numeric,"nodeName" text,zstatus int);
  14. INSERT INTO "Node" VALUES ('co',81,'历史词库',99),('co',82,'停用词库',0),('other',81,'其他帐套',99);`);
  15. const states = ['active', 'pending', null, '', 'recycled', 'disabled', 'active', 'pending', 'pending', 'pending', 'pending'];
  16. for (const [i,state] of states.entries()) {
  17. const id = i + 1;
  18. await db.query('INSERT INTO "CourseBinding" VALUES($1,$2,$3,$4,$5,$6,$7,$8)', [`b${id}`,id===11?'other':'co',id,id===10?43:42,id===9?'82':id===2?'81.0':'81',state,'{"91":"91@已分配单元"}',12]);
  19. if (id !== 8) await db.query('INSERT INTO "CommonModel" VALUES($1,58,$2,$2,$3,now(),$4)', [id===11?'other':'co',id,'已开通词库',id===7?-2:99]);
  20. }
  21. // An explicitly unpublished common record must remain unavailable.
  22. await db.exec(`INSERT INTO "CourseBinding" VALUES('draft','co',12,42,'81','pending','',0); INSERT INTO "CommonModel" VALUES('co',58,12,12,'未发布',now(),0);`);
  23. const context = {
  24. DEFAULT_COMPANY_ID: 'co',
  25. Psql: { query: async (sql,args) => (await db.query(sql,args)).rows },
  26. number: value => Number(value) || 0,
  27. ownLegacyId: current => Number(current.get('legacyUserId')),
  28. };
  29. vm.runInNewContext(extension,context);
  30. const courses = await context.mobileReadableCourseBindings(42);
  31. assert.deepEqual(courses.map(row=>row.bindingObjectId),['b8','b4','b3','b2','b1']);
  32. assert.ok(courses.every(row=>Number(row.yxx)===12 && row.syjd.includes('已分配单元')));
  33. assert.equal(courses.find(row=>row.bindingObjectId==='b2').courseTitle,'历史词库');
  34. const student = {get:key=>({legacyGroupId:1,legacyUserId:42})[key]};
  35. const coach = {get:key=>({legacyGroupId:3,legacyUserId:99})[key]};
  36. assert.equal((await context.mobileUnitBindingRows(42,'b2',81,student)).length,1);
  37. assert.equal((await context.mobileUnitBindingRows(42,'8',81,student)).length,1);
  38. assert.equal((await context.mobileUnitBindingRows(42,'b7',81,student)).length,0);
  39. assert.equal((await context.mobileUnitBindingRows(42,'b5',81,student)).length,0);
  40. assert.equal((await context.mobileUnitBindingRows(42,'b9',82,student)).length,0);
  41. assert.equal((await context.mobileUnitBindingRows(42,'b10',81,student)).length,0);
  42. assert.equal((await context.mobileUnitBindingRows(42,'b2',81,coach)).length,0);
  43. assert.equal((await context.mobileUnitBindingRows(42,'b1',81,coach)).length,1);
  44. assert.equal((await context.mobileUnitBindingRows(43,'b2',81,student)).length,0);
  45. const retained = (await db.query('SELECT "enrollmentStatus",yxx FROM "CourseBinding" WHERE "objectId"=\'b2\'' )).rows[0];
  46. assert.equal(retained.enrollmentStatus,'pending');
  47. assert.equal(Number(retained.yxx),12);
  48. } finally { await db.close(); }
  49. });
  50. test('伴学中心、学习记录和单元入口采用统一的词库读取规则', () => {
  51. const studentOverview = gateway.slice(gateway.indexOf('async function appStudentCompanionOverview'),gateway.indexOf('async function appCompanionOverview'));
  52. const learningOverview = gateway.slice(gateway.indexOf('async function appLearningOverview'),gateway.indexOf('async function appStudentCompanionOverview'));
  53. const unitPage = gateway.slice(gateway.indexOf('async function nodeUnitPage'),gateway.indexOf('function legacyAppRow'));
  54. assert.match(studentOverview,/courses=await mobileReadableCourseBindings\(uid\)/);
  55. assert.match(learningOverview,/mobileReadableCourseBindings\(targetId\)/);
  56. assert.match(unitPage,/mobileUnitBindingRows\(uid,bindingId,parentId,current\)/);
  57. });