| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import { Agent } from './api/models';
- import { checkLeaderMembership, diagnoseLeader } from './leader-membership';
- /**
- * 组长是否在群里。
- *
- * 实测:组长 `lj` 报告「派活已发到群里」,但查群成员发现它压根不在,
- * 40 分钟组员没开工。它在自己的私聊房间里自言自语。
- */
- describe('leader-membership', () => {
- const LEADER = '@lj:fmode.cn';
- const MEMBER = '@lj-test:fmode.cn';
- const ME = '@me:fmode.cn';
- function agent(name: string, mxId?: string): Agent {
- return {
- id: name,
- name,
- status: 'idle',
- matrixReady: true,
- unread: 0,
- channels: mxId ? { matrix: true, matrixConfig: { userId: mxId } } : undefined,
- };
- }
- describe('checkLeaderMembership', () => {
- it('组长在成员列表里 → 正常', () => {
- const r = checkLeaderMembership(LEADER, [ME, MEMBER, LEADER], 'lj');
- expect(r.state).toBe('in-room');
- expect(r.warn).toBeFalse();
- });
- it('🔴 组长不在成员列表里 → 严重提示(实测踩过的坑)', () => {
- const r = checkLeaderMembership(LEADER, [ME, MEMBER], 'lj');
- expect(r.state).toBe('not-in-room');
- expect(r.warn).toBeTrue();
- expect(r.message).toContain('不在这个群里');
- expect(r.message).toContain('lj');
- });
- it('提示要说明「它说的已派活不会真发到群里」', () => {
- const r = checkLeaderMembership(LEADER, [ME], 'lj');
- expect(r.message).toContain('已派活');
- });
- it('成员列表为空 → unknown(启动瞬间不误报)', () => {
- const r = checkLeaderMembership(LEADER, [], 'lj');
- expect(r.state).toBe('unknown');
- expect(r.warn).toBeFalse();
- });
- it('没有组长 mxId → unknown(不误报)', () => {
- const r = checkLeaderMembership(undefined, [ME], 'lj');
- expect(r.state).toBe('unknown');
- expect(r.warn).toBeFalse();
- });
- });
- describe('diagnoseLeader', () => {
- it('🔴 不在群 → 直接判定,不看发言数', () => {
- const r = diagnoseLeader(agent('lj', LEADER), [ME, MEMBER], 0);
- expect(r.state).toBe('not-in-room');
- expect(r.warn).toBeTrue();
- });
- it('🔴 在群但一条没说过 → 提示可能没收到需求', () => {
- const r = diagnoseLeader(agent('lj', LEADER), [ME, LEADER], 0);
- expect(r.warn).toBeTrue();
- expect(r.message).toContain('还没说过话');
- });
- it('在群且说过话 → 正常', () => {
- const r = diagnoseLeader(agent('lj', LEADER), [ME, LEADER], 5);
- expect(r.warn).toBeFalse();
- });
- it('组长没有 Matrix 身份 → unknown', () => {
- const r = diagnoseLeader(agent('lj'), [ME], 0);
- expect(r.state).toBe('unknown');
- expect(r.warn).toBeFalse();
- });
- });
- describe('🔴 回归:解析 SDK 返回结构(曾误报「组长不在群」)', () => {
- // matrix-js-sdk 的 getJoinedRoomMembers 返回的是 { joined: {...} },
- // 直接 Object.keys 会拿到 ["joined"] —— 导致永远判「不在群」
- function parseLike(mx: unknown): string[] {
- const obj = mx as Record<string, unknown>;
- const inner = (obj && typeof obj['joined'] === 'object' ? obj['joined'] : obj) as
- | Record<string, unknown>
- | undefined;
- if (!inner || typeof inner !== 'object') return [];
- return Object.keys(inner);
- }
- it('SDK 的真实结构 {joined:{}} → 正确解析出成员', () => {
- const raw = {
- joined: {
- '@lj:fmode.cn': { display_name: 'lj' },
- '@me:fmode.cn': { display_name: 'me' },
- },
- };
- expect(parseLike(raw)).toEqual(['@lj:fmode.cn', '@me:fmode.cn']);
- });
- it('🔴 不能把 ["joined"] 当成成员列表', () => {
- const raw = { joined: { '@lj:fmode.cn': {} } };
- expect(parseLike(raw)).not.toContain('joined');
- });
- it('已经是直接 map 的形态也能处理(兼容)', () => {
- expect(parseLike({ '@lj:fmode.cn': {} })).toEqual(['@lj:fmode.cn']);
- });
- it('异常输入 → 空数组,不崩', () => {
- expect(parseLike(null)).toEqual([]);
- expect(parseLike({ joined: null })).toEqual([]);
- });
- it('解析正确 + 组长在里面 → 不误报', () => {
- const raw = { joined: { '@lj:fmode.cn': {}, '@me:fmode.cn': {} } };
- const ids = parseLike(raw);
- const r = checkLeaderMembership('@lj:fmode.cn', ids, 'lj');
- expect(r.state).toBe('in-room');
- expect(r.warn).toBeFalse();
- });
- });
- });
|