Files
logger/tests/TechnikerMeAppender.test.ts

135 lines
3.8 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'bun:test';
import TechnikerMeAppender from '../src/appenders/TechnikerMeAppender';
describe('TechnikerMeAppender', () => {
let technikerMeAppender: TechnikerMeAppender;
let mockFetch: any;
let originalFetch: any;
beforeEach(() => {
technikerMeAppender = new TechnikerMeAppender();
// Mock fetch
originalFetch = global.fetch;
mockFetch = vi.fn();
global.fetch = mockFetch;
});
afterEach(() => {
global.fetch = originalFetch;
vi.clearAllMocks();
});
describe('log method', () => {
it('should queue messages and attempt to post them', () => {
mockFetch.mockResolvedValue(new Response());
technikerMeAppender.log('2023-01-01T00:00:00.000Z', 'Info', 'test-category', 'test message');
// Should attempt to fetch
expect(mockFetch).toHaveBeenCalledWith(
'https://logserver.techniker.me/api/logs',
expect.objectContaining({
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
mode: 'no-cors'
})
);
const callArgs = mockFetch.mock.calls[0];
const body = JSON.parse(callArgs[1].body);
expect(body).toEqual({
timestamp: '2023-01-01T00:00:00.000Z',
level: 'Info',
category: 'test-category',
message: 'test message',
domain: '' // Empty since we're in Node.js environment
});
});
it('should include domain in browser environment', () => {
// Mock window.location
const originalWindow = global.window;
global.window = {
location: {
hostname: 'example.com'
}
} as any;
const appender = new TechnikerMeAppender();
mockFetch.mockResolvedValue(new Response());
appender.log('2023-01-01T00:00:00.000Z', 'Info', 'test-category', 'test message');
const callArgs = mockFetch.mock.calls[0];
const body = JSON.parse(callArgs[1].body);
expect(body.domain).toBe('example.com');
// Restore
global.window = originalWindow;
});
it('should handle missing window gracefully', () => {
const originalWindow = global.window;
delete (global as any).window;
const appender = new TechnikerMeAppender();
mockFetch.mockResolvedValue(new Response());
appender.log('2023-01-01T00:00:00.000Z', 'Info', 'test-category', 'test message');
const callArgs = mockFetch.mock.calls[0];
const body = JSON.parse(callArgs[1].body);
expect(body.domain).toBe('');
// Restore
global.window = originalWindow;
});
});
describe('error handling', () => {
it('should handle missing fetch API', () => {
const originalFetch = global.fetch;
delete (global as any).fetch;
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
technikerMeAppender.log('2023-01-01T00:00:00.000Z', 'Info', 'test-category', 'test message');
expect(consoleSpy).toHaveBeenCalledWith('Fetch API is not available in this environment');
consoleSpy.mockRestore();
global.fetch = originalFetch;
});
});
describe('message queuing', () => {
it('should attempt to send messages', () => {
mockFetch.mockResolvedValue(new Response());
technikerMeAppender.log('2023-01-01T00:00:00.000Z', 'Info', 'cat1', 'msg1');
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://logserver.techniker.me/api/logs',
expect.objectContaining({
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
mode: 'no-cors'
})
);
});
// Note: Complex async queuing behavior is tested by the core functionality test above
});
});