signal-sdk 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +184 -61
  2. package/dist/MultiAccountManager.d.ts +149 -0
  3. package/dist/MultiAccountManager.js +320 -0
  4. package/dist/SignalBot.d.ts +1 -0
  5. package/dist/SignalBot.js +20 -2
  6. package/dist/SignalCli.d.ts +315 -16
  7. package/dist/SignalCli.js +880 -26
  8. package/dist/__tests__/MultiAccountManager.test.d.ts +4 -0
  9. package/dist/__tests__/MultiAccountManager.test.js +209 -0
  10. package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
  11. package/dist/__tests__/SignalBot.additional.test.js +353 -0
  12. package/dist/__tests__/SignalBot.test.js +5 -0
  13. package/dist/__tests__/SignalCli.advanced.test.d.ts +5 -0
  14. package/dist/__tests__/SignalCli.advanced.test.js +295 -0
  15. package/dist/__tests__/SignalCli.e2e.test.d.ts +5 -0
  16. package/dist/__tests__/SignalCli.e2e.test.js +240 -0
  17. package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
  18. package/dist/__tests__/SignalCli.integration.test.js +225 -0
  19. package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
  20. package/dist/__tests__/SignalCli.methods.test.js +556 -0
  21. package/dist/__tests__/SignalCli.parsing.test.d.ts +5 -0
  22. package/dist/__tests__/SignalCli.parsing.test.js +258 -0
  23. package/dist/__tests__/SignalCli.test.js +249 -13
  24. package/dist/__tests__/config.test.d.ts +5 -0
  25. package/dist/__tests__/config.test.js +252 -0
  26. package/dist/__tests__/errors.test.d.ts +5 -0
  27. package/dist/__tests__/errors.test.js +276 -0
  28. package/dist/__tests__/retry.test.d.ts +4 -0
  29. package/dist/__tests__/retry.test.js +123 -0
  30. package/dist/__tests__/validators.test.d.ts +4 -0
  31. package/dist/__tests__/validators.test.js +147 -0
  32. package/dist/config.d.ts +82 -0
  33. package/dist/config.js +116 -0
  34. package/dist/errors.d.ts +32 -0
  35. package/dist/errors.js +75 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.js +7 -1
  38. package/dist/interfaces.d.ts +200 -10
  39. package/dist/interfaces.js +1 -1
  40. package/dist/retry.d.ts +56 -0
  41. package/dist/retry.js +152 -0
  42. package/dist/validators.d.ts +59 -0
  43. package/dist/validators.js +170 -0
  44. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for MultiAccountManager
3
+ */
4
+ export {};
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for MultiAccountManager
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const MultiAccountManager_1 = require("../MultiAccountManager");
7
+ const SignalCli_1 = require("../SignalCli");
8
+ // Mock SignalCli
9
+ jest.mock('../SignalCli');
10
+ describe('MultiAccountManager', () => {
11
+ let manager;
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+ manager = new MultiAccountManager_1.MultiAccountManager({
15
+ dataPath: '/tmp/test-data',
16
+ verbose: false
17
+ });
18
+ });
19
+ afterEach(async () => {
20
+ if (manager) {
21
+ await manager.shutdown();
22
+ }
23
+ });
24
+ describe('Account Management', () => {
25
+ it('should add an account', async () => {
26
+ const instance = await manager.addAccount('+33123456789');
27
+ expect(instance).toBeInstanceOf(SignalCli_1.SignalCli);
28
+ expect(manager.hasAccount('+33123456789')).toBe(true);
29
+ expect(manager.getAccounts()).toContain('+33123456789');
30
+ });
31
+ it('should emit accountAdded event', async () => {
32
+ const spy = jest.fn();
33
+ manager.on('accountAdded', spy);
34
+ await manager.addAccount('+33123456789');
35
+ expect(spy).toHaveBeenCalledWith('+33123456789');
36
+ });
37
+ it('should throw error when adding duplicate account', async () => {
38
+ await manager.addAccount('+33123456789');
39
+ await expect(manager.addAccount('+33123456789')).rejects.toThrow('Account +33123456789 already exists');
40
+ });
41
+ it('should remove an account', async () => {
42
+ await manager.addAccount('+33123456789');
43
+ await manager.removeAccount('+33123456789');
44
+ expect(manager.hasAccount('+33123456789')).toBe(false);
45
+ expect(manager.getAccounts()).not.toContain('+33123456789');
46
+ });
47
+ it('should emit accountRemoved event', async () => {
48
+ const spy = jest.fn();
49
+ await manager.addAccount('+33123456789');
50
+ manager.on('accountRemoved', spy);
51
+ await manager.removeAccount('+33123456789');
52
+ expect(spy).toHaveBeenCalledWith('+33123456789');
53
+ });
54
+ it('should throw error when removing non-existent account', async () => {
55
+ await expect(manager.removeAccount('+33123456789')).rejects.toThrow('Account +33123456789 not found');
56
+ });
57
+ it('should get specific account instance', async () => {
58
+ await manager.addAccount('+33123456789');
59
+ const instance = manager.getAccount('+33123456789');
60
+ expect(instance).toBeInstanceOf(SignalCli_1.SignalCli);
61
+ });
62
+ it('should return undefined for non-existent account', () => {
63
+ const instance = manager.getAccount('+33999999999');
64
+ expect(instance).toBeUndefined();
65
+ });
66
+ it('should get all account numbers', async () => {
67
+ await manager.addAccount('+33123456789');
68
+ await manager.addAccount('+33987654321');
69
+ const accounts = manager.getAccounts();
70
+ expect(accounts).toHaveLength(2);
71
+ expect(accounts).toContain('+33123456789');
72
+ expect(accounts).toContain('+33987654321');
73
+ });
74
+ });
75
+ describe('Connection Management', () => {
76
+ it('should connect a specific account', async () => {
77
+ const instance = await manager.addAccount('+33123456789');
78
+ instance.connect = jest.fn().mockResolvedValue(undefined);
79
+ await manager.connect('+33123456789');
80
+ expect(instance.connect).toHaveBeenCalled();
81
+ });
82
+ it('should emit accountConnected event', async () => {
83
+ const instance = await manager.addAccount('+33123456789');
84
+ instance.connect = jest.fn().mockResolvedValue(undefined);
85
+ const spy = jest.fn();
86
+ manager.on('accountConnected', spy);
87
+ await manager.connect('+33123456789');
88
+ expect(spy).toHaveBeenCalledWith('+33123456789');
89
+ });
90
+ it('should disconnect a specific account', async () => {
91
+ const instance = await manager.addAccount('+33123456789');
92
+ instance.connect = jest.fn().mockResolvedValue(undefined);
93
+ instance.disconnect = jest.fn().mockResolvedValue(undefined);
94
+ await manager.connect('+33123456789');
95
+ await manager.disconnect('+33123456789');
96
+ expect(instance.disconnect).toHaveBeenCalled();
97
+ });
98
+ it('should emit accountDisconnected event', async () => {
99
+ const instance = await manager.addAccount('+33123456789');
100
+ instance.connect = jest.fn().mockResolvedValue(undefined);
101
+ instance.disconnect = jest.fn().mockResolvedValue(undefined);
102
+ const spy = jest.fn();
103
+ await manager.connect('+33123456789');
104
+ manager.on('accountDisconnected', spy);
105
+ await manager.disconnect('+33123456789');
106
+ expect(spy).toHaveBeenCalledWith('+33123456789');
107
+ });
108
+ it('should connect all accounts', async () => {
109
+ const instance1 = await manager.addAccount('+33123456789');
110
+ const instance2 = await manager.addAccount('+33987654321');
111
+ instance1.connect = jest.fn().mockResolvedValue(undefined);
112
+ instance2.connect = jest.fn().mockResolvedValue(undefined);
113
+ await manager.connectAll();
114
+ expect(instance1.connect).toHaveBeenCalled();
115
+ expect(instance2.connect).toHaveBeenCalled();
116
+ });
117
+ it('should disconnect all accounts', async () => {
118
+ const instance1 = await manager.addAccount('+33123456789');
119
+ const instance2 = await manager.addAccount('+33987654321');
120
+ instance1.connect = jest.fn().mockResolvedValue(undefined);
121
+ instance2.connect = jest.fn().mockResolvedValue(undefined);
122
+ instance1.disconnect = jest.fn().mockResolvedValue(undefined);
123
+ instance2.disconnect = jest.fn().mockResolvedValue(undefined);
124
+ await manager.connectAll();
125
+ await manager.disconnectAll();
126
+ expect(instance1.disconnect).toHaveBeenCalled();
127
+ expect(instance2.disconnect).toHaveBeenCalled();
128
+ });
129
+ it('should handle connection errors gracefully', async () => {
130
+ const instance = await manager.addAccount('+33123456789');
131
+ instance.connect = jest.fn().mockRejectedValue(new Error('Connection failed'));
132
+ await expect(manager.connect('+33123456789')).rejects.toThrow('Connection failed');
133
+ });
134
+ });
135
+ describe('Message Sending', () => {
136
+ it('should send message from specific account', async () => {
137
+ const instance = await manager.addAccount('+33123456789');
138
+ instance.sendMessage = jest.fn().mockResolvedValue({
139
+ timestamp: Date.now(),
140
+ results: []
141
+ });
142
+ await manager.sendMessage('+33123456789', '+33111111111', 'Hello!');
143
+ expect(instance.sendMessage).toHaveBeenCalledWith('+33111111111', 'Hello!', {});
144
+ });
145
+ it('should throw error when sending from non-existent account', async () => {
146
+ await expect(manager.sendMessage('+33999999999', '+33111111111', 'Hello!')).rejects.toThrow('Account +33999999999 not found');
147
+ });
148
+ it('should send message with options', async () => {
149
+ const instance = await manager.addAccount('+33123456789');
150
+ instance.sendMessage = jest.fn().mockResolvedValue({
151
+ timestamp: Date.now(),
152
+ results: []
153
+ });
154
+ const options = { attachments: ['file.jpg'] };
155
+ await manager.sendMessage('+33123456789', '+33111111111', 'Hello!', options);
156
+ expect(instance.sendMessage).toHaveBeenCalledWith('+33111111111', 'Hello!', options);
157
+ });
158
+ });
159
+ describe('Event Forwarding', () => {
160
+ it('should setup event forwarding on account addition', async () => {
161
+ const instance = await manager.addAccount('+33123456789');
162
+ // Verify instance was created
163
+ expect(instance).toBeDefined();
164
+ expect(manager.hasAccount('+33123456789')).toBe(true);
165
+ });
166
+ });
167
+ describe('Status Information', () => {
168
+ it('should get status for specific account', async () => {
169
+ await manager.addAccount('+33123456789');
170
+ const status = manager.getStatus('+33123456789');
171
+ expect(status).toHaveProperty('account', '+33123456789');
172
+ expect(status).toHaveProperty('connected', false);
173
+ expect(status).toHaveProperty('lastActivity');
174
+ expect(status).toHaveProperty('uptime');
175
+ });
176
+ it('should return null for non-existent account status', () => {
177
+ const status = manager.getStatus('+33999999999');
178
+ expect(status).toBeNull();
179
+ });
180
+ it('should get status for all accounts', async () => {
181
+ await manager.addAccount('+33123456789');
182
+ await manager.addAccount('+33987654321');
183
+ const status = manager.getStatus();
184
+ expect(status.totalAccounts).toBe(2);
185
+ expect(status.connectedAccounts).toBe(0);
186
+ expect(status.accounts).toHaveLength(2);
187
+ });
188
+ it('should update connected count in status', async () => {
189
+ const instance = await manager.addAccount('+33123456789');
190
+ jest.spyOn(instance, 'connect').mockResolvedValue();
191
+ await manager.connect('+33123456789');
192
+ const status = manager.getStatus();
193
+ expect(status.connectedAccounts).toBe(1);
194
+ });
195
+ });
196
+ describe('Shutdown', () => {
197
+ it('should shutdown and cleanup all accounts', async () => {
198
+ const instance1 = await manager.addAccount('+33123456789');
199
+ const instance2 = await manager.addAccount('+33987654321');
200
+ instance1.connect = jest.fn().mockResolvedValue(undefined);
201
+ instance2.connect = jest.fn().mockResolvedValue(undefined);
202
+ instance1.disconnect = jest.fn().mockResolvedValue(undefined);
203
+ instance2.disconnect = jest.fn().mockResolvedValue(undefined);
204
+ await manager.connectAll();
205
+ await manager.shutdown();
206
+ expect(manager.getAccounts()).toHaveLength(0);
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Additional tests for SignalBot
3
+ * Covers message handling, commands, and edge cases
4
+ */
5
+ export {};
@@ -0,0 +1,353 @@
1
+ "use strict";
2
+ /**
3
+ * Additional tests for SignalBot
4
+ * Covers message handling, commands, and edge cases
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const SignalBot_1 = require("../SignalBot");
8
+ describe('SignalBot Additional Tests', () => {
9
+ let bot;
10
+ let mockConfig;
11
+ beforeEach(() => {
12
+ // Use real timers for these tests
13
+ jest.useRealTimers();
14
+ mockConfig = {
15
+ phoneNumber: '+1234567890',
16
+ admins: ['+0987654321'],
17
+ settings: {
18
+ commandPrefix: '/',
19
+ autoReact: true,
20
+ logMessages: true,
21
+ welcomeNewMembers: true,
22
+ cooldownSeconds: 2,
23
+ maxMessageLength: 1000
24
+ }
25
+ };
26
+ });
27
+ afterEach(async () => {
28
+ if (bot) {
29
+ await bot.stop();
30
+ // Remove all listeners to prevent memory leaks
31
+ bot.removeAllListeners();
32
+ bot.getSignalCli().removeAllListeners();
33
+ // Wait a bit for any async operations to complete
34
+ await new Promise(resolve => process.nextTick(resolve));
35
+ }
36
+ });
37
+ describe('Command Management', () => {
38
+ test('should add custom command and execute it', () => {
39
+ bot = new SignalBot_1.SignalBot(mockConfig);
40
+ const customHandler = jest.fn().mockResolvedValue('Custom response');
41
+ bot.addCommand({
42
+ name: 'custom',
43
+ description: 'Custom command',
44
+ handler: customHandler
45
+ });
46
+ const commands = bot.getCommands();
47
+ expect(commands.find(c => c.name === 'custom')).toBeDefined();
48
+ });
49
+ test('should remove command successfully', () => {
50
+ bot = new SignalBot_1.SignalBot(mockConfig);
51
+ bot.addCommand({
52
+ name: 'temp',
53
+ description: 'Temporary command',
54
+ handler: async () => 'temp'
55
+ });
56
+ expect(bot.removeCommand('temp')).toBe(true);
57
+ expect(bot.removeCommand('nonexistent')).toBe(false);
58
+ });
59
+ test('should prevent duplicate commands', () => {
60
+ bot = new SignalBot_1.SignalBot(mockConfig);
61
+ bot.addCommand({
62
+ name: 'test',
63
+ description: 'Test command',
64
+ handler: async () => 'test1'
65
+ });
66
+ bot.addCommand({
67
+ name: 'test',
68
+ description: 'Test command 2',
69
+ handler: async () => 'test2'
70
+ });
71
+ const commands = bot.getCommands();
72
+ const testCommands = commands.filter(c => c.name === 'test');
73
+ expect(testCommands.length).toBe(1);
74
+ });
75
+ });
76
+ describe('Admin Management', () => {
77
+ test('should identify admin correctly', () => {
78
+ bot = new SignalBot_1.SignalBot(mockConfig);
79
+ expect(bot.isAdmin('+0987654321')).toBe(true);
80
+ expect(bot.isAdmin('+1111111111')).toBe(false);
81
+ });
82
+ });
83
+ describe('Statistics', () => {
84
+ test('should track bot statistics', () => {
85
+ bot = new SignalBot_1.SignalBot(mockConfig);
86
+ const stats = bot.getStats();
87
+ expect(stats).toHaveProperty('messagesReceived');
88
+ expect(stats).toHaveProperty('commandsExecuted');
89
+ expect(stats).toHaveProperty('startTime');
90
+ expect(stats).toHaveProperty('lastActivity');
91
+ expect(stats.messagesReceived).toBe(0);
92
+ expect(stats.commandsExecuted).toBe(0);
93
+ });
94
+ });
95
+ describe('Group Management', () => {
96
+ test('should get bot group ID', () => {
97
+ bot = new SignalBot_1.SignalBot(mockConfig);
98
+ const groupId = bot.getBotGroupId();
99
+ expect(groupId).toBeNull(); // Not set until bot starts
100
+ });
101
+ test('should create bot without group config', () => {
102
+ bot = new SignalBot_1.SignalBot({
103
+ phoneNumber: '+1234567890'
104
+ });
105
+ expect(bot).toBeDefined();
106
+ expect(bot.getBotGroupId()).toBeNull();
107
+ });
108
+ test('should create bot with group config', () => {
109
+ bot = new SignalBot_1.SignalBot({
110
+ phoneNumber: '+1234567890',
111
+ group: {
112
+ name: 'Test Group',
113
+ description: 'Test Description',
114
+ createIfNotExists: true,
115
+ initialMembers: ['+1111111111', '+2222222222']
116
+ }
117
+ });
118
+ expect(bot).toBeDefined();
119
+ });
120
+ });
121
+ describe('Message Sending', () => {
122
+ test('should queue message for sending', async () => {
123
+ jest.useFakeTimers();
124
+ bot = new SignalBot_1.SignalBot(mockConfig);
125
+ const mockSignalCli = bot.getSignalCli();
126
+ const sendMessageSpy = jest.spyOn(mockSignalCli, 'sendMessage').mockResolvedValue({
127
+ results: [{ type: 'SUCCESS' }],
128
+ timestamp: Date.now()
129
+ });
130
+ // Send message (queued)
131
+ const sendPromise = bot.sendMessage('+1111111111', 'Test message');
132
+ // Advance timers to process queue
133
+ jest.advanceTimersByTime(250);
134
+ await Promise.resolve(); // Let promises resolve
135
+ await sendPromise;
136
+ expect(sendMessageSpy).toHaveBeenCalledWith('+1111111111', 'Test message');
137
+ jest.useRealTimers();
138
+ });
139
+ test('should queue reaction for sending', async () => {
140
+ jest.useFakeTimers();
141
+ bot = new SignalBot_1.SignalBot(mockConfig);
142
+ const mockSignalCli = bot.getSignalCli();
143
+ const sendReactionSpy = jest.spyOn(mockSignalCli, 'sendReaction').mockResolvedValue({
144
+ results: [{ type: 'SUCCESS' }],
145
+ timestamp: Date.now()
146
+ });
147
+ // Send reaction (queued)
148
+ const sendPromise = bot.sendReaction('+1111111111', '+2222222222', 123456, '👍');
149
+ // Advance timers to process queue
150
+ jest.advanceTimersByTime(250);
151
+ await Promise.resolve();
152
+ await sendPromise;
153
+ expect(sendReactionSpy).toHaveBeenCalledWith('+1111111111', '+2222222222', 123456, '👍');
154
+ jest.useRealTimers();
155
+ });
156
+ test('should handle message with attachments', async () => {
157
+ jest.useFakeTimers();
158
+ bot = new SignalBot_1.SignalBot(mockConfig);
159
+ const mockSignalCli = bot.getSignalCli();
160
+ const sendMessageSpy = jest.spyOn(mockSignalCli, 'sendMessage').mockResolvedValue({
161
+ results: [{ type: 'SUCCESS' }],
162
+ timestamp: Date.now()
163
+ });
164
+ // Send message with attachment (queued)
165
+ const sendPromise = bot.sendMessageWithAttachment('+1111111111', 'Message with files', ['file1.txt', 'file2.jpg']);
166
+ // Advance timers to process queue and cleanup timer
167
+ jest.advanceTimersByTime(2500); // 250ms for queue + 2000ms for cleanup
168
+ await Promise.resolve();
169
+ await sendPromise;
170
+ expect(sendMessageSpy).toHaveBeenCalledWith('+1111111111', 'Message with files', {
171
+ attachments: ['file1.txt', 'file2.jpg']
172
+ });
173
+ jest.useRealTimers();
174
+ });
175
+ });
176
+ describe('Configuration', () => {
177
+ test('should use default settings when not provided', () => {
178
+ bot = new SignalBot_1.SignalBot({
179
+ phoneNumber: '+1234567890'
180
+ });
181
+ const commands = bot.getCommands();
182
+ expect(commands.length).toBeGreaterThan(0); // Should have default commands
183
+ });
184
+ test('should use custom command prefix', () => {
185
+ bot = new SignalBot_1.SignalBot({
186
+ phoneNumber: '+1234567890',
187
+ settings: {
188
+ commandPrefix: '!'
189
+ }
190
+ });
191
+ expect(bot).toBeDefined();
192
+ });
193
+ test('should handle all settings', () => {
194
+ bot = new SignalBot_1.SignalBot({
195
+ phoneNumber: '+1234567890',
196
+ admins: ['+1111111111'],
197
+ settings: {
198
+ commandPrefix: '$',
199
+ autoReact: false,
200
+ logMessages: false,
201
+ welcomeNewMembers: false,
202
+ cooldownSeconds: 5,
203
+ maxMessageLength: 2000
204
+ }
205
+ });
206
+ expect(bot).toBeDefined();
207
+ });
208
+ });
209
+ describe('Signal CLI Access', () => {
210
+ test('should provide access to underlying SignalCli', () => {
211
+ bot = new SignalBot_1.SignalBot(mockConfig);
212
+ const signalCli = bot.getSignalCli();
213
+ expect(signalCli).toBeDefined();
214
+ expect(signalCli.connect).toBeDefined();
215
+ expect(signalCli.disconnect).toBeDefined();
216
+ });
217
+ });
218
+ describe('Bot State', () => {
219
+ test('should track running state', () => {
220
+ bot = new SignalBot_1.SignalBot(mockConfig);
221
+ // Bot is not running initially
222
+ expect(bot.getStats().startTime).toBeDefined();
223
+ });
224
+ test('should handle stop when not running', async () => {
225
+ bot = new SignalBot_1.SignalBot(mockConfig);
226
+ await expect(bot.stop()).resolves.toBeUndefined();
227
+ });
228
+ });
229
+ describe('Image Download Feature', () => {
230
+ test('should have downloadImageFromUrl method', () => {
231
+ bot = new SignalBot_1.SignalBot(mockConfig);
232
+ expect(bot.downloadImageFromUrl).toBeDefined();
233
+ expect(typeof bot.downloadImageFromUrl).toBe('function');
234
+ });
235
+ test('should have sendMessageWithImage method', () => {
236
+ bot = new SignalBot_1.SignalBot(mockConfig);
237
+ expect(bot.sendMessageWithImage).toBeDefined();
238
+ expect(typeof bot.sendMessageWithImage).toBe('function');
239
+ });
240
+ });
241
+ describe('Event Emitters', () => {
242
+ test('should emit ready event structure', (done) => {
243
+ bot = new SignalBot_1.SignalBot({
244
+ phoneNumber: '+1234567890',
245
+ group: {
246
+ name: 'Test Group',
247
+ createIfNotExists: false
248
+ }
249
+ });
250
+ const mockSignalCli = bot.getSignalCli();
251
+ jest.spyOn(mockSignalCli, 'listDevices').mockResolvedValue([
252
+ { id: 1, name: 'Test Device', created: Date.now(), lastSeen: Date.now() }
253
+ ]);
254
+ jest.spyOn(mockSignalCli, 'connect').mockResolvedValue(undefined);
255
+ jest.spyOn(mockSignalCli, 'on').mockReturnValue(mockSignalCli);
256
+ bot.on('ready', () => {
257
+ done();
258
+ });
259
+ bot.start().catch(done);
260
+ });
261
+ test('should have stopped event', async () => {
262
+ bot = new SignalBot_1.SignalBot(mockConfig);
263
+ const stoppedHandler = jest.fn();
264
+ bot.on('stopped', stoppedHandler);
265
+ await bot.stop();
266
+ expect(stoppedHandler).toHaveBeenCalled();
267
+ });
268
+ });
269
+ describe('Default Commands', () => {
270
+ test('should include help command', () => {
271
+ bot = new SignalBot_1.SignalBot(mockConfig);
272
+ const commands = bot.getCommands();
273
+ const helpCmd = commands.find(c => c.name === 'help');
274
+ expect(helpCmd).toBeDefined();
275
+ expect(helpCmd?.description).toBeDefined();
276
+ });
277
+ test('should include stats command', () => {
278
+ bot = new SignalBot_1.SignalBot(mockConfig);
279
+ const commands = bot.getCommands();
280
+ const statsCmd = commands.find(c => c.name === 'stats');
281
+ expect(statsCmd).toBeDefined();
282
+ expect(statsCmd?.description).toBeDefined();
283
+ });
284
+ test('should include ping command', () => {
285
+ bot = new SignalBot_1.SignalBot(mockConfig);
286
+ const commands = bot.getCommands();
287
+ const pingCmd = commands.find(c => c.name === 'ping');
288
+ expect(pingCmd).toBeDefined();
289
+ expect(pingCmd?.description).toBeDefined();
290
+ });
291
+ test('should include info command', () => {
292
+ bot = new SignalBot_1.SignalBot(mockConfig);
293
+ const commands = bot.getCommands();
294
+ const infoCmd = commands.find(c => c.name === 'info');
295
+ expect(infoCmd).toBeDefined();
296
+ expect(infoCmd?.description).toBeDefined();
297
+ });
298
+ });
299
+ describe('Group Configuration with Avatar', () => {
300
+ test('should handle group config with avatar URL', () => {
301
+ bot = new SignalBot_1.SignalBot({
302
+ phoneNumber: '+1234567890',
303
+ group: {
304
+ name: 'Test Group',
305
+ description: 'Test Description',
306
+ createIfNotExists: true,
307
+ initialMembers: ['+1111111111'],
308
+ avatar: 'https://example.com/avatar.jpg'
309
+ }
310
+ });
311
+ expect(bot).toBeDefined();
312
+ });
313
+ test('should handle group config with local avatar path', () => {
314
+ bot = new SignalBot_1.SignalBot({
315
+ phoneNumber: '+1234567890',
316
+ group: {
317
+ name: 'Test Group',
318
+ description: 'Test Description',
319
+ createIfNotExists: true,
320
+ initialMembers: ['+1111111111'],
321
+ avatar: '/path/to/local/avatar.jpg'
322
+ }
323
+ });
324
+ expect(bot).toBeDefined();
325
+ });
326
+ });
327
+ describe('Edge Cases', () => {
328
+ test('should handle empty admins list', () => {
329
+ bot = new SignalBot_1.SignalBot({
330
+ phoneNumber: '+1234567890',
331
+ admins: []
332
+ });
333
+ expect(bot.isAdmin('+1234567890')).toBe(false);
334
+ });
335
+ test('should handle undefined settings', () => {
336
+ bot = new SignalBot_1.SignalBot({
337
+ phoneNumber: '+1234567890',
338
+ settings: undefined
339
+ });
340
+ expect(bot).toBeDefined();
341
+ });
342
+ test('should handle partial settings', () => {
343
+ bot = new SignalBot_1.SignalBot({
344
+ phoneNumber: '+1234567890',
345
+ settings: {
346
+ commandPrefix: '!'
347
+ // Other settings will use defaults
348
+ }
349
+ });
350
+ expect(bot).toBeDefined();
351
+ });
352
+ });
353
+ });
@@ -17,7 +17,12 @@ describe('SignalBot', () => {
17
17
  afterEach(async () => {
18
18
  if (bot) {
19
19
  await bot.stop();
20
+ // Clean up all listeners
21
+ bot.removeAllListeners();
22
+ bot.getSignalCli().removeAllListeners();
20
23
  }
24
+ // Clear all timers
25
+ jest.clearAllTimers();
21
26
  });
22
27
  test('should create bot with minimal config', () => {
23
28
  bot = new SignalBot_1.SignalBot({
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Advanced Features Tests for SignalCli
3
+ * Tests for new features added for 100% signal-cli coverage
4
+ */
5
+ export {};