952a0e9b49
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127 lines
4.8 KiB
TypeScript
127 lines
4.8 KiB
TypeScript
import { WhatsAppSessionPool } from './session-pool';
|
|
|
|
// Mock createWhatsAppSession so we don't need a real WhatsApp connection
|
|
jest.mock('./session', () => ({
|
|
createWhatsAppSession: jest.fn().mockResolvedValue({
|
|
sendMessage: jest.fn().mockResolvedValue({}),
|
|
logout: jest.fn().mockResolvedValue({}),
|
|
end: jest.fn(),
|
|
}),
|
|
}));
|
|
|
|
describe('WhatsAppSessionPool', () => {
|
|
let pool: WhatsAppSessionPool;
|
|
|
|
beforeEach(() => {
|
|
pool = new WhatsAppSessionPool();
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
it('add() stores a session by accountId', async () => {
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn());
|
|
expect(pool.get('acc_1')).toBeDefined();
|
|
});
|
|
|
|
it('get() returns undefined for unknown accountId', () => {
|
|
expect(pool.get('acc_unknown')).toBeUndefined();
|
|
});
|
|
|
|
it('getAll() returns the sessions map', async () => {
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn());
|
|
expect(pool.getAll().size).toBe(1);
|
|
expect(pool.getAll().has('acc_1')).toBe(true);
|
|
});
|
|
|
|
it('sendMessage() throws with informative error when no session exists', async () => {
|
|
await expect(pool.sendMessage('acc_missing', '1234@g.us', 'hello')).rejects.toThrow(
|
|
'No active session for account acc_missing',
|
|
);
|
|
});
|
|
|
|
it('sendMessage() includes available accounts in error when others exist', async () => {
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn());
|
|
await expect(pool.sendMessage('acc_missing', '1234@g.us', 'hello')).rejects.toThrow(
|
|
'Active accounts: [acc_1]',
|
|
);
|
|
});
|
|
|
|
it('remove() removes session from pool', async () => {
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn());
|
|
expect(pool.get('acc_1')).toBeDefined();
|
|
await pool.remove('acc_1');
|
|
expect(pool.get('acc_1')).toBeUndefined();
|
|
});
|
|
|
|
it('remove() is a no-op for unknown accountId', async () => {
|
|
await expect(pool.remove('acc_unknown')).resolves.not.toThrow();
|
|
});
|
|
|
|
it('closeAll() calls end() on all sessions and clears the pool', async () => {
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn());
|
|
await pool.add('acc_2', './sessions/2', jest.fn(), jest.fn(), jest.fn());
|
|
expect(pool.getAll().size).toBe(2);
|
|
|
|
const sock1 = pool.get('acc_1')!;
|
|
const sock2 = pool.get('acc_2')!;
|
|
|
|
await pool.closeAll();
|
|
|
|
expect(sock1.end).toHaveBeenCalledWith(expect.objectContaining({ message: 'Shutdown' }));
|
|
expect(sock2.end).toHaveBeenCalledWith(expect.objectContaining({ message: 'Shutdown' }));
|
|
expect(pool.getAll().size).toBe(0);
|
|
});
|
|
|
|
it('add() injects accountId into onMessage callback', async () => {
|
|
const onMessage = jest.fn();
|
|
const { createWhatsAppSession } = require('./session');
|
|
|
|
let capturedOnMessage: any;
|
|
(createWhatsAppSession as jest.Mock).mockImplementationOnce(
|
|
(_accountId: string, _path: string, cb: any) => {
|
|
capturedOnMessage = cb;
|
|
return Promise.resolve({ sendMessage: jest.fn(), logout: jest.fn() });
|
|
},
|
|
);
|
|
|
|
await pool.add('acc_1', './sessions/1', onMessage, jest.fn(), jest.fn());
|
|
|
|
const fakeMsg = { platformMsgId: 'abc', content: 'hi', sourceGroupJid: '1@g.us', senderJid: '2@s.whatsapp.net', accountId: 'acc_1' };
|
|
await capturedOnMessage(fakeMsg);
|
|
expect(onMessage).toHaveBeenCalledWith(fakeMsg, 'acc_1');
|
|
});
|
|
|
|
it('add() injects accountId into onQr callback', async () => {
|
|
const onQr = jest.fn();
|
|
const { createWhatsAppSession } = require('./session');
|
|
|
|
let capturedOnQr: any;
|
|
(createWhatsAppSession as jest.Mock).mockImplementationOnce(
|
|
(_id: string, _path: string, _onMsg: any, _onReaction: any, _onGroups: any, _onReconnect: any, qrCb: any) => {
|
|
capturedOnQr = qrCb;
|
|
return Promise.resolve({ sendMessage: jest.fn(), logout: jest.fn(), end: jest.fn() });
|
|
},
|
|
);
|
|
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn(), onQr);
|
|
await capturedOnQr('test-qr');
|
|
expect(onQr).toHaveBeenCalledWith('test-qr', 'acc_1');
|
|
});
|
|
|
|
it('add() injects accountId and jid into onStatus callback', async () => {
|
|
const onStatus = jest.fn();
|
|
const { createWhatsAppSession } = require('./session');
|
|
|
|
let capturedOnStatus: any;
|
|
(createWhatsAppSession as jest.Mock).mockImplementationOnce(
|
|
(_id: string, _path: string, _onMsg: any, _onReaction: any, _onGroups: any, _onReconnect: any, _onQr: any, statusCb: any) => {
|
|
capturedOnStatus = statusCb;
|
|
return Promise.resolve({ sendMessage: jest.fn(), logout: jest.fn(), end: jest.fn() });
|
|
},
|
|
);
|
|
|
|
await pool.add('acc_1', './sessions/1', jest.fn(), jest.fn(), jest.fn(), undefined, onStatus);
|
|
await capturedOnStatus('connected', '1234@s.whatsapp.net');
|
|
expect(onStatus).toHaveBeenCalledWith('connected', 'acc_1', '1234@s.whatsapp.net');
|
|
});
|
|
});
|