member-groups.test.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import test from 'node:test';
  2. import assert from 'node:assert/strict';
  3. import { indexBoardMembers, seedMemberGroups, changeMemberGroups } from '../src/core/member-groups.js';
  4. import { buildModel } from '../src/core/kfs/build.js';
  5. import { MemberGroupService } from '../src/services/member-groups.js';
  6. const raw = () => ({ session: [
  7. { objectId: 's1', studentName: '原昵称', groupId: 'G1', meta: { participantKey: 'participant:old1' }, employee: { key: 'channel-employee:stable', displayName: '小智' } },
  8. { objectId: 's2', studentName: '另一昵称', groupId: 'G1', meta: { participantKey: 'participant:old2' }, employee: { key: 'channel-employee:stable', displayName: '小智' } },
  9. { objectId: 's3', studentName: '小智', groupId: 'G2', meta: { participantKey: 'participant:other' } },
  10. ], artifact: [{ objectId: 'a1', ownerName: '原昵称', uploadedByKey: 'participant:old1', ownerSession: 's1' }],
  11. project: [{ objectId: 'p1', ownerName: '原昵称', uploadedByKey: 'participant:old2', ownerSession: 's2' }],
  12. opportunity: [{ objectId: 'o1', title: '机会', uploadedBy: '原昵称', uploadedByKey: 'participant:old1', sourceSession: 's1' }] });
  13. test('同一员工跨会话、旧键与昵称仍归同人,同名其他身份不合并', () => {
  14. const input = raw(), db = buildModel(input);
  15. assert.equal(db.members.length, 2);
  16. const m = db.memberById['channel-employee:stable'];
  17. assert.equal(m.name, '小智(G1)');assert.deepEqual(m.sessionIds, ['s1','s2']);
  18. assert.deepEqual(m.artifactIds, ['a1']);assert.deepEqual(m.projectIds, ['p1']);assert.deepEqual(m.oppIds, ['o1']);
  19. assert.equal(db.memberById['participant:other'].name, '小智(G2)');
  20. const renamed = raw();renamed.session[0].employee.displayName = '新称呼';renamed.session[1].employee.displayName = '新称呼';
  21. assert.equal(indexBoardMembers(renamed).members[0].id, m.id);
  22. assert.equal(input.artifact[0].ownerName, '原昵称');
  23. });
  24. test('姓名补充不能改变旧数据的分组编号,前端与服务端成员索引逐项一致', () => {
  25. const input = { session: [
  26. { objectId: 's1', studentName: '陈静', groupId: 'G1' },
  27. { objectId: 's2', studentName: '陈静', groupId: 'G1', meta: { participantKey: 'legacy-account-1' } },
  28. ], artifact: [{ objectId: 'a1', ownerName: '陈静', ownerSession: 's1', uploadedByKey: 'legacy-account-2' }],
  29. project: [], opportunity: [] };
  30. const directory = indexBoardMembers(input), db = buildModel(input);
  31. assert.deepEqual(db.members.map((m) => m.id).sort(), directory.members.map((m) => m.id).sort());
  32. assert.equal(db.members.length, 1);
  33. assert.equal(db.members[0].name, '陈静');
  34. assert.equal(seedMemberGroups(db.members).assignments[db.members[0].id], 'legacy-group:G1');
  35. });
  36. test('分组名独立于成员身份,重命名不改归属,删除只移回未分组', () => {
  37. const members = indexBoardMembers(raw()).members, ids = new Set(members.map((m) => m.id));
  38. const state = seedMemberGroups(members), before = JSON.stringify(members);
  39. const assigned = changeMemberGroups(state, { action: 'assign', groupId: state.groups[1].id, memberIds: [...ids] }, ids);
  40. const renamed = changeMemberGroups(assigned, { action: 'rename', groupId: state.groups[1].id, name: '新品研发' }, ids);
  41. assert.equal(renamed.groups[1].name, '新品研发');assert.deepEqual(renamed.assignments, assigned.assignments);
  42. const deleted = changeMemberGroups(renamed, { action: 'delete', groupId: state.groups[1].id }, ids);
  43. assert.equal(Object.keys(deleted.assignments).length, 0);assert.equal(JSON.stringify(members), before);
  44. assert.equal(state.revision, 0);
  45. });
  46. test('重复、空白、保留名、长名及未知成员不会产生有效分组变更', () => {
  47. const members = indexBoardMembers(raw()).members, ids = new Set(members.map((m) => m.id)), state = seedMemberGroups(members);
  48. for (const name of ['G1',' G1 ','', '未分组','全部成员','字'.repeat(31)]) assert.throws(() => changeMemberGroups(state, { action:'create',name }, ids, 'new'), { code:'VALIDATION_FAILED' });
  49. assert.throws(() => changeMemberGroups(state, { action:'assign',groupId:state.groups[0].id,memberIds:[members[0].id,'private-person'] }, ids), { code:'VALIDATION_FAILED' });
  50. assert.equal(state.revision, 0);
  51. });
  52. test('分组服务发送版本与稳定编号,网络异常不自动重试', async () => {
  53. let calls=0;
  54. const service = new MemberGroupService({ url:'/fixture',call:async (input) => { calls++;assert.equal(input.name,'ksfManagePublicMemberGroups');assert.equal(input.params.expectedRevision,3);assert.equal(input.params.requestId,'same');throw Error('timeout'); } });
  55. await assert.rejects(() => service.change({revision:3},{action:'assign',memberIds:['employee:one'],groupId:null},'same'),/timeout/);
  56. assert.equal(calls,1);
  57. });