learning-report-query.test.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { after, before, test } from 'node:test';
  2. import assert from 'node:assert/strict';
  3. import { readFileSync } from 'node:fs';
  4. import vm from 'node:vm';
  5. import { PGlite } from '@electric-sql/pglite';
  6. const db = new PGlite();
  7. const source = readFileSync(new URL('../deploy-admin-functions.mjs', import.meta.url), 'utf8');
  8. const gateway = {};
  9. vm.createContext(gateway);
  10. vm.runInContext(source.match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1], gateway);
  11. gateway.companyIdOf = () => 'co';
  12. before(async () => {
  13. await db.exec(`
  14. CREATE TABLE "DailyStudyRecord"("objectId" text,"company" text,"id" int,"userId" int,"pl" text,"dsid" text,"dqrq" text,"xxqs" text,"createdAt" timestamptz);
  15. CREATE TABLE "CommonModel"("objectId" text,"company" text,"modelId" int,"itemId" int,"generalId" int,"createTime" timestamptz,"createdAt" timestamptz);
  16. CREATE TABLE "_User"("objectId" text,"company" text,"legacyUserId" int,"legacyUserData" jsonb,"realName" text,"nickname" text,"username" text,"mobile" text);
  17. CREATE TABLE "CourseAppointment"("objectId" text,"company" text,"id" int,"kcid" text,"dszt" text);
  18. CREATE TABLE "Node"("company" text,"nodeId" int,"nodeName" text);
  19. INSERT INTO "DailyStudyRecord" VALUES
  20. ('compact','co',1,20,'30','','20261004','[]','2026-10-04T00:00:00Z'),
  21. ('dashed','co',2,20,'30','','2026-10-04','[]','2026-10-04T00:00:00Z'),
  22. ('slash','co',3,20,'30','','2026/10/03','[]','2026-10-03T00:00:00Z'),
  23. ('fallback','co',4,20,'30','',NULL,'[]','2026-09-30T16:01:00Z'),
  24. ('history','co',5,20,'30','','20260930','[]','2026-09-30T00:00:00Z'),
  25. ('foreign','other',6,20,'30','','20261004','[]','2026-10-04T00:00:00Z');
  26. `);
  27. });
  28. after(() => db.close());
  29. async function rows(filters) {
  30. const query = gateway.learningReportQueryParts({}, { page: 1, pageSize: 20, filters });
  31. return (await db.query('SELECT d."objectId"' + query.from + query.where + ' ORDER BY ' + query.studyDateSql + ' DESC,d."objectId"', query.values)).rows.map(row => row.objectId);
  32. }
  33. test('月份筛选兼容三种日期格式,并按北京时间补齐缺失学习日期', async () => {
  34. assert.deepEqual(await rows({ month: '2026-10' }), ['compact','dashed','slash','fallback']);
  35. });
  36. test('全部月份包含历史记录,保持帐套隔离', async () => {
  37. assert.deepEqual(await rows({ month: '' }), ['compact','dashed','slash','fallback','history']);
  38. });
  39. test('日期范围包含首尾当天,兼容不同保存格式', async () => {
  40. assert.deepEqual(await rows({ dateFrom: '2026-10-03', dateTo: '2026-10-04' }), ['compact','dashed','slash']);
  41. assert.deepEqual(await rows({ month: '2026-09' }), ['history']);
  42. });
  43. test('报表展示与筛选使用同一个学习日期,斜线日期与 UTC 时间不会少一天', () => {
  44. for(const raw of ['20261004','2026-10-04','2026/10/04'])assert.equal(gateway.learningReportProjection({dqrq:raw}).studyDate,'2026-10-04');
  45. assert.equal(gateway.learningReportProjection({recordCreatedAt:'2026-09-30T16:01:00Z'}).studyDate,'2026-10-01');
  46. });