File size: 3,971 Bytes
d0ded63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { logger, createAsyncMetricsTracker } from './logger';

describe('Logger', () => {
  const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation();
  const mockConsoleError = jest.spyOn(console, 'error').mockImplementation();
  const mockConsoleWarn = jest.spyOn(console, 'warn').mockImplementation();

  beforeEach(() => {
    mockConsoleLog.mockClear();
    mockConsoleError.mockClear();
    mockConsoleWarn.mockClear();
  });

  afterAll(() => {
    mockConsoleLog.mockRestore();
    mockConsoleError.mockRestore();
    mockConsoleWarn.mockRestore();
  });

  describe('log methods', () => {
    it('should log error messages to console.error', () => {
      logger.error('test-component', 'test error message');
      expect(mockConsoleError).toHaveBeenCalledWith(
        '[test-component] test error message',
      );
    });

    it('should log warning messages to console.warn', () => {
      logger.warn('test-component', 'test warning');
      expect(mockConsoleWarn).toHaveBeenCalledWith(
        '[test-component] test warning',
      );
    });

    it('should include metadata in logs', () => {
      const metadata = { userId: '123', action: 'create' };
      logger.error('auth', 'unauthorized access', undefined, metadata);
      expect(mockConsoleError).toHaveBeenCalledWith(
        '[auth] unauthorized access',
        { userId: '123', action: 'create' },
      );
    });

    it('should log error with Error object and extract message/stack', () => {
      const error = new Error('test error');
      logger.error('api', 'request failed', error);
      expect(mockConsoleError).toHaveBeenCalled();
      const callArgs = mockConsoleError.mock.calls[0];
      expect(callArgs[0]).toContain('[api]');
      expect(callArgs[1]).toHaveProperty('errorMessage', 'test error');
      expect(callArgs[1]).toHaveProperty('errorStack');
    });
  });

  describe('measureAsync', () => {
    it('should measure async operation duration and return result', async () => {
      const result = await logger.measureAsync('test', 'operation', async () => {
        return 'success';
      });
      expect(result).toBe('success');
    });

    it('should measure async operation duration and log failure', async () => {
      const testError = new Error('async failure');
      await expect(
        logger.measureAsync('test', 'operation', async () => {
          throw testError;
        }),
      ).rejects.toThrow('async failure');

      expect(mockConsoleError).toHaveBeenCalled();
      const callArgs = mockConsoleError.mock.calls[0];
      expect(callArgs[0]).toContain('[test]');
      expect(callArgs[0]).toContain('operation failed');
    });
  });

  describe('measureSync', () => {
    it('should measure sync operation duration and return result', () => {
      const result = logger.measureSync('test', 'operation', () => {
        return 'success';
      });
      expect(result).toBe('success');
    });

    it('should measure sync operation duration and log failure', () => {
      expect(() => {
        logger.measureSync('test', 'operation', () => {
          throw new Error('sync failure');
        });
      }).toThrow('sync failure');

      expect(mockConsoleError).toHaveBeenCalled();
    });
  });

  describe('createAsyncMetricsTracker', () => {
    it('should track successful async operation', () => {
      const tracker = createAsyncMetricsTracker('api', 'fetch');
      tracker.success({ statusCode: 200 });
      // Logger call succeeds without console verification
    });

    it('should track failed async operation', () => {
      const tracker = createAsyncMetricsTracker('api', 'fetch');
      const error = new Error('network error');
      tracker.error(error, { attempt: 1 });
      expect(mockConsoleError).toHaveBeenCalled();
      const callArgs = mockConsoleError.mock.calls[0];
      expect(callArgs[0]).toContain('[api]');
      expect(callArgs[0]).toContain('fetch failed');
    });
  });
});