import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest'; import { serializeError, serializeObject, logError, logObject } from '$lib/server/utils/logger'; describe('logger utilities', () => { describe('serializeError', () => { test('handles Error objects', () => { const error = new Error('Test error message'); const result = serializeError(error); expect(result).toContain('Test error message'); expect(result).toContain('"name": "Error"'); expect(result).toContain('"message"'); }); test('handles plain objects', () => { const obj = { code: 404, message: 'Not found' }; const result = serializeError(obj); expect(result).toContain('"code": 404'); expect(result).toContain('"message": "Not found"'); }); test('includes stack trace for Error objects', () => { const error = new Error('Stack test'); const result = serializeError(error); expect(result).toContain('"stack"'); }); test('handles Error with custom properties', () => { const error = new Error('Custom error') as any; error.statusCode = 500; error.details = { info: 'extra data' }; const result = serializeError(error); expect(result).toContain('"statusCode": 500'); expect(result).toContain('extra data'); }); }); describe('serializeObject', () => { test('handles circular references', () => { const obj: any = { a: 1, b: 2 }; obj.self = obj; const result = serializeObject(obj); expect(result).toContain('[Circular]'); expect(result).toContain('"a": 1'); }); test('handles deeply nested objects', () => { const obj = { level1: { level2: { level3: { value: 'deep' } } } }; const result = serializeObject(obj); expect(result).toContain('"value": "deep"'); }); test('handles arrays', () => { const obj = { items: [1, 2, 3] }; const result = serializeObject(obj); expect(result).toContain('"items"'); expect(result).toContain('['); }); test('handles null and undefined', () => { const obj = { a: null, b: undefined }; const result = serializeObject(obj); expect(result).toContain('"a": null'); }); }); describe('logError', () => { let consoleErrorSpy: any; beforeEach(() => { consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { consoleErrorSpy.mockRestore(); }); test('outputs to console.error', () => { const error = new Error('Test'); logError('[Test]', error); expect(consoleErrorSpy).toHaveBeenCalledWith('[Test]', 'Test'); }); test('logs stack trace for Error objects', () => { const error = new Error('Stack error'); logError('[Test]', error); expect(consoleErrorSpy).toHaveBeenCalledWith( expect.stringMatching(/Stack/), expect.any(String) ); }); test('handles non-Error objects', () => { const obj = { code: 500, message: 'Server error' }; logError('[Test]', obj); expect(consoleErrorSpy).toHaveBeenCalledWith( '[Test]', expect.stringContaining('"code": 500') ); }); }); describe('logObject', () => { let consoleLogSpy: any; beforeEach(() => { consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); }); afterEach(() => { consoleLogSpy.mockRestore(); }); test('outputs to console.log', () => { const obj = { key: 'value' }; logObject('[Test]', obj); expect(consoleLogSpy).toHaveBeenCalledWith( '[Test]', expect.stringContaining('"key": "value"') ); }); test('handles circular references', () => { const obj: any = { a: 1 }; obj.self = obj; logObject('[Test]', obj); expect(consoleLogSpy).toHaveBeenCalledWith( '[Test]', expect.stringContaining('[Circular]') ); }); }); });