271 lines
6.8 KiB
TypeScript
271 lines
6.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import Client from '../src/core/Client';
|
|
import { setAnonymousId } from '../src/utils/identity';
|
|
|
|
describe('SDK Error Safety', () => {
|
|
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterAll(() => {
|
|
consoleWarnSpy.mockRestore();
|
|
consoleLogSpy.mockRestore();
|
|
});
|
|
|
|
describe('Client public methods should not throw', () => {
|
|
let client: Client;
|
|
|
|
beforeEach(() => {
|
|
client = new Client({
|
|
dsn: 'https://proj_abc123@log.example.com/1001',
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
client.destroy();
|
|
});
|
|
|
|
it('captureException should not throw on invalid input', () => {
|
|
expect(() => {
|
|
client.captureException(null as unknown as Error);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureException should not throw on undefined input', () => {
|
|
expect(() => {
|
|
client.captureException(undefined);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureException should not throw when SDK is disabled', () => {
|
|
client.disable();
|
|
expect(() => {
|
|
client.captureException(new Error('test'));
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureMessage should not throw on empty message', () => {
|
|
expect(() => {
|
|
client.captureMessage('');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureMessage should not throw when SDK is disabled', () => {
|
|
client.disable();
|
|
expect(() => {
|
|
client.captureMessage('test');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureEvent should not throw on minimal event', () => {
|
|
expect(() => {
|
|
client.captureEvent({ type: 'custom' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('captureEvent should not throw when SDK is disabled', () => {
|
|
client.disable();
|
|
expect(() => {
|
|
client.captureEvent({ type: 'custom' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setUser should not throw on null input', () => {
|
|
expect(() => {
|
|
client.setUser(null);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setUser should not throw on valid input', () => {
|
|
expect(() => {
|
|
client.setUser({ id: '123', username: 'test' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setTag should not throw', () => {
|
|
expect(() => {
|
|
client.setTag('key', 'value');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setTags should not throw', () => {
|
|
expect(() => {
|
|
client.setTags({ key1: 'val1', key2: 'val2' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setExtra should not throw', () => {
|
|
expect(() => {
|
|
client.setExtra('key', { nested: true });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('addBreadcrumb should not throw', () => {
|
|
expect(() => {
|
|
client.addBreadcrumb({
|
|
type: 'default',
|
|
message: 'test breadcrumb',
|
|
level: 'info',
|
|
});
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('addBreadcrumb should not throw on empty breadcrumb', () => {
|
|
expect(() => {
|
|
client.addBreadcrumb({
|
|
type: 'default',
|
|
});
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('startTransaction should not throw', () => {
|
|
expect(() => {
|
|
client.startTransaction({ name: 'test-tx', op: 'test' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('startTransaction should not throw when SDK is disabled', () => {
|
|
client.disable();
|
|
const result = client.startTransaction({ name: 'test-tx', op: 'test' });
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('getCurrentTransaction should not throw', () => {
|
|
expect(() => {
|
|
client.getCurrentTransaction();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('getCurrentSpan should not throw', () => {
|
|
expect(() => {
|
|
client.getCurrentSpan();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('setSpan should not throw', () => {
|
|
expect(() => {
|
|
client.setSpan(null);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('startSpan should not throw', () => {
|
|
expect(() => {
|
|
client.startSpan({ name: 'test-span', op: 'test' });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('startSpan should not throw when SDK is disabled', () => {
|
|
client.disable();
|
|
const result = client.startSpan({ name: 'test-span', op: 'test' });
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('disable should not throw', () => {
|
|
expect(() => {
|
|
client.disable();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('enable should not throw', () => {
|
|
expect(() => {
|
|
client.enable();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('use should not throw on valid plugin', () => {
|
|
const plugin = {
|
|
name: 'test-plugin',
|
|
setup: vi.fn(),
|
|
};
|
|
expect(() => {
|
|
client.use(plugin);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('use should not throw when plugin setup throws', () => {
|
|
const plugin = {
|
|
name: 'bad-plugin',
|
|
setup: () => {
|
|
throw new Error('setup failed');
|
|
},
|
|
};
|
|
expect(() => {
|
|
client.use(plugin);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('flush should not throw', async () => {
|
|
await expect(client.flush()).resolves.not.toThrow();
|
|
});
|
|
|
|
it('destroy should not throw', () => {
|
|
expect(() => {
|
|
client.destroy();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('init should not throw', () => {
|
|
const newClient = new Client({
|
|
dsn: 'https://proj_abc123@log.example.com/1001',
|
|
});
|
|
expect(() => {
|
|
newClient.init();
|
|
}).not.toThrow();
|
|
newClient.destroy();
|
|
});
|
|
|
|
it('setAnonymousId should not throw', () => {
|
|
expect(() => {
|
|
client.setAnonymousId('test-anon-id');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('on/off/emit should not throw', () => {
|
|
const handler = vi.fn();
|
|
expect(() => {
|
|
client.on('test', handler);
|
|
}).not.toThrow();
|
|
expect(() => {
|
|
client.emit('test', 'data');
|
|
}).not.toThrow();
|
|
expect(() => {
|
|
client.off('test', handler);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('event handler errors should not affect other handlers', () => {
|
|
const handler1 = vi.fn(() => {
|
|
throw new Error('handler1 failed');
|
|
});
|
|
const handler2 = vi.fn();
|
|
|
|
client.on('test-event', handler1);
|
|
client.on('test-event', handler2);
|
|
|
|
expect(() => {
|
|
client.emit('test-event', 'data');
|
|
}).not.toThrow();
|
|
|
|
expect(handler1).toHaveBeenCalled();
|
|
expect(handler2).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Config edge cases', () => {
|
|
it('should throw on missing DSN (config error, not SDK bug)', () => {
|
|
expect(() => {
|
|
new Client({ dsn: '' });
|
|
}).toThrow();
|
|
});
|
|
|
|
it('should throw on undefined DSN', () => {
|
|
expect(() => {
|
|
new Client({ dsn: undefined as unknown as string });
|
|
}).toThrow();
|
|
});
|
|
});
|
|
});
|