signal-sdk 0.0.9 → 0.1.0
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.
- package/README.md +175 -59
- package/dist/SignalCli.d.ts +72 -2
- package/dist/SignalCli.js +257 -1
- package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
- package/dist/__tests__/SignalBot.additional.test.js +333 -0
- package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
- package/dist/__tests__/SignalCli.integration.test.js +218 -0
- package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
- package/dist/__tests__/SignalCli.methods.test.js +470 -0
- package/dist/__tests__/SignalCli.test.js +244 -0
- package/dist/__tests__/config.test.d.ts +5 -0
- package/dist/__tests__/config.test.js +252 -0
- package/dist/__tests__/errors.test.d.ts +5 -0
- package/dist/__tests__/errors.test.js +276 -0
- package/dist/__tests__/retry.test.d.ts +4 -0
- package/dist/__tests__/retry.test.js +123 -0
- package/dist/__tests__/validators.test.d.ts +4 -0
- package/dist/__tests__/validators.test.js +147 -0
- package/dist/config.d.ts +67 -0
- package/dist/config.js +111 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +75 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/interfaces.d.ts +136 -1
- package/dist/interfaces.js +1 -1
- package/dist/retry.d.ts +56 -0
- package/dist/retry.js +135 -0
- package/dist/validators.d.ts +59 -0
- package/dist/validators.js +170 -0
- package/package.json +1 -1
|
@@ -232,4 +232,248 @@ describe('SignalCli', () => {
|
|
|
232
232
|
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
|
+
// Test v0.1.0 features: Polls
|
|
236
|
+
describe('Poll Management', () => {
|
|
237
|
+
beforeEach(() => {
|
|
238
|
+
jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
|
|
239
|
+
});
|
|
240
|
+
it('should create a poll', async () => {
|
|
241
|
+
const mockResponse = { timestamp: 123456789 };
|
|
242
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
243
|
+
.mockResolvedValue(mockResponse);
|
|
244
|
+
const result = await signalCli.sendPollCreate({
|
|
245
|
+
recipients: ['+1234567890'],
|
|
246
|
+
question: 'What is your favorite color?',
|
|
247
|
+
options: ['Red', 'Blue', 'Green']
|
|
248
|
+
});
|
|
249
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
|
|
250
|
+
account: '+1234567890',
|
|
251
|
+
recipients: ['+1234567890'],
|
|
252
|
+
question: 'What is your favorite color?',
|
|
253
|
+
options: ['Red', 'Blue', 'Green']
|
|
254
|
+
});
|
|
255
|
+
expect(result).toEqual(mockResponse);
|
|
256
|
+
});
|
|
257
|
+
it('should create a group poll', async () => {
|
|
258
|
+
const mockResponse = { timestamp: 123456789 };
|
|
259
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
260
|
+
.mockResolvedValue(mockResponse);
|
|
261
|
+
const result = await signalCli.sendPollCreate({
|
|
262
|
+
groupId: 'group-123',
|
|
263
|
+
question: 'Best meeting time?',
|
|
264
|
+
options: ['9 AM', '2 PM', '4 PM']
|
|
265
|
+
});
|
|
266
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
|
|
267
|
+
account: '+1234567890',
|
|
268
|
+
groupId: 'group-123',
|
|
269
|
+
question: 'Best meeting time?',
|
|
270
|
+
options: ['9 AM', '2 PM', '4 PM']
|
|
271
|
+
});
|
|
272
|
+
expect(result).toEqual(mockResponse);
|
|
273
|
+
});
|
|
274
|
+
it('should vote on a poll', async () => {
|
|
275
|
+
const mockResponse = { timestamp: 123456790 };
|
|
276
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
277
|
+
.mockResolvedValue(mockResponse);
|
|
278
|
+
const result = await signalCli.sendPollVote('+1234567890', {
|
|
279
|
+
pollAuthor: '+9876543210',
|
|
280
|
+
pollTimestamp: 123456789,
|
|
281
|
+
optionIndexes: [0, 1]
|
|
282
|
+
});
|
|
283
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollVote', {
|
|
284
|
+
account: '+1234567890',
|
|
285
|
+
recipient: '+1234567890',
|
|
286
|
+
pollAuthor: '+9876543210',
|
|
287
|
+
pollTimestamp: 123456789,
|
|
288
|
+
options: [0, 1]
|
|
289
|
+
});
|
|
290
|
+
expect(result).toEqual(mockResponse);
|
|
291
|
+
});
|
|
292
|
+
it('should terminate a poll', async () => {
|
|
293
|
+
const mockResponse = { timestamp: 123456791 };
|
|
294
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
295
|
+
.mockResolvedValue(mockResponse);
|
|
296
|
+
const result = await signalCli.sendPollTerminate('+1234567890', {
|
|
297
|
+
pollTimestamp: 123456789
|
|
298
|
+
});
|
|
299
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollTerminate', {
|
|
300
|
+
account: '+1234567890',
|
|
301
|
+
recipient: '+1234567890',
|
|
302
|
+
pollTimestamp: 123456789
|
|
303
|
+
});
|
|
304
|
+
expect(result).toEqual(mockResponse);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
// Test v0.1.0 features: Attachment Retrieval
|
|
308
|
+
describe('Attachment Retrieval', () => {
|
|
309
|
+
beforeEach(() => {
|
|
310
|
+
jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
|
|
311
|
+
});
|
|
312
|
+
it('should get attachment by ID', async () => {
|
|
313
|
+
const mockBase64 = 'base64-encoded-data';
|
|
314
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
315
|
+
.mockResolvedValue(mockBase64);
|
|
316
|
+
const result = await signalCli.getAttachment({
|
|
317
|
+
id: 'attachment-123'
|
|
318
|
+
});
|
|
319
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAttachment', {
|
|
320
|
+
account: '+1234567890',
|
|
321
|
+
id: 'attachment-123'
|
|
322
|
+
});
|
|
323
|
+
expect(result).toBe(mockBase64);
|
|
324
|
+
});
|
|
325
|
+
it('should get contact avatar', async () => {
|
|
326
|
+
const mockBase64 = 'base64-avatar-data';
|
|
327
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
328
|
+
.mockResolvedValue(mockBase64);
|
|
329
|
+
const result = await signalCli.getAvatar({
|
|
330
|
+
contact: '+9876543210'
|
|
331
|
+
});
|
|
332
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
|
|
333
|
+
account: '+1234567890',
|
|
334
|
+
contact: '+9876543210'
|
|
335
|
+
});
|
|
336
|
+
expect(result).toBe(mockBase64);
|
|
337
|
+
});
|
|
338
|
+
it('should get profile avatar', async () => {
|
|
339
|
+
const mockBase64 = 'base64-profile-avatar';
|
|
340
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
341
|
+
.mockResolvedValue(mockBase64);
|
|
342
|
+
const result = await signalCli.getAvatar({
|
|
343
|
+
profile: '+1234567890'
|
|
344
|
+
});
|
|
345
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
|
|
346
|
+
account: '+1234567890',
|
|
347
|
+
profile: '+1234567890'
|
|
348
|
+
});
|
|
349
|
+
expect(result).toBe(mockBase64);
|
|
350
|
+
});
|
|
351
|
+
it('should get group avatar', async () => {
|
|
352
|
+
const mockBase64 = 'base64-group-avatar';
|
|
353
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
354
|
+
.mockResolvedValue(mockBase64);
|
|
355
|
+
const result = await signalCli.getAvatar({
|
|
356
|
+
groupId: 'group-123'
|
|
357
|
+
});
|
|
358
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
|
|
359
|
+
account: '+1234567890',
|
|
360
|
+
groupId: 'group-123'
|
|
361
|
+
});
|
|
362
|
+
expect(result).toBe(mockBase64);
|
|
363
|
+
});
|
|
364
|
+
it('should get sticker data', async () => {
|
|
365
|
+
const mockBase64 = 'base64-sticker-data';
|
|
366
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
367
|
+
.mockResolvedValue(mockBase64);
|
|
368
|
+
const result = await signalCli.getSticker({
|
|
369
|
+
packId: 'pack-123',
|
|
370
|
+
stickerId: 5
|
|
371
|
+
});
|
|
372
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getSticker', {
|
|
373
|
+
account: '+1234567890',
|
|
374
|
+
packId: 'pack-123',
|
|
375
|
+
stickerId: 5
|
|
376
|
+
});
|
|
377
|
+
expect(result).toBe(mockBase64);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
// Test v0.1.0 features: Account Management
|
|
381
|
+
describe('Account Management', () => {
|
|
382
|
+
beforeEach(() => {
|
|
383
|
+
jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
|
|
384
|
+
});
|
|
385
|
+
it('should update account settings', async () => {
|
|
386
|
+
const mockResponse = {
|
|
387
|
+
username: 'myusername',
|
|
388
|
+
usernameLink: 'https://signal.me/#myusername'
|
|
389
|
+
};
|
|
390
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
391
|
+
.mockResolvedValue(mockResponse);
|
|
392
|
+
const result = await signalCli.updateAccount({
|
|
393
|
+
deviceName: 'My Device',
|
|
394
|
+
username: 'myusername'
|
|
395
|
+
});
|
|
396
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('updateAccount', {
|
|
397
|
+
account: '+1234567890',
|
|
398
|
+
deviceName: 'My Device',
|
|
399
|
+
username: 'myusername'
|
|
400
|
+
});
|
|
401
|
+
expect(result.success).toBe(true);
|
|
402
|
+
expect(result.username).toBe('myusername');
|
|
403
|
+
});
|
|
404
|
+
it('should list accounts with details', async () => {
|
|
405
|
+
const mockResponse = {
|
|
406
|
+
accounts: [
|
|
407
|
+
{ number: '+1234567890', name: 'Account 1', uuid: 'uuid-1' },
|
|
408
|
+
{ number: '+9876543210', name: 'Account 2', uuid: 'uuid-2' }
|
|
409
|
+
]
|
|
410
|
+
};
|
|
411
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
412
|
+
.mockResolvedValue(mockResponse);
|
|
413
|
+
const result = await signalCli.listAccountsDetailed();
|
|
414
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listAccounts');
|
|
415
|
+
expect(result).toEqual(mockResponse.accounts);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
// Test v0.1.0 features: Synchronization
|
|
419
|
+
describe('Synchronization', () => {
|
|
420
|
+
beforeEach(() => {
|
|
421
|
+
jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
|
|
422
|
+
});
|
|
423
|
+
it('should send contacts to linked devices', async () => {
|
|
424
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
425
|
+
.mockResolvedValue({});
|
|
426
|
+
await signalCli.sendContacts();
|
|
427
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendContacts', {
|
|
428
|
+
account: '+1234567890'
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
it('should list groups with detailed information', async () => {
|
|
432
|
+
const mockGroups = [
|
|
433
|
+
{
|
|
434
|
+
id: 'group-1',
|
|
435
|
+
name: 'Test Group 1',
|
|
436
|
+
members: ['+1111111111', '+2222222222'],
|
|
437
|
+
groupType: 'GROUP_V2'
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
id: 'group-2',
|
|
441
|
+
name: 'Test Group 2',
|
|
442
|
+
members: ['+3333333333'],
|
|
443
|
+
groupType: 'GROUP_V2'
|
|
444
|
+
}
|
|
445
|
+
];
|
|
446
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
447
|
+
.mockResolvedValue(mockGroups);
|
|
448
|
+
const result = await signalCli.listGroupsDetailed({
|
|
449
|
+
detailed: true
|
|
450
|
+
});
|
|
451
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
|
|
452
|
+
account: '+1234567890',
|
|
453
|
+
detailed: true
|
|
454
|
+
});
|
|
455
|
+
expect(result).toEqual(mockGroups);
|
|
456
|
+
});
|
|
457
|
+
it('should filter groups by ID', async () => {
|
|
458
|
+
const mockGroups = [
|
|
459
|
+
{
|
|
460
|
+
id: 'group-1',
|
|
461
|
+
name: 'Specific Group',
|
|
462
|
+
members: ['+1111111111']
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
|
|
466
|
+
.mockResolvedValue(mockGroups);
|
|
467
|
+
const result = await signalCli.listGroupsDetailed({
|
|
468
|
+
groupIds: ['group-1'],
|
|
469
|
+
detailed: true
|
|
470
|
+
});
|
|
471
|
+
expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
|
|
472
|
+
account: '+1234567890',
|
|
473
|
+
detailed: true,
|
|
474
|
+
groupId: ['group-1']
|
|
475
|
+
});
|
|
476
|
+
expect(result).toEqual(mockGroups);
|
|
477
|
+
});
|
|
478
|
+
});
|
|
235
479
|
});
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Additional tests for config.ts
|
|
4
|
+
* Tests configuration validation and logger functionality
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const config_1 = require("../config");
|
|
8
|
+
describe('Config Additional Tests', () => {
|
|
9
|
+
describe('validateConfig', () => {
|
|
10
|
+
test('should return default config when no user config provided', () => {
|
|
11
|
+
const config = (0, config_1.validateConfig)();
|
|
12
|
+
expect(config).toEqual(config_1.DEFAULT_CONFIG);
|
|
13
|
+
});
|
|
14
|
+
test('should merge user config with defaults', () => {
|
|
15
|
+
const userConfig = {
|
|
16
|
+
verbose: true,
|
|
17
|
+
maxRetries: 5
|
|
18
|
+
};
|
|
19
|
+
const config = (0, config_1.validateConfig)(userConfig);
|
|
20
|
+
expect(config.verbose).toBe(true);
|
|
21
|
+
expect(config.maxRetries).toBe(5);
|
|
22
|
+
expect(config.connectionTimeout).toBe(config_1.DEFAULT_CONFIG.connectionTimeout);
|
|
23
|
+
});
|
|
24
|
+
test('should throw error for negative connectionTimeout', () => {
|
|
25
|
+
expect(() => (0, config_1.validateConfig)({ connectionTimeout: -1 }))
|
|
26
|
+
.toThrow('connectionTimeout must be non-negative');
|
|
27
|
+
});
|
|
28
|
+
test('should throw error for negative requestTimeout', () => {
|
|
29
|
+
expect(() => (0, config_1.validateConfig)({ requestTimeout: -100 }))
|
|
30
|
+
.toThrow('requestTimeout must be non-negative');
|
|
31
|
+
});
|
|
32
|
+
test('should throw error for negative maxRetries', () => {
|
|
33
|
+
expect(() => (0, config_1.validateConfig)({ maxRetries: -5 }))
|
|
34
|
+
.toThrow('maxRetries must be non-negative');
|
|
35
|
+
});
|
|
36
|
+
test('should throw error for negative retryDelay', () => {
|
|
37
|
+
expect(() => (0, config_1.validateConfig)({ retryDelay: -1000 }))
|
|
38
|
+
.toThrow('retryDelay must be non-negative');
|
|
39
|
+
});
|
|
40
|
+
test('should throw error for maxConcurrentRequests less than 1', () => {
|
|
41
|
+
expect(() => (0, config_1.validateConfig)({ maxConcurrentRequests: 0 }))
|
|
42
|
+
.toThrow('maxConcurrentRequests must be at least 1');
|
|
43
|
+
expect(() => (0, config_1.validateConfig)({ maxConcurrentRequests: -1 }))
|
|
44
|
+
.toThrow('maxConcurrentRequests must be at least 1');
|
|
45
|
+
});
|
|
46
|
+
test('should throw error for negative minRequestInterval', () => {
|
|
47
|
+
expect(() => (0, config_1.validateConfig)({ minRequestInterval: -50 }))
|
|
48
|
+
.toThrow('minRequestInterval must be non-negative');
|
|
49
|
+
});
|
|
50
|
+
test('should accept all valid trustNewIdentities values', () => {
|
|
51
|
+
expect(() => (0, config_1.validateConfig)({ trustNewIdentities: 'on-first-use' }))
|
|
52
|
+
.not.toThrow();
|
|
53
|
+
expect(() => (0, config_1.validateConfig)({ trustNewIdentities: 'always' }))
|
|
54
|
+
.not.toThrow();
|
|
55
|
+
expect(() => (0, config_1.validateConfig)({ trustNewIdentities: 'never' }))
|
|
56
|
+
.not.toThrow();
|
|
57
|
+
});
|
|
58
|
+
test('should accept zero values for valid fields', () => {
|
|
59
|
+
const config = (0, config_1.validateConfig)({
|
|
60
|
+
connectionTimeout: 0,
|
|
61
|
+
requestTimeout: 0,
|
|
62
|
+
maxRetries: 0,
|
|
63
|
+
retryDelay: 0,
|
|
64
|
+
minRequestInterval: 0
|
|
65
|
+
});
|
|
66
|
+
expect(config.connectionTimeout).toBe(0);
|
|
67
|
+
expect(config.requestTimeout).toBe(0);
|
|
68
|
+
expect(config.maxRetries).toBe(0);
|
|
69
|
+
expect(config.retryDelay).toBe(0);
|
|
70
|
+
expect(config.minRequestInterval).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
test('should handle all configuration options', () => {
|
|
73
|
+
const fullConfig = {
|
|
74
|
+
signalCliPath: '/custom/path/signal-cli',
|
|
75
|
+
account: '+1234567890',
|
|
76
|
+
connectionTimeout: 60000,
|
|
77
|
+
requestTimeout: 120000,
|
|
78
|
+
enableRetry: false,
|
|
79
|
+
maxRetries: 10,
|
|
80
|
+
retryDelay: 2000,
|
|
81
|
+
verbose: true,
|
|
82
|
+
logFile: '/var/log/signal.log',
|
|
83
|
+
maxConcurrentRequests: 10,
|
|
84
|
+
minRequestInterval: 200,
|
|
85
|
+
autoReconnect: false,
|
|
86
|
+
trustNewIdentities: 'never',
|
|
87
|
+
disableSendLog: true
|
|
88
|
+
};
|
|
89
|
+
const config = (0, config_1.validateConfig)(fullConfig);
|
|
90
|
+
expect(config).toMatchObject(fullConfig);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('Logger', () => {
|
|
94
|
+
let logger;
|
|
95
|
+
beforeEach(() => {
|
|
96
|
+
logger = new config_1.Logger({
|
|
97
|
+
level: 'debug',
|
|
98
|
+
enableConsole: true,
|
|
99
|
+
enableFile: false,
|
|
100
|
+
includeTimestamp: true,
|
|
101
|
+
includeLevel: true
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
test('should create logger with default config', () => {
|
|
105
|
+
const defaultLogger = new config_1.Logger();
|
|
106
|
+
expect(defaultLogger).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
test('should log debug messages', () => {
|
|
109
|
+
const consoleSpy = jest.spyOn(console, 'debug').mockImplementation();
|
|
110
|
+
logger.debug('Test debug message');
|
|
111
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
112
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Test debug message'));
|
|
113
|
+
consoleSpy.mockRestore();
|
|
114
|
+
});
|
|
115
|
+
test('should log info messages', () => {
|
|
116
|
+
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
117
|
+
logger.info('Test info message');
|
|
118
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
119
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Test info message'));
|
|
120
|
+
consoleSpy.mockRestore();
|
|
121
|
+
});
|
|
122
|
+
test('should log warn messages', () => {
|
|
123
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
124
|
+
logger.warn('Test warning message');
|
|
125
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('WARN'));
|
|
126
|
+
consoleSpy.mockRestore();
|
|
127
|
+
});
|
|
128
|
+
test('should log error messages', () => {
|
|
129
|
+
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
130
|
+
logger.error('Test error message');
|
|
131
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('ERROR'));
|
|
132
|
+
consoleSpy.mockRestore();
|
|
133
|
+
});
|
|
134
|
+
test('should include timestamp when configured', () => {
|
|
135
|
+
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
136
|
+
logger.info('Timestamped message');
|
|
137
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
138
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\]/));
|
|
139
|
+
consoleSpy.mockRestore();
|
|
140
|
+
});
|
|
141
|
+
test('should not log when console is disabled', () => {
|
|
142
|
+
const consoleLogger = new config_1.Logger({
|
|
143
|
+
level: 'info',
|
|
144
|
+
enableConsole: false,
|
|
145
|
+
enableFile: false,
|
|
146
|
+
includeTimestamp: true,
|
|
147
|
+
includeLevel: true
|
|
148
|
+
});
|
|
149
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
150
|
+
consoleLogger.info('Should not appear in console');
|
|
151
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
152
|
+
consoleSpy.mockRestore();
|
|
153
|
+
});
|
|
154
|
+
test('should respect log level', () => {
|
|
155
|
+
const infoLogger = new config_1.Logger({
|
|
156
|
+
level: 'info',
|
|
157
|
+
enableConsole: true,
|
|
158
|
+
enableFile: false,
|
|
159
|
+
includeTimestamp: false,
|
|
160
|
+
includeLevel: true
|
|
161
|
+
});
|
|
162
|
+
const consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation();
|
|
163
|
+
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
164
|
+
infoLogger.debug('Debug message'); // Should not log
|
|
165
|
+
infoLogger.info('Info message'); // Should log
|
|
166
|
+
expect(consoleDebugSpy).not.toHaveBeenCalled();
|
|
167
|
+
expect(consoleInfoSpy).toHaveBeenCalledTimes(1);
|
|
168
|
+
expect(consoleInfoSpy).toHaveBeenCalledWith(expect.stringContaining('Info message'));
|
|
169
|
+
consoleDebugSpy.mockRestore();
|
|
170
|
+
consoleInfoSpy.mockRestore();
|
|
171
|
+
});
|
|
172
|
+
test('should log with additional data', () => {
|
|
173
|
+
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
174
|
+
logger.info('Message with data', { key: 'value', number: 42 });
|
|
175
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
176
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('key'));
|
|
177
|
+
consoleSpy.mockRestore();
|
|
178
|
+
});
|
|
179
|
+
test('should handle error log level hierarchy', () => {
|
|
180
|
+
const errorLogger = new config_1.Logger({
|
|
181
|
+
level: 'error',
|
|
182
|
+
enableConsole: true,
|
|
183
|
+
enableFile: false,
|
|
184
|
+
includeTimestamp: false,
|
|
185
|
+
includeLevel: true
|
|
186
|
+
});
|
|
187
|
+
const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
188
|
+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
189
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
190
|
+
errorLogger.debug('Debug'); // Should not log
|
|
191
|
+
errorLogger.info('Info'); // Should not log
|
|
192
|
+
errorLogger.warn('Warn'); // Should not log
|
|
193
|
+
errorLogger.error('Error'); // Should log
|
|
194
|
+
expect(consoleLogSpy).not.toHaveBeenCalled();
|
|
195
|
+
expect(consoleWarnSpy).not.toHaveBeenCalled();
|
|
196
|
+
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
|
|
197
|
+
consoleLogSpy.mockRestore();
|
|
198
|
+
consoleWarnSpy.mockRestore();
|
|
199
|
+
consoleErrorSpy.mockRestore();
|
|
200
|
+
});
|
|
201
|
+
test('should format messages without timestamp', () => {
|
|
202
|
+
const noTimestampLogger = new config_1.Logger({
|
|
203
|
+
level: 'info',
|
|
204
|
+
enableConsole: true,
|
|
205
|
+
enableFile: false,
|
|
206
|
+
includeTimestamp: false,
|
|
207
|
+
includeLevel: true
|
|
208
|
+
});
|
|
209
|
+
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
210
|
+
noTimestampLogger.info('No timestamp');
|
|
211
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
212
|
+
const calls = consoleSpy.mock.calls[0][0];
|
|
213
|
+
expect(calls).not.toMatch(/\[\d{4}-\d{2}-\d{2}T/);
|
|
214
|
+
consoleSpy.mockRestore();
|
|
215
|
+
});
|
|
216
|
+
test('should format messages without level', () => {
|
|
217
|
+
const noLevelLogger = new config_1.Logger({
|
|
218
|
+
level: 'info',
|
|
219
|
+
enableConsole: true,
|
|
220
|
+
enableFile: false,
|
|
221
|
+
includeTimestamp: false,
|
|
222
|
+
includeLevel: false
|
|
223
|
+
});
|
|
224
|
+
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
225
|
+
noLevelLogger.info('No level');
|
|
226
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
227
|
+
const calls = consoleSpy.mock.calls[0][0];
|
|
228
|
+
expect(calls).not.toContain('[INFO]');
|
|
229
|
+
consoleSpy.mockRestore();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
describe('DEFAULT_CONFIG', () => {
|
|
233
|
+
test('should have sensible defaults', () => {
|
|
234
|
+
expect(config_1.DEFAULT_CONFIG.connectionTimeout).toBe(30000);
|
|
235
|
+
expect(config_1.DEFAULT_CONFIG.requestTimeout).toBe(60000);
|
|
236
|
+
expect(config_1.DEFAULT_CONFIG.enableRetry).toBe(true);
|
|
237
|
+
expect(config_1.DEFAULT_CONFIG.maxRetries).toBe(3);
|
|
238
|
+
expect(config_1.DEFAULT_CONFIG.retryDelay).toBe(1000);
|
|
239
|
+
expect(config_1.DEFAULT_CONFIG.verbose).toBe(false);
|
|
240
|
+
expect(config_1.DEFAULT_CONFIG.maxConcurrentRequests).toBe(5);
|
|
241
|
+
expect(config_1.DEFAULT_CONFIG.minRequestInterval).toBe(100);
|
|
242
|
+
expect(config_1.DEFAULT_CONFIG.autoReconnect).toBe(true);
|
|
243
|
+
expect(config_1.DEFAULT_CONFIG.trustNewIdentities).toBe('on-first-use');
|
|
244
|
+
expect(config_1.DEFAULT_CONFIG.disableSendLog).toBe(false);
|
|
245
|
+
});
|
|
246
|
+
test('should have empty strings for optional paths', () => {
|
|
247
|
+
expect(config_1.DEFAULT_CONFIG.signalCliPath).toBe('');
|
|
248
|
+
expect(config_1.DEFAULT_CONFIG.account).toBe('');
|
|
249
|
+
expect(config_1.DEFAULT_CONFIG.logFile).toBe('');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|