64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
import { test } from 'node:test';
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { declineInvite } from './matrix';
|
||
|
|
|
||
|
|
// declineInvite must only leave when we're still in the room (invite/join/knock)
|
||
|
|
// — re-leaving an already-left remote room is what Synapse 500s on — and must
|
||
|
|
// always forget afterwards (best-effort) so the ghost invite can't linger.
|
||
|
|
const makeMx = (
|
||
|
|
membership: string | undefined,
|
||
|
|
opts: { leaveRejects?: boolean; forgetRejects?: boolean } = {},
|
||
|
|
) => {
|
||
|
|
const calls: string[] = [];
|
||
|
|
const mx = {
|
||
|
|
getRoom: () => (membership === undefined ? null : { getMyMembership: () => membership }),
|
||
|
|
leave: async () => {
|
||
|
|
calls.push('leave');
|
||
|
|
if (opts.leaveRejects) throw new Error('leave failed');
|
||
|
|
return {};
|
||
|
|
},
|
||
|
|
forget: async () => {
|
||
|
|
calls.push('forget');
|
||
|
|
if (opts.forgetRejects) throw new Error('forget failed');
|
||
|
|
return {};
|
||
|
|
},
|
||
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
|
} as any;
|
||
|
|
return { mx, calls };
|
||
|
|
};
|
||
|
|
|
||
|
|
test('declineInvite: invite → leave then forget', async () => {
|
||
|
|
const { mx, calls } = makeMx('invite');
|
||
|
|
await declineInvite(mx, '!r:s');
|
||
|
|
assert.deepEqual(calls, ['leave', 'forget']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('declineInvite: already left → skips leave, still forgets (no double-leave 500)', async () => {
|
||
|
|
const { mx, calls } = makeMx('leave');
|
||
|
|
await declineInvite(mx, '!r:s');
|
||
|
|
assert.deepEqual(calls, ['forget']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('declineInvite: join → leave then forget', async () => {
|
||
|
|
const { mx, calls } = makeMx('join');
|
||
|
|
await declineInvite(mx, '!r:s');
|
||
|
|
assert.deepEqual(calls, ['leave', 'forget']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('declineInvite: no room object → only forget', async () => {
|
||
|
|
const { mx, calls } = makeMx(undefined);
|
||
|
|
await declineInvite(mx, '!r:s');
|
||
|
|
assert.deepEqual(calls, ['forget']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('declineInvite: forget failure is swallowed (best-effort)', async () => {
|
||
|
|
const { mx, calls } = makeMx('invite', { forgetRejects: true });
|
||
|
|
await declineInvite(mx, '!r:s'); // resolves despite forget throwing
|
||
|
|
assert.deepEqual(calls, ['leave', 'forget']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('declineInvite: genuine leave failure rejects', async () => {
|
||
|
|
const { mx } = makeMx('invite', { leaveRejects: true });
|
||
|
|
await assert.rejects(() => declineInvite(mx, '!r:s'), /leave failed/);
|
||
|
|
});
|