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,258 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for enhanced parsing functionality (Phase 5)
4
+ * Tests profile and group data parsing methods
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const SignalCli_1 = require("../SignalCli");
8
+ describe('SignalCli - Enhanced Parsing (Phase 5)', () => {
9
+ let signal;
10
+ beforeEach(() => {
11
+ signal = new SignalCli_1.SignalCli('+33123456789');
12
+ // Mock sendJsonRpcRequest to avoid actual signal-cli calls
13
+ signal.sendJsonRpcRequest = jest.fn();
14
+ });
15
+ describe('parseContactProfile', () => {
16
+ it('should parse contact with full profile data', () => {
17
+ const contact = {
18
+ number: '+33123456789',
19
+ name: 'John Doe',
20
+ uuid: 'test-uuid',
21
+ blocked: false,
22
+ givenName: 'John',
23
+ familyName: 'Doe',
24
+ mobileCoinAddress: 'mc1_test_address_123',
25
+ profileName: 'John Doe',
26
+ };
27
+ const parsed = signal.parseContactProfile(contact);
28
+ expect(parsed.givenName).toBe('John');
29
+ expect(parsed.familyName).toBe('Doe');
30
+ expect(parsed.mobileCoinAddress).toBe('mc1_test_address_123');
31
+ expect(parsed.profileName).toBe('John Doe');
32
+ });
33
+ it('should build profileName from givenName and familyName if missing', () => {
34
+ const contact = {
35
+ number: '+33123456789',
36
+ name: 'John Doe',
37
+ uuid: 'test-uuid',
38
+ blocked: false,
39
+ givenName: 'John',
40
+ familyName: 'Doe',
41
+ };
42
+ const parsed = signal.parseContactProfile(contact);
43
+ expect(parsed.profileName).toBe('John Doe');
44
+ });
45
+ it('should use givenName as profileName if no familyName', () => {
46
+ const contact = {
47
+ number: '+33123456789',
48
+ name: 'John',
49
+ uuid: 'test-uuid',
50
+ blocked: false,
51
+ givenName: 'John',
52
+ };
53
+ const parsed = signal.parseContactProfile(contact);
54
+ expect(parsed.profileName).toBe('John');
55
+ });
56
+ it('should handle contact with minimal data', () => {
57
+ const contact = {
58
+ number: '+33123456789',
59
+ name: 'Unknown',
60
+ blocked: false,
61
+ };
62
+ const parsed = signal.parseContactProfile(contact);
63
+ expect(parsed.givenName).toBeUndefined();
64
+ expect(parsed.familyName).toBeUndefined();
65
+ expect(parsed.mobileCoinAddress).toBeUndefined();
66
+ });
67
+ it('should preserve additional contact fields', () => {
68
+ const contact = {
69
+ number: '+33123456789',
70
+ name: 'John Doe',
71
+ uuid: 'test-uuid',
72
+ blocked: true,
73
+ profileAvatar: 'avatar.jpg',
74
+ color: 'blue',
75
+ archived: true,
76
+ mutedUntil: 123456789,
77
+ hideStory: true,
78
+ givenName: 'John',
79
+ };
80
+ const parsed = signal.parseContactProfile(contact);
81
+ expect(parsed.blocked).toBe(true);
82
+ expect(parsed.profileAvatar).toBe('avatar.jpg');
83
+ expect(parsed.color).toBe('blue');
84
+ expect(parsed.archived).toBe(true);
85
+ expect(parsed.mutedUntil).toBe(123456789);
86
+ expect(parsed.hideStory).toBe(true);
87
+ });
88
+ });
89
+ describe('parseGroupDetails', () => {
90
+ it('should parse group with full membership data', () => {
91
+ const group = {
92
+ groupId: 'group123==',
93
+ name: 'Test Group',
94
+ description: 'A test group',
95
+ isMember: true,
96
+ isBlocked: false,
97
+ messageExpirationTime: 0,
98
+ members: [
99
+ { number: '+33111111111' },
100
+ { number: '+33222222222' },
101
+ ],
102
+ pendingMembers: [
103
+ { number: '+33333333333' },
104
+ ],
105
+ requestingMembers: [],
106
+ admins: [
107
+ { number: '+33111111111' },
108
+ ],
109
+ banned: [
110
+ { number: '+33444444444' },
111
+ ],
112
+ permissionAddMember: 'ONLY_ADMINS',
113
+ permissionEditDetails: 'ONLY_ADMINS',
114
+ permissionSendMessage: 'EVERY_MEMBER',
115
+ groupInviteLink: 'https://signal.group/test',
116
+ };
117
+ const parsed = signal.parseGroupDetails(group);
118
+ expect(parsed.pendingMembers).toHaveLength(1);
119
+ expect(parsed.pendingMembers[0].number).toBe('+33333333333');
120
+ expect(parsed.banned).toHaveLength(1);
121
+ expect(parsed.banned[0].number).toBe('+33444444444');
122
+ expect(parsed.inviteLink).toBe('https://signal.group/test');
123
+ expect(parsed.groupInviteLink).toBe('https://signal.group/test');
124
+ });
125
+ it('should normalize inviteLink field', () => {
126
+ const group1 = {
127
+ groupId: 'group123==',
128
+ name: 'Test Group',
129
+ isMember: true,
130
+ isBlocked: false,
131
+ messageExpirationTime: 0,
132
+ members: [],
133
+ pendingMembers: [],
134
+ requestingMembers: [],
135
+ admins: [],
136
+ banned: [],
137
+ permissionAddMember: 'EVERY_MEMBER',
138
+ permissionEditDetails: 'EVERY_MEMBER',
139
+ permissionSendMessage: 'EVERY_MEMBER',
140
+ groupInviteLink: 'https://signal.group/test1',
141
+ };
142
+ const parsed1 = signal.parseGroupDetails(group1);
143
+ expect(parsed1.inviteLink).toBe('https://signal.group/test1');
144
+ expect(parsed1.groupInviteLink).toBe('https://signal.group/test1');
145
+ const group2 = {
146
+ ...group1,
147
+ groupInviteLink: undefined,
148
+ inviteLink: 'https://signal.group/test2',
149
+ };
150
+ const parsed2 = signal.parseGroupDetails(group2);
151
+ expect(parsed2.inviteLink).toBe('https://signal.group/test2');
152
+ expect(parsed2.groupInviteLink).toBe('https://signal.group/test2');
153
+ });
154
+ it('should ensure membership arrays exist', () => {
155
+ const group = {
156
+ groupId: 'group123==',
157
+ name: 'Minimal Group',
158
+ isMember: true,
159
+ isBlocked: false,
160
+ messageExpirationTime: 0,
161
+ members: [],
162
+ pendingMembers: [],
163
+ requestingMembers: [],
164
+ admins: [],
165
+ banned: [],
166
+ permissionAddMember: 'EVERY_MEMBER',
167
+ permissionEditDetails: 'EVERY_MEMBER',
168
+ permissionSendMessage: 'EVERY_MEMBER',
169
+ };
170
+ const parsed = signal.parseGroupDetails(group);
171
+ expect(Array.isArray(parsed.members)).toBe(true);
172
+ expect(Array.isArray(parsed.pendingMembers)).toBe(true);
173
+ expect(Array.isArray(parsed.requestingMembers)).toBe(true);
174
+ expect(Array.isArray(parsed.admins)).toBe(true);
175
+ expect(Array.isArray(parsed.banned)).toBe(true);
176
+ });
177
+ it('should preserve group permissions', () => {
178
+ const group = {
179
+ groupId: 'group123==',
180
+ name: 'Restricted Group',
181
+ isMember: true,
182
+ isBlocked: false,
183
+ messageExpirationTime: 3600,
184
+ members: [],
185
+ pendingMembers: [],
186
+ requestingMembers: [],
187
+ admins: [],
188
+ banned: [],
189
+ permissionAddMember: 'ONLY_ADMINS',
190
+ permissionEditDetails: 'ONLY_ADMINS',
191
+ permissionSendMessage: 'ONLY_ADMINS',
192
+ };
193
+ const parsed = signal.parseGroupDetails(group);
194
+ expect(parsed.permissionAddMember).toBe('ONLY_ADMINS');
195
+ expect(parsed.permissionEditDetails).toBe('ONLY_ADMINS');
196
+ expect(parsed.permissionSendMessage).toBe('ONLY_ADMINS');
197
+ expect(parsed.messageExpirationTime).toBe(3600);
198
+ });
199
+ });
200
+ describe('getContactsWithProfiles', () => {
201
+ it('should return enriched contacts list', async () => {
202
+ const mockContacts = [
203
+ {
204
+ number: '+33111111111',
205
+ name: 'Alice',
206
+ blocked: false,
207
+ givenName: 'Alice',
208
+ familyName: 'Smith',
209
+ },
210
+ {
211
+ number: '+33222222222',
212
+ name: 'Bob',
213
+ blocked: false,
214
+ givenName: 'Bob',
215
+ mobileCoinAddress: 'mc1_bob',
216
+ },
217
+ ];
218
+ signal.sendJsonRpcRequest = jest.fn().mockResolvedValue(mockContacts);
219
+ const enriched = await signal.getContactsWithProfiles();
220
+ expect(enriched).toHaveLength(2);
221
+ expect(enriched[0].profileName).toBe('Alice Smith');
222
+ expect(enriched[1].profileName).toBe('Bob');
223
+ expect(enriched[1].mobileCoinAddress).toBe('mc1_bob');
224
+ });
225
+ });
226
+ describe('getGroupsWithDetails', () => {
227
+ it('should return enriched groups list', async () => {
228
+ const mockGroups = [
229
+ {
230
+ groupId: 'group1==',
231
+ name: 'Group 1',
232
+ isMember: true,
233
+ isBlocked: false,
234
+ messageExpirationTime: 0,
235
+ members: [{ number: '+33111111111' }],
236
+ pendingMembers: [{ number: '+33222222222' }],
237
+ requestingMembers: [],
238
+ admins: [{ number: '+33111111111' }],
239
+ banned: [],
240
+ permissionAddMember: 'EVERY_MEMBER',
241
+ permissionEditDetails: 'EVERY_MEMBER',
242
+ permissionSendMessage: 'EVERY_MEMBER',
243
+ groupInviteLink: 'https://signal.group/group1',
244
+ },
245
+ ];
246
+ signal.sendJsonRpcRequest = jest.fn().mockResolvedValue(mockGroups);
247
+ const enriched = await signal.getGroupsWithDetails();
248
+ expect(enriched).toHaveLength(1);
249
+ expect(enriched[0].inviteLink).toBe('https://signal.group/group1');
250
+ expect(enriched[0].pendingMembers).toHaveLength(1);
251
+ });
252
+ it('should support list options', async () => {
253
+ signal.sendJsonRpcRequest = jest.fn().mockResolvedValue([]);
254
+ await signal.getGroupsWithDetails({ detailed: true });
255
+ expect(signal.sendJsonRpcRequest).toHaveBeenCalledWith('listGroups', expect.objectContaining({ detailed: true }));
256
+ });
257
+ });
258
+ });
@@ -155,31 +155,23 @@ describe('SignalCli', () => {
155
155
  expect(result).toEqual(mockResponse);
156
156
  });
157
157
  it('should start change number', async () => {
158
- const mockResponse = {
159
- session: 'change-session-id',
160
- challenge: 'challenge-token'
161
- };
162
158
  const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
163
- .mockResolvedValue(mockResponse);
164
- const result = await signalCli.startChangeNumber('+1987654321');
159
+ .mockResolvedValue({});
160
+ await signalCli.startChangeNumber('+1987654321');
165
161
  expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('startChangeNumber', {
166
162
  account: '+1234567890',
167
163
  number: '+1987654321',
168
164
  voice: false
169
165
  });
170
- expect(result).toEqual({
171
- session: 'change-session-id',
172
- newNumber: '+1987654321',
173
- challenge: 'challenge-token'
174
- });
175
166
  });
176
167
  it('should finish change number', async () => {
177
168
  const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
178
169
  .mockResolvedValue({});
179
- await signalCli.finishChangeNumber('123456', 'pin-code');
170
+ await signalCli.finishChangeNumber('+1987654321', '123456', 'pin-code');
180
171
  expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('finishChangeNumber', {
181
172
  account: '+1234567890',
182
- code: '123456',
173
+ number: '+1987654321',
174
+ verificationCode: '123456',
183
175
  pin: 'pin-code'
184
176
  });
185
177
  });
@@ -232,4 +224,248 @@ describe('SignalCli', () => {
232
224
  Object.defineProperty(process, 'platform', { value: originalPlatform });
233
225
  });
234
226
  });
227
+ // Test v0.1.0 features: Polls
228
+ describe('Poll Management', () => {
229
+ beforeEach(() => {
230
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
231
+ });
232
+ it('should create a poll', async () => {
233
+ const mockResponse = { timestamp: 123456789 };
234
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
235
+ .mockResolvedValue(mockResponse);
236
+ const result = await signalCli.sendPollCreate({
237
+ recipients: ['+1234567890'],
238
+ question: 'What is your favorite color?',
239
+ options: ['Red', 'Blue', 'Green']
240
+ });
241
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
242
+ account: '+1234567890',
243
+ recipients: ['+1234567890'],
244
+ question: 'What is your favorite color?',
245
+ options: ['Red', 'Blue', 'Green']
246
+ });
247
+ expect(result).toEqual(mockResponse);
248
+ });
249
+ it('should create a group poll', async () => {
250
+ const mockResponse = { timestamp: 123456789 };
251
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
252
+ .mockResolvedValue(mockResponse);
253
+ const result = await signalCli.sendPollCreate({
254
+ groupId: 'group-123',
255
+ question: 'Best meeting time?',
256
+ options: ['9 AM', '2 PM', '4 PM']
257
+ });
258
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
259
+ account: '+1234567890',
260
+ groupId: 'group-123',
261
+ question: 'Best meeting time?',
262
+ options: ['9 AM', '2 PM', '4 PM']
263
+ });
264
+ expect(result).toEqual(mockResponse);
265
+ });
266
+ it('should vote on a poll', async () => {
267
+ const mockResponse = { timestamp: 123456790 };
268
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
269
+ .mockResolvedValue(mockResponse);
270
+ const result = await signalCli.sendPollVote('+1234567890', {
271
+ pollAuthor: '+9876543210',
272
+ pollTimestamp: 123456789,
273
+ optionIndexes: [0, 1]
274
+ });
275
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollVote', {
276
+ account: '+1234567890',
277
+ recipient: '+1234567890',
278
+ pollAuthor: '+9876543210',
279
+ pollTimestamp: 123456789,
280
+ options: [0, 1]
281
+ });
282
+ expect(result).toEqual(mockResponse);
283
+ });
284
+ it('should terminate a poll', async () => {
285
+ const mockResponse = { timestamp: 123456791 };
286
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
287
+ .mockResolvedValue(mockResponse);
288
+ const result = await signalCli.sendPollTerminate('+1234567890', {
289
+ pollTimestamp: 123456789
290
+ });
291
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollTerminate', {
292
+ account: '+1234567890',
293
+ recipient: '+1234567890',
294
+ pollTimestamp: 123456789
295
+ });
296
+ expect(result).toEqual(mockResponse);
297
+ });
298
+ });
299
+ // Test v0.1.0 features: Attachment Retrieval
300
+ describe('Attachment Retrieval', () => {
301
+ beforeEach(() => {
302
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
303
+ });
304
+ it('should get attachment by ID', async () => {
305
+ const mockBase64 = 'base64-encoded-data';
306
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
307
+ .mockResolvedValue(mockBase64);
308
+ const result = await signalCli.getAttachment({
309
+ id: 'attachment-123'
310
+ });
311
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAttachment', {
312
+ account: '+1234567890',
313
+ id: 'attachment-123'
314
+ });
315
+ expect(result).toBe(mockBase64);
316
+ });
317
+ it('should get contact avatar', async () => {
318
+ const mockBase64 = 'base64-avatar-data';
319
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
320
+ .mockResolvedValue(mockBase64);
321
+ const result = await signalCli.getAvatar({
322
+ contact: '+9876543210'
323
+ });
324
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
325
+ account: '+1234567890',
326
+ contact: '+9876543210'
327
+ });
328
+ expect(result).toBe(mockBase64);
329
+ });
330
+ it('should get profile avatar', async () => {
331
+ const mockBase64 = 'base64-profile-avatar';
332
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
333
+ .mockResolvedValue(mockBase64);
334
+ const result = await signalCli.getAvatar({
335
+ profile: '+1234567890'
336
+ });
337
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
338
+ account: '+1234567890',
339
+ profile: '+1234567890'
340
+ });
341
+ expect(result).toBe(mockBase64);
342
+ });
343
+ it('should get group avatar', async () => {
344
+ const mockBase64 = 'base64-group-avatar';
345
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
346
+ .mockResolvedValue(mockBase64);
347
+ const result = await signalCli.getAvatar({
348
+ groupId: 'group-123'
349
+ });
350
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
351
+ account: '+1234567890',
352
+ groupId: 'group-123'
353
+ });
354
+ expect(result).toBe(mockBase64);
355
+ });
356
+ it('should get sticker data', async () => {
357
+ const mockBase64 = 'base64-sticker-data';
358
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
359
+ .mockResolvedValue(mockBase64);
360
+ const result = await signalCli.getSticker({
361
+ packId: 'pack-123',
362
+ stickerId: 5
363
+ });
364
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getSticker', {
365
+ account: '+1234567890',
366
+ packId: 'pack-123',
367
+ stickerId: 5
368
+ });
369
+ expect(result).toBe(mockBase64);
370
+ });
371
+ });
372
+ // Test v0.1.0 features: Account Management
373
+ describe('Account Management', () => {
374
+ beforeEach(() => {
375
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
376
+ });
377
+ it('should update account settings', async () => {
378
+ const mockResponse = {
379
+ username: 'myusername',
380
+ usernameLink: 'https://signal.me/#myusername'
381
+ };
382
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
383
+ .mockResolvedValue(mockResponse);
384
+ const result = await signalCli.updateAccount({
385
+ deviceName: 'My Device',
386
+ username: 'myusername'
387
+ });
388
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('updateAccount', {
389
+ account: '+1234567890',
390
+ deviceName: 'My Device',
391
+ username: 'myusername'
392
+ });
393
+ expect(result.success).toBe(true);
394
+ expect(result.username).toBe('myusername');
395
+ });
396
+ it('should list accounts with details', async () => {
397
+ const mockResponse = {
398
+ accounts: [
399
+ { number: '+1234567890', name: 'Account 1', uuid: 'uuid-1' },
400
+ { number: '+9876543210', name: 'Account 2', uuid: 'uuid-2' }
401
+ ]
402
+ };
403
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
404
+ .mockResolvedValue(mockResponse);
405
+ const result = await signalCli.listAccountsDetailed();
406
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listAccounts');
407
+ expect(result).toEqual(mockResponse.accounts);
408
+ });
409
+ });
410
+ // Test v0.1.0 features: Synchronization
411
+ describe('Synchronization', () => {
412
+ beforeEach(() => {
413
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
414
+ });
415
+ it('should send contacts to linked devices', async () => {
416
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
417
+ .mockResolvedValue({});
418
+ await signalCli.sendContacts();
419
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendContacts', {
420
+ account: '+1234567890'
421
+ });
422
+ });
423
+ it('should list groups with detailed information', async () => {
424
+ const mockGroups = [
425
+ {
426
+ id: 'group-1',
427
+ name: 'Test Group 1',
428
+ members: ['+1111111111', '+2222222222'],
429
+ groupType: 'GROUP_V2'
430
+ },
431
+ {
432
+ id: 'group-2',
433
+ name: 'Test Group 2',
434
+ members: ['+3333333333'],
435
+ groupType: 'GROUP_V2'
436
+ }
437
+ ];
438
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
439
+ .mockResolvedValue(mockGroups);
440
+ const result = await signalCli.listGroupsDetailed({
441
+ detailed: true
442
+ });
443
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
444
+ account: '+1234567890',
445
+ detailed: true
446
+ });
447
+ expect(result).toEqual(mockGroups);
448
+ });
449
+ it('should filter groups by ID', async () => {
450
+ const mockGroups = [
451
+ {
452
+ id: 'group-1',
453
+ name: 'Specific Group',
454
+ members: ['+1111111111']
455
+ }
456
+ ];
457
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
458
+ .mockResolvedValue(mockGroups);
459
+ const result = await signalCli.listGroupsDetailed({
460
+ groupIds: ['group-1'],
461
+ detailed: true
462
+ });
463
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
464
+ account: '+1234567890',
465
+ detailed: true,
466
+ groupId: ['group-1']
467
+ });
468
+ expect(result).toEqual(mockGroups);
469
+ });
470
+ });
235
471
  });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Additional tests for config.ts
3
+ * Tests configuration validation and logger functionality
4
+ */
5
+ export {};